aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorRick Hudson <rlh@golang.org>2016-04-27 18:19:16 -0400
committerRick Hudson <rlh@golang.org>2016-04-27 18:46:52 -0400
commit23aeb34df172b17b7bfaa85fb59ca64bef9073bb (patch)
treea8ab866f1e50f0059856ce628f036d93ab620155 /src/cmd
parent1354b32cd70f2702381764fd595dd2faa996840c (diff)
parentd3c79d324acd7300b6f705e66af8ca711af00d9f (diff)
downloadgo-23aeb34df172b17b7bfaa85fb59ca64bef9073bb.tar.xz
[dev.garbage] Merge remote-tracking branch 'origin/master' into HEAD
Change-Id: I282fd9ce9db435dfd35e882a9502ab1abc185297
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/api/goapi.go5
-rw-r--r--src/cmd/asm/internal/asm/asm.go53
-rw-r--r--src/cmd/asm/internal/asm/endtoend_test.go5
-rw-r--r--src/cmd/asm/internal/asm/parse.go16
-rw-r--r--src/cmd/asm/internal/asm/testdata/s390x.s4
-rw-r--r--src/cmd/asm/main.go31
-rw-r--r--src/cmd/cgo/ast.go10
-rw-r--r--src/cmd/cgo/gcc.go2
-rw-r--r--src/cmd/cgo/main.go2
-rw-r--r--src/cmd/cgo/out.go2
-rw-r--r--src/cmd/compile/internal/amd64/galign.go12
-rw-r--r--src/cmd/compile/internal/amd64/gsubr.go2
-rw-r--r--src/cmd/compile/internal/amd64/ssa.go261
-rw-r--r--src/cmd/compile/internal/arm/cgen64.go6
-rw-r--r--src/cmd/compile/internal/arm/galign.go7
-rw-r--r--src/cmd/compile/internal/arm/gsubr.go4
-rw-r--r--src/cmd/compile/internal/arm/ssa.go8
-rw-r--r--src/cmd/compile/internal/arm64/galign.go9
-rw-r--r--src/cmd/compile/internal/arm64/ggen.go47
-rw-r--r--src/cmd/compile/internal/arm64/gsubr.go18
-rw-r--r--src/cmd/compile/internal/arm64/peep.go3
-rw-r--r--src/cmd/compile/internal/arm64/prog.go3
-rw-r--r--src/cmd/compile/internal/gc/alg.go20
-rw-r--r--src/cmd/compile/internal/gc/align.go54
-rw-r--r--src/cmd/compile/internal/gc/bexport.go301
-rw-r--r--src/cmd/compile/internal/gc/bimport.go363
-rw-r--r--src/cmd/compile/internal/gc/builtin.go231
-rw-r--r--src/cmd/compile/internal/gc/builtin/runtime.go2
-rw-r--r--src/cmd/compile/internal/gc/cgen.go239
-rw-r--r--src/cmd/compile/internal/gc/closure.go4
-rw-r--r--src/cmd/compile/internal/gc/const.go179
-rw-r--r--src/cmd/compile/internal/gc/cplx.go9
-rw-r--r--src/cmd/compile/internal/gc/dcl.go107
-rw-r--r--src/cmd/compile/internal/gc/esc.go30
-rw-r--r--src/cmd/compile/internal/gc/export.go32
-rw-r--r--src/cmd/compile/internal/gc/fmt.go190
-rw-r--r--src/cmd/compile/internal/gc/gen.go20
-rw-r--r--src/cmd/compile/internal/gc/go.go219
-rw-r--r--src/cmd/compile/internal/gc/gsubr.go51
-rw-r--r--src/cmd/compile/internal/gc/init.go2
-rw-r--r--src/cmd/compile/internal/gc/inl.go60
-rw-r--r--src/cmd/compile/internal/gc/lex.go238
-rw-r--r--src/cmd/compile/internal/gc/lex_test.go79
-rw-r--r--src/cmd/compile/internal/gc/main.go151
-rw-r--r--src/cmd/compile/internal/gc/obj.go79
-rw-r--r--src/cmd/compile/internal/gc/opnames.go8
-rw-r--r--src/cmd/compile/internal/gc/order.go46
-rw-r--r--src/cmd/compile/internal/gc/parser.go39
-rw-r--r--src/cmd/compile/internal/gc/pgen.go18
-rw-r--r--src/cmd/compile/internal/gc/pgen_test.go20
-rw-r--r--src/cmd/compile/internal/gc/plive.go24
-rw-r--r--src/cmd/compile/internal/gc/popt.go28
-rw-r--r--src/cmd/compile/internal/gc/racewalk.go30
-rw-r--r--src/cmd/compile/internal/gc/range.go18
-rw-r--r--src/cmd/compile/internal/gc/reflect.go490
-rw-r--r--src/cmd/compile/internal/gc/reg.go17
-rw-r--r--src/cmd/compile/internal/gc/select.go8
-rw-r--r--src/cmd/compile/internal/gc/sinit.go111
-rw-r--r--src/cmd/compile/internal/gc/sizeof_test.go15
-rw-r--r--src/cmd/compile/internal/gc/ssa.go377
-rw-r--r--src/cmd/compile/internal/gc/ssa_test.go4
-rw-r--r--src/cmd/compile/internal/gc/subr.go134
-rw-r--r--src/cmd/compile/internal/gc/swt.go2
-rw-r--r--src/cmd/compile/internal/gc/syntax.go1
-rw-r--r--src/cmd/compile/internal/gc/testdata/dupLoad.go83
-rw-r--r--src/cmd/compile/internal/gc/testdata/namedReturn.go105
-rw-r--r--src/cmd/compile/internal/gc/type.go518
-rw-r--r--src/cmd/compile/internal/gc/typecheck.go309
-rw-r--r--src/cmd/compile/internal/gc/universe.go13
-rw-r--r--src/cmd/compile/internal/gc/unsafe.go4
-rw-r--r--src/cmd/compile/internal/gc/walk.go191
-rw-r--r--src/cmd/compile/internal/mips64/galign.go10
-rw-r--r--src/cmd/compile/internal/mips64/gsubr.go6
-rw-r--r--src/cmd/compile/internal/ppc64/galign.go13
-rw-r--r--src/cmd/compile/internal/ppc64/gsubr.go6
-rw-r--r--src/cmd/compile/internal/ppc64/reg.go2
-rw-r--r--src/cmd/compile/internal/s390x/cgen.go178
-rw-r--r--src/cmd/compile/internal/s390x/galign.go66
-rw-r--r--src/cmd/compile/internal/s390x/ggen.go577
-rw-r--r--src/cmd/compile/internal/s390x/gsubr.go1115
-rw-r--r--src/cmd/compile/internal/s390x/peep.go1664
-rw-r--r--src/cmd/compile/internal/s390x/prog.go179
-rw-r--r--src/cmd/compile/internal/s390x/reg.go130
-rw-r--r--src/cmd/compile/internal/ssa/TODO2
-rw-r--r--src/cmd/compile/internal/ssa/check.go20
-rw-r--r--src/cmd/compile/internal/ssa/compile.go13
-rw-r--r--src/cmd/compile/internal/ssa/config.go7
-rw-r--r--src/cmd/compile/internal/ssa/cse.go60
-rw-r--r--src/cmd/compile/internal/ssa/cse_test.go1
-rw-r--r--src/cmd/compile/internal/ssa/decompose.go29
-rw-r--r--src/cmd/compile/internal/ssa/dom.go290
-rw-r--r--src/cmd/compile/internal/ssa/dom_test.go208
-rw-r--r--src/cmd/compile/internal/ssa/export_test.go3
-rw-r--r--src/cmd/compile/internal/ssa/func.go15
-rw-r--r--src/cmd/compile/internal/ssa/gen/AMD64.rules749
-rw-r--r--src/cmd/compile/internal/ssa/gen/AMD64Ops.go56
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARMOps.go6
-rw-r--r--src/cmd/compile/internal/ssa/gen/generic.rules71
-rw-r--r--src/cmd/compile/internal/ssa/gen/genericOps.go9
-rw-r--r--src/cmd/compile/internal/ssa/gen/main.go8
-rw-r--r--src/cmd/compile/internal/ssa/gen/rulegen.go127
-rw-r--r--src/cmd/compile/internal/ssa/id.go2
-rw-r--r--src/cmd/compile/internal/ssa/likelyadjust.go142
-rw-r--r--src/cmd/compile/internal/ssa/loopbce.go57
-rw-r--r--src/cmd/compile/internal/ssa/nilcheck.go4
-rw-r--r--src/cmd/compile/internal/ssa/nilcheck_test.go12
-rw-r--r--src/cmd/compile/internal/ssa/op.go5
-rw-r--r--src/cmd/compile/internal/ssa/opGen.go825
-rw-r--r--src/cmd/compile/internal/ssa/phielim.go6
-rw-r--r--src/cmd/compile/internal/ssa/phiopt.go70
-rw-r--r--src/cmd/compile/internal/ssa/prove.go9
-rw-r--r--src/cmd/compile/internal/ssa/regalloc.go843
-rw-r--r--src/cmd/compile/internal/ssa/regalloc_test.go4
-rw-r--r--src/cmd/compile/internal/ssa/rewrite.go70
-rw-r--r--src/cmd/compile/internal/ssa/rewriteAMD64.go4205
-rw-r--r--src/cmd/compile/internal/ssa/rewritegeneric.go1120
-rw-r--r--src/cmd/compile/internal/ssa/sparsemap.go16
-rw-r--r--src/cmd/compile/internal/ssa/sparsetree.go12
-rw-r--r--src/cmd/compile/internal/ssa/stackalloc.go25
-rw-r--r--src/cmd/compile/internal/ssa/type.go67
-rw-r--r--src/cmd/compile/internal/ssa/type_test.go49
-rw-r--r--src/cmd/compile/internal/ssa/value.go1
-rw-r--r--src/cmd/compile/internal/x86/cgen64.go6
-rw-r--r--src/cmd/compile/internal/x86/galign.go7
-rw-r--r--src/cmd/compile/internal/x86/ggen.go2
-rw-r--r--src/cmd/compile/internal/x86/gsubr.go6
-rw-r--r--src/cmd/compile/internal/x86/reg.go2
-rw-r--r--src/cmd/compile/main.go3
-rw-r--r--src/cmd/dist/buildgo.go16
-rw-r--r--src/cmd/dist/buildtool.go3
-rw-r--r--src/cmd/dist/test.go4
-rw-r--r--src/cmd/doc/pkg.go34
-rw-r--r--src/cmd/go/alldocs.go14
-rw-r--r--src/cmd/go/build.go114
-rw-r--r--src/cmd/go/get.go8
-rw-r--r--src/cmd/go/go_test.go125
-rw-r--r--src/cmd/go/http.go2
-rw-r--r--src/cmd/go/list.go1
-rw-r--r--src/cmd/go/pkg.go66
-rw-r--r--src/cmd/go/test.go16
-rw-r--r--src/cmd/go/vcs.go17
-rw-r--r--src/cmd/go/vcs_test.go35
-rw-r--r--src/cmd/go/vendor_test.go26
-rw-r--r--src/cmd/gofmt/simplify.go28
-rw-r--r--src/cmd/gofmt/testdata/slices2.golden63
-rw-r--r--src/cmd/gofmt/testdata/slices2.input63
-rw-r--r--src/cmd/internal/bio/buf.go99
-rw-r--r--src/cmd/internal/bio/must.go43
-rw-r--r--src/cmd/internal/goobj/read.go7
-rw-r--r--src/cmd/internal/obj/arm/asm5.go8
-rw-r--r--src/cmd/internal/obj/arm/obj5.go15
-rw-r--r--src/cmd/internal/obj/arm64/asm7.go8
-rw-r--r--src/cmd/internal/obj/arm64/list7.go2
-rw-r--r--src/cmd/internal/obj/arm64/obj7.go19
-rw-r--r--src/cmd/internal/obj/data.go38
-rw-r--r--src/cmd/internal/obj/link.go78
-rw-r--r--src/cmd/internal/obj/mips/asm0.go8
-rw-r--r--src/cmd/internal/obj/mips/obj0.go22
-rw-r--r--src/cmd/internal/obj/objfile.go204
-rw-r--r--src/cmd/internal/obj/pcln.go23
-rw-r--r--src/cmd/internal/obj/plist.go218
-rw-r--r--src/cmd/internal/obj/ppc64/asm9.go24
-rw-r--r--src/cmd/internal/obj/ppc64/obj9.go26
-rw-r--r--src/cmd/internal/obj/s390x/a.out.go1
-rw-r--r--src/cmd/internal/obj/s390x/anames.go1
-rw-r--r--src/cmd/internal/obj/s390x/asmz.go38
-rw-r--r--src/cmd/internal/obj/s390x/objz.go15
-rw-r--r--src/cmd/internal/obj/sym.go3
-rw-r--r--src/cmd/internal/obj/util.go142
-rw-r--r--src/cmd/internal/obj/x86/a.out.go2
-rw-r--r--src/cmd/internal/obj/x86/anames.go1
-rw-r--r--src/cmd/internal/obj/x86/asm6.go49
-rw-r--r--src/cmd/internal/obj/x86/obj6.go59
-rw-r--r--src/cmd/internal/obj/x86/obj6_test.go1
-rw-r--r--src/cmd/internal/objfile/pe.go2
-rw-r--r--src/cmd/internal/objfile/plan9obj.go2
-rw-r--r--src/cmd/internal/pprof/commands/commands.go (renamed from src/cmd/pprof/internal/commands/commands.go)8
-rw-r--r--src/cmd/internal/pprof/driver/driver.go (renamed from src/cmd/pprof/internal/driver/driver.go)10
-rw-r--r--src/cmd/internal/pprof/driver/interactive.go (renamed from src/cmd/pprof/internal/driver/interactive.go)6
-rw-r--r--src/cmd/internal/pprof/fetch/fetch.go (renamed from src/cmd/pprof/internal/fetch/fetch.go)4
-rw-r--r--src/cmd/internal/pprof/plugin/plugin.go (renamed from src/cmd/pprof/internal/plugin/plugin.go)2
-rw-r--r--src/cmd/internal/pprof/profile/encode.go (renamed from src/cmd/pprof/internal/profile/encode.go)0
-rw-r--r--src/cmd/internal/pprof/profile/filter.go (renamed from src/cmd/pprof/internal/profile/filter.go)0
-rw-r--r--src/cmd/internal/pprof/profile/legacy_profile.go (renamed from src/cmd/pprof/internal/profile/legacy_profile.go)51
-rw-r--r--src/cmd/internal/pprof/profile/profile.go (renamed from src/cmd/pprof/internal/profile/profile.go)0
-rw-r--r--src/cmd/internal/pprof/profile/profile_test.go (renamed from src/cmd/pprof/internal/profile/profile_test.go)0
-rw-r--r--src/cmd/internal/pprof/profile/proto.go (renamed from src/cmd/pprof/internal/profile/proto.go)0
-rw-r--r--src/cmd/internal/pprof/profile/proto_test.go (renamed from src/cmd/pprof/internal/profile/proto_test.go)0
-rw-r--r--src/cmd/internal/pprof/profile/prune.go (renamed from src/cmd/pprof/internal/profile/prune.go)0
-rw-r--r--src/cmd/internal/pprof/report/report.go (renamed from src/cmd/pprof/internal/report/report.go)4
-rw-r--r--src/cmd/internal/pprof/report/source.go (renamed from src/cmd/pprof/internal/report/source.go)4
-rw-r--r--src/cmd/internal/pprof/report/source_html.go (renamed from src/cmd/pprof/internal/report/source_html.go)0
-rw-r--r--src/cmd/internal/pprof/svg/svg.go (renamed from src/cmd/pprof/internal/svg/svg.go)0
-rw-r--r--src/cmd/internal/pprof/svg/svgpan.go (renamed from src/cmd/pprof/internal/svg/svgpan.go)0
-rw-r--r--src/cmd/internal/pprof/symbolizer/symbolizer.go (renamed from src/cmd/pprof/internal/symbolizer/symbolizer.go)4
-rw-r--r--src/cmd/internal/pprof/symbolz/symbolz.go (renamed from src/cmd/pprof/internal/symbolz/symbolz.go)2
-rw-r--r--src/cmd/internal/pprof/tempfile/tempfile.go (renamed from src/cmd/pprof/internal/tempfile/tempfile.go)0
-rw-r--r--src/cmd/internal/sys/arch.go148
-rw-r--r--src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go8
-rw-r--r--src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go2
-rw-r--r--src/cmd/link/internal/amd64/asm.go55
-rw-r--r--src/cmd/link/internal/amd64/l.go5
-rw-r--r--src/cmd/link/internal/amd64/obj.go11
-rw-r--r--src/cmd/link/internal/amd64/z.go1
-rw-r--r--src/cmd/link/internal/arm/asm.go77
-rw-r--r--src/cmd/link/internal/arm/l.go2
-rw-r--r--src/cmd/link/internal/arm/obj.go9
-rw-r--r--src/cmd/link/internal/arm64/asm.go48
-rw-r--r--src/cmd/link/internal/arm64/l.go2
-rw-r--r--src/cmd/link/internal/arm64/obj.go9
-rw-r--r--src/cmd/link/internal/ld/ar.go23
-rw-r--r--src/cmd/link/internal/ld/arch.go97
-rw-r--r--src/cmd/link/internal/ld/data.go1032
-rw-r--r--src/cmd/link/internal/ld/deadcode.go63
-rw-r--r--src/cmd/link/internal/ld/decodesym.go126
-rw-r--r--src/cmd/link/internal/ld/dwarf.go1590
-rw-r--r--src/cmd/link/internal/ld/elf.go146
-rw-r--r--src/cmd/link/internal/ld/go.go36
-rw-r--r--src/cmd/link/internal/ld/ldelf.go214
-rw-r--r--src/cmd/link/internal/ld/ldmacho.go85
-rw-r--r--src/cmd/link/internal/ld/ldpe.go46
-rw-r--r--src/cmd/link/internal/ld/lib.go302
-rw-r--r--src/cmd/link/internal/ld/link.go45
-rw-r--r--src/cmd/link/internal/ld/macho.go126
-rw-r--r--src/cmd/link/internal/ld/macho_combine_dwarf.go4
-rw-r--r--src/cmd/link/internal/ld/objfile.go74
-rw-r--r--src/cmd/link/internal/ld/pcln.go146
-rw-r--r--src/cmd/link/internal/ld/pe.go51
-rw-r--r--src/cmd/link/internal/ld/pobj.go26
-rw-r--r--src/cmd/link/internal/ld/sym.go33
-rw-r--r--src/cmd/link/internal/ld/symtab.go121
-rw-r--r--src/cmd/link/internal/mips64/asm.go39
-rw-r--r--src/cmd/link/internal/mips64/l.go2
-rw-r--r--src/cmd/link/internal/mips64/obj.go15
-rw-r--r--src/cmd/link/internal/ppc64/asm.go69
-rw-r--r--src/cmd/link/internal/ppc64/l.go2
-rw-r--r--src/cmd/link/internal/ppc64/obj.go17
-rw-r--r--src/cmd/link/internal/s390x/asm.go27
-rw-r--r--src/cmd/link/internal/s390x/l.go5
-rw-r--r--src/cmd/link/internal/s390x/obj.go9
-rw-r--r--src/cmd/link/internal/x86/asm.go58
-rw-r--r--src/cmd/link/internal/x86/l.go3
-rw-r--r--src/cmd/link/internal/x86/obj.go9
-rw-r--r--src/cmd/link/link_test.go30
-rw-r--r--src/cmd/link/main.go3
-rw-r--r--src/cmd/objdump/objdump_test.go4
-rw-r--r--src/cmd/pprof/pprof.go14
-rw-r--r--src/cmd/trace/main.go7
-rw-r--r--src/cmd/trace/pprof.go78
-rw-r--r--src/cmd/trace/trace.go91
-rw-r--r--src/cmd/vet/asmdecl.go5
-rw-r--r--src/cmd/vet/atomic.go3
-rw-r--r--src/cmd/vet/composite.go6
-rw-r--r--src/cmd/vet/doc.go20
-rw-r--r--src/cmd/vet/internal/whitelist/whitelist.go3
-rw-r--r--src/cmd/vet/main.go3
-rw-r--r--src/cmd/vet/print.go104
-rw-r--r--src/cmd/vet/structtag.go2
-rw-r--r--src/cmd/vet/testdata/asm.go2
-rw-r--r--src/cmd/vet/testdata/asm1.s11
-rw-r--r--src/cmd/vet/testdata/atomic.go9
-rw-r--r--src/cmd/vet/testdata/composite.go8
-rw-r--r--src/cmd/vet/testdata/print.go38
-rw-r--r--src/cmd/vet/types.go66
264 files changed, 16039 insertions, 10347 deletions
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 982c40b085..e9c91477c6 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -143,6 +143,11 @@ func main() {
w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
for _, name := range pkgNames {
+ // Vendored packages do not contribute to our
+ // public API surface.
+ if strings.HasPrefix(name, "vendor/") {
+ continue
+ }
// - Package "unsafe" contains special signatures requiring
// extra care when printing them - ignore since it is not
// going to change w/o a language change.
diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go
index 950fd735c9..24906e2cce 100644
--- a/src/cmd/asm/internal/asm/asm.go
+++ b/src/cmd/asm/internal/asm/asm.go
@@ -13,6 +13,7 @@ import (
"cmd/asm/internal/flags"
"cmd/asm/internal/lex"
"cmd/internal/obj"
+ "cmd/internal/sys"
)
// TODO: configure the architecture
@@ -23,14 +24,14 @@ var testOut *bytes.Buffer // Gathers output when testing.
// If doLabel is set, it also defines the labels collect for this Prog.
func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
if cond != "" {
- switch p.arch.Thechar {
- case '5':
+ switch p.arch.Family {
+ case sys.ARM:
if !arch.ARMConditionCodes(prog, cond) {
p.errorf("unrecognized condition code .%q", cond)
return
}
- case '7':
+ case sys.ARM64:
if !arch.ARM64Suffix(prog, cond) {
p.errorf("unrecognized suffix .%q", cond)
return
@@ -58,7 +59,7 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
}
p.pendingLabels = p.pendingLabels[0:0]
}
- prog.Pc = int64(p.pc)
+ prog.Pc = p.pc
if *flags.Debug {
fmt.Println(p.histLineNum, prog)
}
@@ -361,7 +362,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
target = &a[1]
prog.From = a[0]
case 3:
- if p.arch.Thechar == '9' {
+ if p.arch.Family == sys.PPC64 {
// Special 3-operand jumps.
// First two must be constants; a[1] is a register number.
target = &a[2]
@@ -370,7 +371,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
Offset: p.getConstant(prog, op, &a[0]),
}
reg := int16(p.getConstant(prog, op, &a[1]))
- reg, ok := p.arch.RegisterNumber("R", int16(reg))
+ reg, ok := p.arch.RegisterNumber("R", reg)
if !ok {
p.errorf("bad register number %d", reg)
return
@@ -378,7 +379,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
prog.Reg = reg
break
}
- if p.arch.Thechar == '0' {
+ if p.arch.Family == sys.MIPS64 {
// 3-operand jumps.
// First two must be registers
target = &a[2]
@@ -386,7 +387,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
prog.Reg = p.getRegister(prog, op, &a[1])
break
}
- if p.arch.Thechar == 'z' {
+ if p.arch.Family == sys.S390X {
// 3-operand jumps.
target = &a[2]
prog.From = a[0]
@@ -438,7 +439,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
// JMP 4(R0)
prog.To = *target
// On the ppc64, 9a encodes BR (CTR) as BR CTR. We do the same.
- if p.arch.Thechar == '9' && target.Offset == 0 {
+ if p.arch.Family == sys.PPC64 && target.Offset == 0 {
prog.To.Type = obj.TYPE_REG
}
case target.Type == obj.TYPE_CONST:
@@ -492,14 +493,14 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.From = a[0]
// prog.To is no address.
}
- if p.arch.Thechar == '9' && arch.IsPPC64NEG(op) {
+ if p.arch.Family == sys.PPC64 && arch.IsPPC64NEG(op) {
// NEG: From and To are both a[0].
prog.To = a[0]
prog.From = a[0]
break
}
case 2:
- if p.arch.Thechar == '5' {
+ if p.arch.Family == sys.ARM {
if arch.IsARMCMP(op) {
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
@@ -532,11 +533,11 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.Reg = p.getRegister(prog, op, &a[1])
break
}
- } else if p.arch.Thechar == '7' && arch.IsARM64CMP(op) {
+ } else if p.arch.Family == sys.ARM64 && arch.IsARM64CMP(op) {
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
break
- } else if p.arch.Thechar == '0' {
+ } else if p.arch.Family == sys.MIPS64 {
if arch.IsMIPS64CMP(op) || arch.IsMIPS64MUL(op) {
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
@@ -546,12 +547,12 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.From = a[0]
prog.To = a[1]
case 3:
- switch p.arch.Thechar {
- case '0':
+ switch p.arch.Family {
+ case sys.MIPS64:
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
prog.To = a[2]
- case '5':
+ case sys.ARM:
// Special cases.
if arch.IsARMSTREX(op) {
/*
@@ -567,7 +568,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
prog.To = a[2]
- case '7':
+ case sys.ARM64:
// ARM64 instructions with one input and two outputs.
if arch.IsARM64STLXR(op) {
prog.From = a[0]
@@ -582,11 +583,11 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
prog.To = a[2]
- case '6', '8':
+ case sys.AMD64, sys.I386:
prog.From = a[0]
prog.From3 = newAddr(a[1])
prog.To = a[2]
- case '9':
+ case sys.PPC64:
if arch.IsPPC64CMP(op) {
// CMPW etc.; third argument is a CR register that goes into prog.Reg.
prog.From = a[0]
@@ -612,7 +613,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
p.errorf("invalid addressing modes for %s instruction", obj.Aconv(op))
return
}
- case 'z':
+ case sys.S390X:
if arch.IsS390xWithLength(op) || arch.IsS390xWithIndex(op) {
prog.From = a[1]
prog.From3 = newAddr(a[0])
@@ -626,7 +627,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
return
}
case 4:
- if p.arch.Thechar == '5' && arch.IsARMMULA(op) {
+ if p.arch.Family == sys.ARM && arch.IsARMMULA(op) {
// All must be registers.
p.getRegister(prog, op, &a[0])
r1 := p.getRegister(prog, op, &a[1])
@@ -639,14 +640,14 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.Reg = r1
break
}
- if p.arch.Thechar == '7' {
+ if p.arch.Family == sys.ARM64 {
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
prog.From3 = newAddr(a[2])
prog.To = a[3]
break
}
- if p.arch.Thechar == '9' && arch.IsPPC64RLD(op) {
+ if p.arch.Family == sys.PPC64 && arch.IsPPC64RLD(op) {
// 2nd operand must always be a register.
// TODO: Do we need to guard this with the instruction type?
// That is, are there 4-operand instructions without this property?
@@ -656,7 +657,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.To = a[3]
break
}
- if p.arch.Thechar == 'z' {
+ if p.arch.Family == sys.S390X {
prog.From = a[1]
prog.Reg = p.getRegister(prog, op, &a[2])
prog.From3 = newAddr(a[0])
@@ -666,7 +667,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
p.errorf("can't handle %s instruction with 4 operands", obj.Aconv(op))
return
case 5:
- if p.arch.Thechar == '9' && arch.IsPPC64RLD(op) {
+ if p.arch.Family == sys.PPC64 && arch.IsPPC64RLD(op) {
// Always reg, reg, con, con, reg. (con, con is a 'mask').
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
@@ -688,7 +689,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
p.errorf("can't handle %s instruction with 5 operands", obj.Aconv(op))
return
case 6:
- if p.arch.Thechar == '5' && arch.IsARMMRC(op) {
+ if p.arch.Family == sys.ARM && arch.IsARMMRC(op) {
// Strange special case: MCR, MRC.
prog.To.Type = obj.TYPE_CONST
x0 := p.getConstant(prog, op, &a[0])
diff --git a/src/cmd/asm/internal/asm/endtoend_test.go b/src/cmd/asm/internal/asm/endtoend_test.go
index 1307c4243f..bc992a7c99 100644
--- a/src/cmd/asm/internal/asm/endtoend_test.go
+++ b/src/cmd/asm/internal/asm/endtoend_test.go
@@ -5,6 +5,7 @@
package asm
import (
+ "bufio"
"bytes"
"fmt"
"io/ioutil"
@@ -33,7 +34,7 @@ func testEndToEnd(t *testing.T, goarch, file string) {
pList := obj.Linknewplist(ctxt)
var ok bool
testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
- ctxt.Bso = obj.Binitw(os.Stdout)
+ ctxt.Bso = bufio.NewWriter(os.Stdout)
defer ctxt.Bso.Flush()
failed := false
ctxt.DiagFunc = func(format string, args ...interface{}) {
@@ -271,7 +272,7 @@ func testErrors(t *testing.T, goarch, file string) {
pList := obj.Linknewplist(ctxt)
var ok bool
testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
- ctxt.Bso = obj.Binitw(os.Stdout)
+ ctxt.Bso = bufio.NewWriter(os.Stdout)
defer ctxt.Bso.Flush()
failed := false
var errBuf bytes.Buffer
diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go
index ee37439962..40206e6dc1 100644
--- a/src/cmd/asm/internal/asm/parse.go
+++ b/src/cmd/asm/internal/asm/parse.go
@@ -19,6 +19,7 @@ import (
"cmd/asm/internal/flags"
"cmd/asm/internal/lex"
"cmd/internal/obj"
+ "cmd/internal/sys"
)
type Parser struct {
@@ -130,7 +131,7 @@ func (p *Parser) line() bool {
for {
tok = p.lex.Next()
if len(operands) == 0 && len(items) == 0 {
- if (p.arch.Thechar == '5' || p.arch.Thechar == '7') && tok == '.' {
+ if p.arch.InFamily(sys.ARM, sys.ARM64) && tok == '.' {
// ARM conditionals.
tok = p.lex.Next()
str := p.lex.Text()
@@ -420,7 +421,7 @@ func (p *Parser) atStartOfRegister(name string) bool {
// We have consumed the register or R prefix.
func (p *Parser) atRegisterShift() bool {
// ARM only.
- if p.arch.Thechar != '5' {
+ if p.arch.Family != sys.ARM {
return false
}
// R1<<...
@@ -476,15 +477,14 @@ func (p *Parser) register(name string, prefix rune) (r1, r2 int16, scale int8, o
if c == ':' || c == ',' || c == '+' {
// 2nd register; syntax (R1+R2) etc. No two architectures agree.
// Check the architectures match the syntax.
- char := p.arch.Thechar
switch p.next().ScanToken {
case ',':
- if char != '5' && char != '7' {
+ if !p.arch.InFamily(sys.ARM, sys.ARM64) {
p.errorf("(register,register) not supported on this architecture")
return
}
case '+':
- if char != '9' {
+ if p.arch.Family != sys.PPC64 {
p.errorf("(register+register) not supported on this architecture")
return
}
@@ -649,7 +649,7 @@ func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) {
a.Reg = r1
if r2 != 0 {
// TODO: Consistency in the encoding would be nice here.
- if p.arch.Thechar == '5' || p.arch.Thechar == '7' {
+ if p.arch.InFamily(sys.ARM, sys.ARM64) {
// Special form
// ARM: destination register pair (R1, R2).
// ARM64: register pair (R1, R2) for LDP/STP.
@@ -662,7 +662,7 @@ func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) {
// Nothing may follow
return
}
- if p.arch.Thechar == '9' {
+ if p.arch.Family == sys.PPC64 {
// Special form for PPC64: (R1+R2); alias for (R1)(R2*1).
if prefix != 0 || scale != 0 {
p.errorf("illegal address mode for register+register")
@@ -752,7 +752,7 @@ ListLoop:
// register number is ARM-specific. It returns the number of the specified register.
func (p *Parser) registerNumber(name string) uint16 {
- if p.arch.Thechar == '5' && name == "g" {
+ if p.arch.Family == sys.ARM && name == "g" {
return 10
}
if name[0] != 'R' {
diff --git a/src/cmd/asm/internal/asm/testdata/s390x.s b/src/cmd/asm/internal/asm/testdata/s390x.s
index 148cd2eaae..f1dc9aff2d 100644
--- a/src/cmd/asm/internal/asm/testdata/s390x.s
+++ b/src/cmd/asm/internal/asm/testdata/s390x.s
@@ -61,6 +61,10 @@ TEXT main·foo(SB),7,$16-0 // TEXT main.foo(SB), 7, $16-0
MULLW R6, R7, R8 // b9040087b91c0086
MULLW $8192, R6 // c26000002000
MULLW $8192, R6, R7 // b9040076c27000002000
+ MULHD R9, R8 // b90400b8b98600a9ebb9003f000ab98000b8b90900abebb8003f000ab98000b9b9e9b08a
+ MULHD R7, R2, R1 // b90400b2b98600a7ebb7003f000ab98000b2b90900abebb2003f000ab98000b7b9e9b01a
+ MULHDU R3, R4 // b90400b4b98600a3b904004a
+ MULHDU R5, R6, R7 // b90400b6b98600a5b904007a
DIVD R1, R2 // b90400b2b90d00a1b904002b
DIVD R1, R2, R3 // b90400b2b90d00a1b904003b
DIVW R4, R5 // b90400b5b91d00a4b904005b
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
index 4e450bec98..c612583e6b 100644
--- a/src/cmd/asm/main.go
+++ b/src/cmd/asm/main.go
@@ -5,6 +5,7 @@
package main
import (
+ "bufio"
"flag"
"fmt"
"log"
@@ -15,6 +16,7 @@ import (
"cmd/asm/internal/flags"
"cmd/asm/internal/lex"
+ "cmd/internal/bio"
"cmd/internal/obj"
)
@@ -31,25 +33,26 @@ func main() {
flags.Parse()
- // Create object file, write header.
- fd, err := os.Create(*flags.OutputFile)
- if err != nil {
- log.Fatal(err)
- }
ctxt := obj.Linknew(architecture.LinkArch)
if *flags.PrintOut {
ctxt.Debugasm = 1
}
ctxt.LineHist.TrimPathPrefix = *flags.TrimPath
ctxt.Flag_dynlink = *flags.Dynlink
- if *flags.Shared || *flags.Dynlink {
- ctxt.Flag_shared = 1
- }
- ctxt.Bso = obj.Binitw(os.Stdout)
+ ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
+ ctxt.Bso = bufio.NewWriter(os.Stdout)
defer ctxt.Bso.Flush()
- output := obj.Binitw(fd)
- fmt.Fprintf(output, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion())
- fmt.Fprintf(output, "!\n")
+
+ // Create object file, write header.
+ out, err := os.Create(*flags.OutputFile)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer bio.MustClose(out)
+ buf := bufio.NewWriter(bio.MustWriter(out))
+
+ fmt.Fprintf(buf, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion())
+ fmt.Fprintf(buf, "!\n")
lexer := lex.NewLexer(flag.Arg(0), ctxt)
parser := asm.NewParser(ctxt, architecture, lexer)
@@ -63,12 +66,12 @@ func main() {
pList.Firstpc, ok = parser.Parse()
if ok {
// reports errors to parser.Errorf
- obj.Writeobjdirect(ctxt, output)
+ obj.Writeobjdirect(ctxt, buf)
}
if !ok || diag {
log.Printf("assembly of %s failed", flag.Arg(0))
os.Remove(*flags.OutputFile)
os.Exit(1)
}
- output.Flush()
+ buf.Flush()
}
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
index 2859d59750..823da43c1d 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -73,7 +73,7 @@ func (f *File) ReadGo(name string) {
}
for _, spec := range d.Specs {
s, ok := spec.(*ast.ImportSpec)
- if !ok || string(s.Path.Value) != `"C"` {
+ if !ok || s.Path.Value != `"C"` {
continue
}
sawC = true
@@ -106,7 +106,7 @@ func (f *File) ReadGo(name string) {
ws := 0
for _, spec := range d.Specs {
s, ok := spec.(*ast.ImportSpec)
- if !ok || string(s.Path.Value) != `"C"` {
+ if !ok || s.Path.Value != `"C"` {
d.Specs[ws] = spec
ws++
}
@@ -147,7 +147,7 @@ func commentText(g *ast.CommentGroup) string {
}
var pieces []string
for _, com := range g.List {
- c := string(com.Text)
+ c := com.Text
// Remove comment markers.
// The parser has given us exactly the comment text.
switch c[1] {
@@ -242,11 +242,11 @@ func (f *File) saveExport(x interface{}, context string) {
return
}
for _, c := range n.Doc.List {
- if !strings.HasPrefix(string(c.Text), "//export ") {
+ if !strings.HasPrefix(c.Text, "//export ") {
continue
}
- name := strings.TrimSpace(string(c.Text[9:]))
+ name := strings.TrimSpace(c.Text[9:])
if name == "" {
error_(c.Pos(), "export missing name")
}
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 84cd2e816a..3ee4461352 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -1009,7 +1009,7 @@ func (p *Package) rewriteRef(f *File) {
if r.Name.Kind == "var" {
expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
} else {
- error_(r.Pos(), "only C variables allowed in selector expression", fixGo(r.Name.Go))
+ error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go))
}
case "type":
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 5e863549d6..2dc36c20db 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -156,7 +156,7 @@ var intSizeMap = map[string]int64{
"ppc64": 8,
"ppc64le": 8,
"s390": 4,
- "s390x": 4,
+ "s390x": 8,
}
var cPrefix string
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 621c41c6b2..88b0147364 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -1451,7 +1451,7 @@ const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) {
void *_cgoPREFIX_Cfunc_CBytes(struct __go_open_array b) {
char *p = malloc(b.__count);
- memmove(p, b.__data, b.__count);
+ memmove(p, b.__values, b.__count);
return p;
}
diff --git a/src/cmd/compile/internal/amd64/galign.go b/src/cmd/compile/internal/amd64/galign.go
index 14721ea35b..461ef2ada1 100644
--- a/src/cmd/compile/internal/amd64/galign.go
+++ b/src/cmd/compile/internal/amd64/galign.go
@@ -18,12 +18,7 @@ var (
)
func betypeinit() {
- gc.Widthptr = 8
- gc.Widthint = 8
- gc.Widthreg = 8
if obj.Getgoarch() == "amd64p32" {
- gc.Widthptr = 4
- gc.Widthint = 4
addptr = x86.AADDL
movptr = x86.AMOVL
leaptr = x86.ALEAL
@@ -42,12 +37,9 @@ func Main() {
resvd = append(resvd, x86.REG_BP)
}
- gc.Thearch.Thechar = '6'
- gc.Thearch.Thestring = "amd64"
- gc.Thearch.Thelinkarch = &x86.Linkamd64
+ gc.Thearch.LinkArch = &x86.Linkamd64
if obj.Getgoarch() == "amd64p32" {
- gc.Thearch.Thestring = "amd64p32"
- gc.Thearch.Thelinkarch = &x86.Linkamd64p32
+ gc.Thearch.LinkArch = &x86.Linkamd64p32
}
gc.Thearch.REGSP = x86.REGSP
gc.Thearch.REGCTXT = x86.REGCTXT
diff --git a/src/cmd/compile/internal/amd64/gsubr.go b/src/cmd/compile/internal/amd64/gsubr.go
index 456fa7cbae..e3535f3244 100644
--- a/src/cmd/compile/internal/amd64/gsubr.go
+++ b/src/cmd/compile/internal/amd64/gsubr.go
@@ -722,7 +722,7 @@ func optoas(op gc.Op, t *gc.Type) obj.As {
a := obj.AXXX
switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
default:
- gc.Fatalf("optoas: no entry %v-%v", gc.Oconv(op, 0), t)
+ gc.Fatalf("optoas: no entry %v-%v", op, t)
case OADDR_ | gc.TPTR32:
a = x86.ALEAL
diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go
index 3f8e0ece12..6557287caa 100644
--- a/src/cmd/compile/internal/amd64/ssa.go
+++ b/src/cmd/compile/internal/amd64/ssa.go
@@ -62,7 +62,7 @@ func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
}
for i := len(b.Values) - 1; i >= 0; i-- {
v := b.Values[i]
- if flive && (v.Op == ssa.OpAMD64MOVBconst || v.Op == ssa.OpAMD64MOVWconst || v.Op == ssa.OpAMD64MOVLconst || v.Op == ssa.OpAMD64MOVQconst) {
+ if flive && (v.Op == ssa.OpAMD64MOVLconst || v.Op == ssa.OpAMD64MOVQconst) {
// The "mark" is any non-nil Aux value.
v.Aux = v
}
@@ -160,7 +160,7 @@ func opregreg(op obj.As, dest, src int16) *obj.Prog {
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line)
switch v.Op {
- case ssa.OpAMD64ADDQ, ssa.OpAMD64ADDL, ssa.OpAMD64ADDW, ssa.OpAMD64ADDB:
+ case ssa.OpAMD64ADDQ, ssa.OpAMD64ADDL:
r := gc.SSARegNum(v)
r1 := gc.SSARegNum(v.Args[0])
r2 := gc.SSARegNum(v.Args[1])
@@ -192,74 +192,23 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_REG
p.To.Reg = r
}
- // 2-address opcode arithmetic, symmetric
- case ssa.OpAMD64ADDSS, ssa.OpAMD64ADDSD,
- ssa.OpAMD64ANDQ, ssa.OpAMD64ANDL, ssa.OpAMD64ANDW, ssa.OpAMD64ANDB,
- ssa.OpAMD64ORQ, ssa.OpAMD64ORL, ssa.OpAMD64ORW, ssa.OpAMD64ORB,
- ssa.OpAMD64XORQ, ssa.OpAMD64XORL, ssa.OpAMD64XORW, ssa.OpAMD64XORB,
- ssa.OpAMD64MULQ, ssa.OpAMD64MULL, ssa.OpAMD64MULW, ssa.OpAMD64MULB,
- ssa.OpAMD64MULSS, ssa.OpAMD64MULSD, ssa.OpAMD64PXOR:
- r := gc.SSARegNum(v)
- x := gc.SSARegNum(v.Args[0])
- y := gc.SSARegNum(v.Args[1])
- if x != r && y != r {
- opregreg(moveByType(v.Type), r, x)
- x = r
- }
- p := gc.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_REG
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
- if x == r {
- p.From.Reg = y
- } else {
- p.From.Reg = x
- }
- // 2-address opcode arithmetic, not symmetric
- case ssa.OpAMD64SUBQ, ssa.OpAMD64SUBL, ssa.OpAMD64SUBW, ssa.OpAMD64SUBB:
- r := gc.SSARegNum(v)
- x := gc.SSARegNum(v.Args[0])
- y := gc.SSARegNum(v.Args[1])
- var neg bool
- if y == r {
- // compute -(y-x) instead
- x, y = y, x
- neg = true
- }
- if x != r {
- opregreg(moveByType(v.Type), r, x)
- }
- opregreg(v.Op.Asm(), r, y)
-
- if neg {
- if v.Op == ssa.OpAMD64SUBQ {
- p := gc.Prog(x86.ANEGQ)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
- } else { // Avoids partial registers write
- p := gc.Prog(x86.ANEGL)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
- }
- }
- case ssa.OpAMD64SUBSS, ssa.OpAMD64SUBSD, ssa.OpAMD64DIVSS, ssa.OpAMD64DIVSD:
+ // 2-address opcode arithmetic
+ case ssa.OpAMD64SUBQ, ssa.OpAMD64SUBL,
+ ssa.OpAMD64MULQ, ssa.OpAMD64MULL,
+ ssa.OpAMD64ANDQ, ssa.OpAMD64ANDL,
+ ssa.OpAMD64ORQ, ssa.OpAMD64ORL,
+ ssa.OpAMD64XORQ, ssa.OpAMD64XORL,
+ ssa.OpAMD64SHLQ, ssa.OpAMD64SHLL,
+ ssa.OpAMD64SHRQ, ssa.OpAMD64SHRL, ssa.OpAMD64SHRW, ssa.OpAMD64SHRB,
+ ssa.OpAMD64SARQ, ssa.OpAMD64SARL, ssa.OpAMD64SARW, ssa.OpAMD64SARB,
+ ssa.OpAMD64ADDSS, ssa.OpAMD64ADDSD, ssa.OpAMD64SUBSS, ssa.OpAMD64SUBSD,
+ ssa.OpAMD64MULSS, ssa.OpAMD64MULSD, ssa.OpAMD64DIVSS, ssa.OpAMD64DIVSD,
+ ssa.OpAMD64PXOR:
r := gc.SSARegNum(v)
- x := gc.SSARegNum(v.Args[0])
- y := gc.SSARegNum(v.Args[1])
- if y == r && x != r {
- // r/y := x op r/y, need to preserve x and rewrite to
- // r/y := r/y op x15
- x15 := int16(x86.REG_X15)
- // register move y to x15
- // register move x to y
- // rename y with x15
- opregreg(moveByType(v.Type), x15, y)
- opregreg(moveByType(v.Type), r, x)
- y = x15
- } else if x != r {
- opregreg(moveByType(v.Type), r, x)
+ if r != gc.SSARegNum(v.Args[0]) {
+ v.Fatalf("input[0] and output not in same register %s", v.LongString())
}
- opregreg(v.Op.Asm(), r, y)
+ opregreg(v.Op.Asm(), r, gc.SSARegNum(v.Args[1]))
case ssa.OpAMD64DIVQ, ssa.OpAMD64DIVL, ssa.OpAMD64DIVW,
ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU,
@@ -372,48 +321,21 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
// Do a 64-bit add, the overflow goes into the carry.
// Shift right once and pull the carry back into the 63rd bit.
r := gc.SSARegNum(v)
- x := gc.SSARegNum(v.Args[0])
- y := gc.SSARegNum(v.Args[1])
- if x != r && y != r {
- opregreg(moveByType(v.Type), r, x)
- x = r
+ if r != gc.SSARegNum(v.Args[0]) {
+ v.Fatalf("input[0] and output not in same register %s", v.LongString())
}
p := gc.Prog(x86.AADDQ)
p.From.Type = obj.TYPE_REG
p.To.Type = obj.TYPE_REG
p.To.Reg = r
- if x == r {
- p.From.Reg = y
- } else {
- p.From.Reg = x
- }
+ p.From.Reg = gc.SSARegNum(v.Args[1])
p = gc.Prog(x86.ARCRQ)
p.From.Type = obj.TYPE_CONST
p.From.Offset = 1
p.To.Type = obj.TYPE_REG
p.To.Reg = r
- case ssa.OpAMD64SHLQ, ssa.OpAMD64SHLL, ssa.OpAMD64SHLW, ssa.OpAMD64SHLB,
- ssa.OpAMD64SHRQ, ssa.OpAMD64SHRL, ssa.OpAMD64SHRW, ssa.OpAMD64SHRB,
- ssa.OpAMD64SARQ, ssa.OpAMD64SARL, ssa.OpAMD64SARW, ssa.OpAMD64SARB:
- x := gc.SSARegNum(v.Args[0])
- r := gc.SSARegNum(v)
- if x != r {
- if r == x86.REG_CX {
- v.Fatalf("can't implement %s, target and shift both in CX", v.LongString())
- }
- p := gc.Prog(moveByType(v.Type))
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
- }
- p := gc.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_REG
- p.From.Reg = gc.SSARegNum(v.Args[1]) // should be CX
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
- case ssa.OpAMD64ADDQconst, ssa.OpAMD64ADDLconst, ssa.OpAMD64ADDWconst, ssa.OpAMD64ADDBconst:
+ case ssa.OpAMD64ADDQconst, ssa.OpAMD64ADDLconst:
r := gc.SSARegNum(v)
a := gc.SSARegNum(v.Args[0])
if r == a {
@@ -433,7 +355,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_REG
p.To.Reg = r
return
- } else if v.AuxInt == -1 {
+ }
+ if v.AuxInt == -1 {
var asm obj.As
if v.Op == ssa.OpAMD64ADDQconst {
asm = x86.ADECQ
@@ -444,14 +367,13 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_REG
p.To.Reg = r
return
- } else {
- p := gc.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = v.AuxInt
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
- return
}
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = v.AuxInt
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ return
}
var asm obj.As
if v.Op == ssa.OpAMD64ADDQconst {
@@ -469,17 +391,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpAMD64CMOVQEQconst, ssa.OpAMD64CMOVLEQconst, ssa.OpAMD64CMOVWEQconst,
ssa.OpAMD64CMOVQNEconst, ssa.OpAMD64CMOVLNEconst, ssa.OpAMD64CMOVWNEconst:
r := gc.SSARegNum(v)
- x := gc.SSARegNum(v.Args[0])
- // Arg0 is in/out, move in to out if not already same
- if r != x {
- p := gc.Prog(moveByType(v.Type))
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
+ if r != gc.SSARegNum(v.Args[0]) {
+ v.Fatalf("input[0] and output not in same register %s", v.LongString())
}
- // Constant into AX, after arg0 movement in case arg0 is in AX
+ // Constant into AX
p := gc.Prog(moveByType(v.Type))
p.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt
@@ -492,15 +408,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_REG
p.To.Reg = r
- case ssa.OpAMD64MULQconst, ssa.OpAMD64MULLconst, ssa.OpAMD64MULWconst, ssa.OpAMD64MULBconst:
+ case ssa.OpAMD64MULQconst, ssa.OpAMD64MULLconst:
r := gc.SSARegNum(v)
- x := gc.SSARegNum(v.Args[0])
- if r != x {
- p := gc.Prog(moveByType(v.Type))
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
+ if r != gc.SSARegNum(v.Args[0]) {
+ v.Fatalf("input[0] and output not in same register %s", v.LongString())
}
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST
@@ -508,87 +419,22 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_REG
p.To.Reg = r
// TODO: Teach doasm to compile the three-address multiply imul $c, r1, r2
- // instead of using the MOVQ above.
+ // then we don't need to use resultInArg0 for these ops.
//p.From3 = new(obj.Addr)
//p.From3.Type = obj.TYPE_REG
//p.From3.Reg = gc.SSARegNum(v.Args[0])
- case ssa.OpAMD64SUBQconst, ssa.OpAMD64SUBLconst, ssa.OpAMD64SUBWconst, ssa.OpAMD64SUBBconst:
- x := gc.SSARegNum(v.Args[0])
- r := gc.SSARegNum(v)
- // We have 3-op add (lea), so transforming a = b - const into
- // a = b + (- const), saves us 1 instruction. We can't fit
- // - (-1 << 31) into 4 bytes offset in lea.
- // We handle 2-address just fine below.
- if v.AuxInt == -1<<31 || x == r {
- if x != r {
- // This code compensates for the fact that the register allocator
- // doesn't understand 2-address instructions yet. TODO: fix that.
- p := gc.Prog(moveByType(v.Type))
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
- }
- p := gc.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = v.AuxInt
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
- } else if x == r && v.AuxInt == -1 {
- var asm obj.As
- // x = x - (-1) is the same as x++
- // See OpAMD64ADDQconst comments about inc vs add $1,reg
- if v.Op == ssa.OpAMD64SUBQconst {
- asm = x86.AINCQ
- } else {
- asm = x86.AINCL
- }
- p := gc.Prog(asm)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
- } else if x == r && v.AuxInt == 1 {
- var asm obj.As
- if v.Op == ssa.OpAMD64SUBQconst {
- asm = x86.ADECQ
- } else {
- asm = x86.ADECL
- }
- p := gc.Prog(asm)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
- } else {
- var asm obj.As
- if v.Op == ssa.OpAMD64SUBQconst {
- asm = x86.ALEAQ
- } else {
- asm = x86.ALEAL
- }
- p := gc.Prog(asm)
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = x
- p.From.Offset = -v.AuxInt
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
- }
- case ssa.OpAMD64ANDQconst, ssa.OpAMD64ANDLconst, ssa.OpAMD64ANDWconst, ssa.OpAMD64ANDBconst,
- ssa.OpAMD64ORQconst, ssa.OpAMD64ORLconst, ssa.OpAMD64ORWconst, ssa.OpAMD64ORBconst,
- ssa.OpAMD64XORQconst, ssa.OpAMD64XORLconst, ssa.OpAMD64XORWconst, ssa.OpAMD64XORBconst,
- ssa.OpAMD64SHLQconst, ssa.OpAMD64SHLLconst, ssa.OpAMD64SHLWconst,
- ssa.OpAMD64SHLBconst, ssa.OpAMD64SHRQconst, ssa.OpAMD64SHRLconst, ssa.OpAMD64SHRWconst,
- ssa.OpAMD64SHRBconst, ssa.OpAMD64SARQconst, ssa.OpAMD64SARLconst, ssa.OpAMD64SARWconst,
- ssa.OpAMD64SARBconst, ssa.OpAMD64ROLQconst, ssa.OpAMD64ROLLconst, ssa.OpAMD64ROLWconst,
- ssa.OpAMD64ROLBconst:
- // This code compensates for the fact that the register allocator
- // doesn't understand 2-address instructions yet. TODO: fix that.
- x := gc.SSARegNum(v.Args[0])
+ case ssa.OpAMD64SUBQconst, ssa.OpAMD64SUBLconst,
+ ssa.OpAMD64ANDQconst, ssa.OpAMD64ANDLconst,
+ ssa.OpAMD64ORQconst, ssa.OpAMD64ORLconst,
+ ssa.OpAMD64XORQconst, ssa.OpAMD64XORLconst,
+ ssa.OpAMD64SHLQconst, ssa.OpAMD64SHLLconst,
+ ssa.OpAMD64SHRQconst, ssa.OpAMD64SHRLconst, ssa.OpAMD64SHRWconst, ssa.OpAMD64SHRBconst,
+ ssa.OpAMD64SARQconst, ssa.OpAMD64SARLconst, ssa.OpAMD64SARWconst, ssa.OpAMD64SARBconst,
+ ssa.OpAMD64ROLQconst, ssa.OpAMD64ROLLconst, ssa.OpAMD64ROLWconst, ssa.OpAMD64ROLBconst:
r := gc.SSARegNum(v)
- if x != r {
- p := gc.Prog(moveByType(v.Type))
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
+ if r != gc.SSARegNum(v.Args[0]) {
+ v.Fatalf("input[0] and output not in same register %s", v.LongString())
}
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST
@@ -651,7 +497,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Offset = v.AuxInt
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v.Args[0])
- case ssa.OpAMD64MOVBconst, ssa.OpAMD64MOVWconst, ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst:
+ case ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst:
x := gc.SSARegNum(v)
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST
@@ -966,17 +812,12 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
if gc.Maxarg < v.AuxInt {
gc.Maxarg = v.AuxInt
}
- case ssa.OpAMD64NEGQ, ssa.OpAMD64NEGL, ssa.OpAMD64NEGW, ssa.OpAMD64NEGB,
+ case ssa.OpAMD64NEGQ, ssa.OpAMD64NEGL,
ssa.OpAMD64BSWAPQ, ssa.OpAMD64BSWAPL,
- ssa.OpAMD64NOTQ, ssa.OpAMD64NOTL, ssa.OpAMD64NOTW, ssa.OpAMD64NOTB:
- x := gc.SSARegNum(v.Args[0])
+ ssa.OpAMD64NOTQ, ssa.OpAMD64NOTL:
r := gc.SSARegNum(v)
- if x != r {
- p := gc.Prog(moveByType(v.Type))
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x
- p.To.Type = obj.TYPE_REG
- p.To.Reg = r
+ if r != gc.SSARegNum(v.Args[0]) {
+ v.Fatalf("input[0] and output not in same register %s", v.LongString())
}
p := gc.Prog(v.Op.Asm())
p.To.Type = obj.TYPE_REG
diff --git a/src/cmd/compile/internal/arm/cgen64.go b/src/cmd/compile/internal/arm/cgen64.go
index 337bf03179..33e840615c 100644
--- a/src/cmd/compile/internal/arm/cgen64.go
+++ b/src/cmd/compile/internal/arm/cgen64.go
@@ -19,7 +19,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
if res.Op != gc.OINDREG && res.Op != gc.ONAME {
gc.Dump("n", n)
gc.Dump("res", res)
- gc.Fatalf("cgen64 %v of %v", gc.Oconv(n.Op, 0), gc.Oconv(res.Op, 0))
+ gc.Fatalf("cgen64 %v of %v", n.Op, res.Op)
}
l := n.Left
@@ -35,7 +35,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
split64(l, &lo1, &hi1)
switch n.Op {
default:
- gc.Fatalf("cgen64 %v", gc.Oconv(n.Op, 0))
+ gc.Fatalf("cgen64 %v", n.Op)
case gc.OMINUS:
var lo2 gc.Node
@@ -793,7 +793,7 @@ func cmp64(nl *gc.Node, nr *gc.Node, op gc.Op, likely int, to *obj.Prog) {
var br *obj.Prog
switch op {
default:
- gc.Fatalf("cmp64 %v %v", gc.Oconv(op, 0), t)
+ gc.Fatalf("cmp64 %v %v", op, t)
// cmp hi
// bne L
diff --git a/src/cmd/compile/internal/arm/galign.go b/src/cmd/compile/internal/arm/galign.go
index e05f4d06bb..afd86e44c8 100644
--- a/src/cmd/compile/internal/arm/galign.go
+++ b/src/cmd/compile/internal/arm/galign.go
@@ -11,15 +11,10 @@ import (
)
func betypeinit() {
- gc.Widthptr = 4
- gc.Widthint = 4
- gc.Widthreg = 4
}
func Main() {
- gc.Thearch.Thechar = '5'
- gc.Thearch.Thestring = "arm"
- gc.Thearch.Thelinkarch = &arm.Linkarm
+ gc.Thearch.LinkArch = &arm.Linkarm
gc.Thearch.REGSP = arm.REGSP
gc.Thearch.REGCTXT = arm.REGCTXT
gc.Thearch.REGCALLX = arm.REG_R1
diff --git a/src/cmd/compile/internal/arm/gsubr.go b/src/cmd/compile/internal/arm/gsubr.go
index 26da2e2081..73905f18ce 100644
--- a/src/cmd/compile/internal/arm/gsubr.go
+++ b/src/cmd/compile/internal/arm/gsubr.go
@@ -719,7 +719,7 @@ func raddr(n *gc.Node, p *obj.Prog) {
gc.Naddr(&a, n)
if a.Type != obj.TYPE_REG {
if n != nil {
- gc.Fatalf("bad in raddr: %v", gc.Oconv(n.Op, 0))
+ gc.Fatalf("bad in raddr: %v", n.Op)
} else {
gc.Fatalf("bad in raddr: <null>")
}
@@ -790,7 +790,7 @@ func optoas(op gc.Op, t *gc.Type) obj.As {
a := obj.AXXX
switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
default:
- gc.Fatalf("optoas: no entry %v-%v etype %v simtype %v", gc.Oconv(op, 0), t, gc.Types[t.Etype], gc.Types[gc.Simtype[t.Etype]])
+ gc.Fatalf("optoas: no entry %v-%v etype %v simtype %v", op, t, gc.Types[t.Etype], gc.Types[gc.Simtype[t.Etype]])
/* case CASE(OADDR, TPTR32):
a = ALEAL;
diff --git a/src/cmd/compile/internal/arm/ssa.go b/src/cmd/compile/internal/arm/ssa.go
index e6211d00b7..ca10f1c508 100644
--- a/src/cmd/compile/internal/arm/ssa.go
+++ b/src/cmd/compile/internal/arm/ssa.go
@@ -91,8 +91,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpARMCMP:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
- p.From.Reg = gc.SSARegNum(v.Args[0])
- p.Reg = gc.SSARegNum(v.Args[1])
+ // Special layout in ARM assembly
+ // Comparing to x86, the operands of ARM's CMP are reversed.
+ p.From.Reg = gc.SSARegNum(v.Args[1])
+ p.Reg = gc.SSARegNum(v.Args[0])
case ssa.OpARMMOVWload:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_MEM
@@ -142,7 +144,7 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
case ssa.BlockRet:
gc.Prog(obj.ARET)
case ssa.BlockARMLT:
- p := gc.Prog(arm.ABGE)
+ p := gc.Prog(arm.ABLT)
p.To.Type = obj.TYPE_BRANCH
s.Branches = append(s.Branches, gc.Branch{p, b.Succs[0]})
p = gc.Prog(obj.AJMP)
diff --git a/src/cmd/compile/internal/arm64/galign.go b/src/cmd/compile/internal/arm64/galign.go
index 7e1226fee1..7acc4e08eb 100644
--- a/src/cmd/compile/internal/arm64/galign.go
+++ b/src/cmd/compile/internal/arm64/galign.go
@@ -10,15 +10,10 @@ import (
)
func betypeinit() {
- gc.Widthptr = 8
- gc.Widthint = 8
- gc.Widthreg = 8
}
func Main() {
- gc.Thearch.Thechar = '7'
- gc.Thearch.Thestring = "arm64"
- gc.Thearch.Thelinkarch = &arm64.Linkarm64
+ gc.Thearch.LinkArch = &arm64.Linkarm64
gc.Thearch.REGSP = arm64.REGSP
gc.Thearch.REGCTXT = arm64.REGCTXT
gc.Thearch.REGCALLX = arm64.REGRT1
@@ -34,6 +29,8 @@ func Main() {
gc.Thearch.Betypeinit = betypeinit
gc.Thearch.Cgen_hmul = cgen_hmul
+ gc.Thearch.AddSetCarry = AddSetCarry
+ gc.Thearch.RightShiftWithCarry = RightShiftWithCarry
gc.Thearch.Cgen_shift = cgen_shift
gc.Thearch.Clearfat = clearfat
gc.Thearch.Defframe = defframe
diff --git a/src/cmd/compile/internal/arm64/ggen.go b/src/cmd/compile/internal/arm64/ggen.go
index 9abd901d7a..bddfed631a 100644
--- a/src/cmd/compile/internal/arm64/ggen.go
+++ b/src/cmd/compile/internal/arm64/ggen.go
@@ -252,6 +252,53 @@ func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
}
}
+// RightShiftWithCarry generates a constant unsigned
+// right shift with carry.
+//
+// res = n >> shift // with carry
+func RightShiftWithCarry(n *gc.Node, shift uint, res *gc.Node) {
+ // Extra 1 is for carry bit.
+ maxshift := uint(n.Type.Width*8 + 1)
+ if shift == 0 {
+ gmove(n, res)
+ } else if shift < maxshift {
+ // 1. clear rightmost bit of target
+ var n1 gc.Node
+ gc.Nodconst(&n1, n.Type, 1)
+ gins(optoas(gc.ORSH, n.Type), &n1, n)
+ gins(optoas(gc.OLSH, n.Type), &n1, n)
+ // 2. add carry flag to target
+ var n2 gc.Node
+ gc.Nodconst(&n1, n.Type, 0)
+ gc.Regalloc(&n2, n.Type, nil)
+ gins(optoas(gc.OAS, n.Type), &n1, &n2)
+ gins(arm64.AADC, &n2, n)
+ // 3. right rotate 1 bit
+ gc.Nodconst(&n1, n.Type, 1)
+ gins(arm64.AROR, &n1, n)
+
+ // ARM64 backend doesn't eliminate shifts by 0. It is manually checked here.
+ if shift > 1 {
+ var n3 gc.Node
+ gc.Nodconst(&n3, n.Type, int64(shift-1))
+ cgen_shift(gc.ORSH, true, n, &n3, res)
+ } else {
+ gmove(n, res)
+ }
+ gc.Regfree(&n2)
+ } else {
+ gc.Fatalf("RightShiftWithCarry: shift(%v) is bigger than max size(%v)", shift, maxshift)
+ }
+}
+
+// AddSetCarry generates add and set carry.
+//
+// res = nl + nr // with carry flag set
+func AddSetCarry(nl *gc.Node, nr *gc.Node, res *gc.Node) {
+ gins(arm64.AADDS, nl, nr)
+ gmove(nr, res)
+}
+
/*
* generate high multiply:
* res = (nl*nr) >> width
diff --git a/src/cmd/compile/internal/arm64/gsubr.go b/src/cmd/compile/internal/arm64/gsubr.go
index 4d64e790af..f193291d01 100644
--- a/src/cmd/compile/internal/arm64/gsubr.go
+++ b/src/cmd/compile/internal/arm64/gsubr.go
@@ -567,7 +567,7 @@ func raddr(n *gc.Node, p *obj.Prog) {
gc.Naddr(&a, n)
if a.Type != obj.TYPE_REG {
if n != nil {
- gc.Fatalf("bad in raddr: %v", gc.Oconv(n.Op, 0))
+ gc.Fatalf("bad in raddr: %v", n.Op)
} else {
gc.Fatalf("bad in raddr: <null>")
}
@@ -579,7 +579,7 @@ func raddr(n *gc.Node, p *obj.Prog) {
func gcmp(as obj.As, lhs *gc.Node, rhs *gc.Node) *obj.Prog {
if lhs.Op != gc.OREGISTER {
- gc.Fatalf("bad operands to gcmp: %v %v", gc.Oconv(lhs.Op, 0), gc.Oconv(rhs.Op, 0))
+ gc.Fatalf("bad operands to gcmp: %v %v", lhs.Op, rhs.Op)
}
p := rawgins(as, rhs, nil)
@@ -622,7 +622,7 @@ func optoas(op gc.Op, t *gc.Type) obj.As {
a := obj.AXXX
switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
default:
- gc.Fatalf("optoas: no entry for op=%v type=%v", gc.Oconv(op, 0), t)
+ gc.Fatalf("optoas: no entry for op=%v type=%v", op, t)
case OEQ_ | gc.TBOOL,
OEQ_ | gc.TINT8,
@@ -890,18 +890,6 @@ func optoas(op gc.Op, t *gc.Type) obj.As {
ORSH_ | gc.TINT64:
a = arm64.AASR
- // TODO(minux): handle rotates
- //case CASE(ORROTC, TINT8):
- //case CASE(ORROTC, TUINT8):
- //case CASE(ORROTC, TINT16):
- //case CASE(ORROTC, TUINT16):
- //case CASE(ORROTC, TINT32):
- //case CASE(ORROTC, TUINT32):
- //case CASE(ORROTC, TINT64):
- //case CASE(ORROTC, TUINT64):
- // a = 0//??? RLDC??
- // break;
-
case OHMUL_ | gc.TINT64:
a = arm64.ASMULH
diff --git a/src/cmd/compile/internal/arm64/peep.go b/src/cmd/compile/internal/arm64/peep.go
index 887353c889..22be1afebc 100644
--- a/src/cmd/compile/internal/arm64/peep.go
+++ b/src/cmd/compile/internal/arm64/peep.go
@@ -534,10 +534,13 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
return 0
case arm64.AADD, /* read p->from, read p->reg, write p->to */
+ arm64.AADDS,
arm64.ASUB,
+ arm64.AADC,
arm64.AAND,
arm64.AORR,
arm64.AEOR,
+ arm64.AROR,
arm64.AMUL,
arm64.ASMULL,
arm64.AUMULL,
diff --git a/src/cmd/compile/internal/arm64/prog.go b/src/cmd/compile/internal/arm64/prog.go
index 3091c4a840..d504d0f0ee 100644
--- a/src/cmd/compile/internal/arm64/prog.go
+++ b/src/cmd/compile/internal/arm64/prog.go
@@ -59,6 +59,9 @@ var progtable = [arm64.ALAST & obj.AMask]obj.ProgInfo{
arm64.ALSR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AASR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.ACMP & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
+ arm64.AADC & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite | gc.UseCarry},
+ arm64.AROR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ arm64.AADDS & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite | gc.SetCarry},
// Floating point.
arm64.AFADDD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
index e9b5afe838..136612d56f 100644
--- a/src/cmd/compile/internal/gc/alg.go
+++ b/src/cmd/compile/internal/gc/alg.go
@@ -127,11 +127,10 @@ func algtype1(t *Type) (AlgKind, *Type) {
}
return AINTER, nil
- case TARRAY:
- if t.IsSlice() {
- return ANOEQ, t
- }
+ case TSLICE:
+ return ANOEQ, t
+ case TARRAY:
a, bad := algtype1(t.Elem())
switch a {
case AMEM:
@@ -219,10 +218,6 @@ func genhash(sym *Sym, t *Type) {
Fatalf("genhash %v", t)
case TARRAY:
- if t.IsSlice() {
- Fatalf("genhash %v", t)
- }
-
// An array of pure memory would be handled by the
// standard algorithm, so the element type must not be
// pure memory.
@@ -316,11 +311,12 @@ func genhash(sym *Sym, t *Type) {
// for a struct containing a reflect.Value, which itself has
// an unexported field of type unsafe.Pointer.
old_safemode := safemode
+ safemode = false
- safemode = 0
Disable_checknil++
funccompile(fn)
Disable_checknil--
+
safemode = old_safemode
}
@@ -398,10 +394,6 @@ func geneq(sym *Sym, t *Type) {
Fatalf("geneq %v", t)
case TARRAY:
- if t.IsSlice() {
- Fatalf("geneq %v", t)
- }
-
// An array of pure memory would be handled by the
// standard memequal, so the element type must not be
// pure memory. Even if we unrolled the range loop,
@@ -509,7 +501,7 @@ func geneq(sym *Sym, t *Type) {
// for a struct containing a reflect.Value, which itself has
// an unexported field of type unsafe.Pointer.
old_safemode := safemode
- safemode = 0
+ safemode = false
// Disable checknils while compiling this code.
// We are comparing a struct or an array,
diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go
index b7ed9f19b9..8123041318 100644
--- a/src/cmd/compile/internal/gc/align.go
+++ b/src/cmd/compile/internal/gc/align.go
@@ -198,11 +198,11 @@ func dowidth(t *Type) {
// make fake type to check later to
// trigger channel argument check.
- t1 := typWrapper(TCHANARGS, t)
+ t1 := typChanArgs(t)
checkwidth(t1)
case TCHANARGS:
- t1 := t.Wrapped()
+ t1 := t.ChanArgs()
dowidth(t1) // just in case
if t1.Elem().Width >= 1<<16 {
Yyerror("channel element type too large (>64kB)")
@@ -238,32 +238,34 @@ func dowidth(t *Type) {
if t.Elem() == nil {
break
}
- if t.IsArray() {
- dowidth(t.Elem())
- if t.Elem().Width != 0 {
- cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width)
- if uint64(t.NumElem()) > cap {
- Yyerror("type %v larger than address space", Tconv(t, FmtLong))
- }
- }
-
- w = t.NumElem() * t.Elem().Width
- t.Align = t.Elem().Align
- } else if t.IsSlice() {
- w = int64(sizeof_Array)
- checkwidth(t.Elem())
- t.Align = uint8(Widthptr)
- } else if t.isDDDArray() {
+ if t.isDDDArray() {
if !t.Broke {
Yyerror("use of [...] array outside of array literal")
t.Broke = true
}
- } else {
- Fatalf("dowidth %v", t) // probably [...]T
+ break
+ }
+
+ dowidth(t.Elem())
+ if t.Elem().Width != 0 {
+ cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width)
+ if uint64(t.NumElem()) > cap {
+ Yyerror("type %v larger than address space", Tconv(t, FmtLong))
+ }
}
+ w = t.NumElem() * t.Elem().Width
+ t.Align = t.Elem().Align
+
+ case TSLICE:
+ if t.Elem() == nil {
+ break
+ }
+ w = int64(sizeof_Array)
+ checkwidth(t.Elem())
+ t.Align = uint8(Widthptr)
case TSTRUCT:
- if t.Funarg {
+ if t.IsFuncArgStruct() {
Fatalf("dowidth fn struct %v", t)
}
w = widstruct(t, t, 0, 1)
@@ -271,18 +273,18 @@ func dowidth(t *Type) {
// make fake type to check later to
// trigger function argument computation.
case TFUNC:
- t1 := typWrapper(TFUNCARGS, t)
+ t1 := typFuncArgs(t)
checkwidth(t1)
w = int64(Widthptr) // width of func type is pointer
// function is 3 cated structures;
// compute their widths as side-effect.
case TFUNCARGS:
- t1 := t.Wrapped()
+ t1 := t.FuncArgs()
w = widstruct(t1, t1.Recvs(), 0, 0)
w = widstruct(t1, t1.Params(), w, Widthreg)
w = widstruct(t1, t1.Results(), w, Widthreg)
- t1.Argwid = w
+ t1.Extra.(*FuncType).Argwid = w
if w%int64(Widthreg) != 0 {
Warn("bad type %v %d\n", t1, w)
}
@@ -335,7 +337,7 @@ func checkwidth(t *Type) {
// function arg structs should not be checked
// outside of the enclosing function.
- if t.Funarg {
+ if t.IsFuncArgStruct() {
Fatalf("checkwidth %v", t)
}
@@ -386,7 +388,7 @@ func Argsize(t *Type) int {
}
}
- w = (w + int64(Widthptr) - 1) &^ (int64(Widthptr) - 1)
+ w = Rnd(w, int64(Widthptr))
if int64(int(w)) != w {
Fatalf("argsize too big")
}
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index 8968ce8924..53662620aa 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -36,32 +36,27 @@ If the field is a pointer to another object, that object is serialized,
recursively. Otherwise the field is written. Non-pointer fields are all
encoded as integer or string values.
-Only packages and types may be referred to more than once. When getting
-to a package or type that was not serialized before, an integer _index_
+Some objects (packages, types) may be referred to more than once. When
+reaching an object that was not serialized before, an integer _index_
is assigned to it, starting at 0. In this case, the encoding starts
with an integer _tag_ < 0. The tag value indicates the kind of object
-(package or type) that follows and that this is the first time that we
-see this object. If the package or tag was already serialized, the encoding
-starts with the respective package or type index >= 0. An importer can
-trivially determine if a package or type needs to be read in for the first
-time (tag < 0) and entered into the respective package or type table, or
-if the package or type was seen already (index >= 0), in which case the
-index is used to look up the object in a table.
+that follows and that this is the first time that we see this object.
+If the object was already serialized, the encoding is simply the object
+index >= 0. An importer can trivially determine if an object needs to
+be read in for the first time (tag < 0) and entered into the respective
+object table, or if the object was seen already (index >= 0), in which
+case the index is used to look up the object in a table.
Before exporting or importing, the type tables are populated with the
predeclared types (int, string, error, unsafe.Pointer, etc.). This way
they are automatically encoded with a known and fixed type index.
-TODO(gri) We may consider using the same sharing for other items
-that are written out, such as strings, or possibly symbols (*Sym).
-
Encoding format:
The export data starts with a single byte indicating the encoding format
(compact, or with debugging information), followed by a version string
-(so we can evolve the encoding if need be), the name of the imported
-package, and a string containing platform-specific information for that
-package.
+(so we can evolve the encoding if need be), and then the package object
+for the exported package (with an empty path).
After this header, two lists of objects and the list of inlined function
bodies follows.
@@ -74,11 +69,17 @@ the previously imported type pointer so that we have exactly one version
(i.e., one pointer) for each named type (and read but discard the current
type encoding). Unnamed types simply encode their respective fields.
-In the encoding, some lists start with the list length (incl. strings).
-Some lists are terminated with an end marker (usually for lists where
-we may not know the length a priori).
+In the encoding, some lists start with the list length. Some lists are
+terminated with an end marker (usually for lists where we may not know
+the length a priori).
+
+Integers use variable-length encoding for compact representation.
-All integer values use variable-length encoding for compact representation.
+Strings are canonicalized similar to objects that may occur multiple times:
+If the string was exported already, it is represented by its index only.
+Otherwise, the export data starts with the negative string length (negative,
+so we can distinguish from string index), followed by the string bytes.
+The empty string is mapped to index 0.
The exporter and importer are completely symmetric in implementation: For
each encoding routine there is a matching and symmetric decoding routine.
@@ -90,9 +91,9 @@ importer.
package gc
import (
+ "bufio"
"bytes"
"cmd/compile/internal/big"
- "cmd/internal/obj"
"encoding/binary"
"fmt"
"sort"
@@ -109,12 +110,13 @@ import (
//
// NOTE: This flag is the first flag to enable if importing dies because of
// (suspected) format errors, and whenever a change is made to the format.
-// Having debugFormat enabled increases the export data size massively (by
-// several factors) - avoid running with the flag enabled in general.
const debugFormat = false // default: false
-// TODO(gri) remove eventually
-const forceNewExport = false // force new export format - DO NOT SUBMIT with this flag set
+// forceObjFileStability enforces additional constraints in export data
+// and other parts of the compiler to eliminate object file differences
+// only due to the choice of export format.
+// TODO(gri) disable and remove once there is only one export format again
+const forceObjFileStability = true
const exportVersion = "v0"
@@ -126,10 +128,18 @@ const exportVersion = "v0"
const exportInlined = true // default: true
type exporter struct {
- out *obj.Biobuf
+ out *bufio.Writer
+
+ // object -> index maps, indexed in order of serialization
+ strIndex map[string]int
pkgIndex map[*Pkg]int
typIndex map[*Type]int
- inlined []*Func
+ funcList []*Func
+
+ // position encoding
+ posInfoFormat bool
+ prevFile string
+ prevLine int
// debugging support
written int // bytes written
@@ -137,13 +147,18 @@ type exporter struct {
trace bool
}
-// Export writes the exportlist for localpkg to out and returns the number of bytes written.
-func Export(out *obj.Biobuf, trace bool) int {
+// export writes the exportlist for localpkg to out and returns the number of bytes written.
+func export(out *bufio.Writer, trace bool) int {
p := exporter{
out: out,
+ strIndex: map[string]int{"": 0}, // empty string is mapped to 0
pkgIndex: make(map[*Pkg]int),
typIndex: make(map[*Type]int),
- trace: trace,
+ // don't emit pos info for builtin packages
+ // (not needed and avoids path name diffs in builtin.go between
+ // Windows and non-Windows machines, exposed via builtin_test.go)
+ posInfoFormat: Debug['A'] == 0,
+ trace: trace,
}
// first byte indicates low-level encoding format
@@ -151,7 +166,10 @@ func Export(out *obj.Biobuf, trace bool) int {
if debugFormat {
format = 'd'
}
- p.byte(format)
+ p.rawByte(format)
+
+ // posInfo exported or not?
+ p.bool(p.posInfoFormat)
// --- generic export data ---
@@ -184,22 +202,12 @@ func Export(out *obj.Biobuf, trace bool) int {
Fatalf("exporter: local package path not empty: %q", localpkg.Path)
}
p.pkg(localpkg)
-
- // write compiler-specific flags
- // TODO(gri) move this into the compiler-specific export data section
- {
- var flags string
- if safemode != 0 {
- flags = "safe"
- }
- p.string(flags)
- }
if p.trace {
p.tracef("\n")
}
// export objects
-
+ //
// First, export all exported (package-level) objects; i.e., all objects
// in the current exportlist. These objects represent all information
// required to import this package and type-check against it; i.e., this
@@ -272,6 +280,12 @@ func Export(out *obj.Biobuf, trace bool) int {
}
}
+ // write compiler-specific flags
+ p.bool(safemode)
+ if p.trace {
+ p.tracef("\n")
+ }
+
// Phase 2: Export objects added to exportlist during phase 1.
// Don't use range since exportlist may grow during this phase
// and we want to export all remaining objects.
@@ -328,27 +342,39 @@ func Export(out *obj.Biobuf, trace bool) int {
// --- inlined function bodies ---
if p.trace {
- p.tracef("\n--- inlined function bodies ---\n[ ")
+ p.tracef("\n--- inlined function bodies ---\n")
if p.indent != 0 {
Fatalf("exporter: incorrect indentation")
}
}
- // write inlined function bodies
- p.int(len(p.inlined))
- if p.trace {
- p.tracef("]\n")
- }
- for _, f := range p.inlined {
- if p.trace {
- p.tracef("\n----\nfunc { %s }\n", Hconv(f.Inl, FmtSharp))
- }
- p.stmtList(f.Inl)
- if p.trace {
- p.tracef("\n")
+ // write inlineable function bodies
+ objcount = 0
+ for i, f := range p.funcList {
+ if f != nil {
+ // function has inlineable body:
+ // write index and body
+ if p.trace {
+ p.tracef("\n----\nfunc { %s }\n", Hconv(f.Inl, FmtSharp))
+ }
+ p.int(i)
+ p.stmtList(f.Inl)
+ if p.trace {
+ p.tracef("\n")
+ }
+ objcount++
}
}
+ // indicate end of list
+ if p.trace {
+ p.tracef("\n")
+ }
+ p.int(-1) // invalid index terminates list
+
+ // for self-verification only (redundant)
+ p.int(objcount)
+
if p.trace {
p.tracef("\n--- end ---\n")
}
@@ -413,6 +439,7 @@ func (p *exporter) obj(sym *Sym) {
}
p.tag(constTag)
+ p.pos(n)
// TODO(gri) In inlined functions, constants are used directly
// so they should never occur as re-exported objects. We may
// not need the qualified name here. See also comment above.
@@ -441,6 +468,7 @@ func (p *exporter) obj(sym *Sym) {
if n.Type.Etype == TFUNC && n.Class == PFUNC {
// function
p.tag(funcTag)
+ p.pos(n)
p.qualifiedName(sym)
sig := sym.Def.Type
@@ -449,10 +477,9 @@ func (p *exporter) obj(sym *Sym) {
p.paramList(sig.Params(), inlineable)
p.paramList(sig.Results(), inlineable)
- index := -1
+ var f *Func
if inlineable {
- index = len(p.inlined)
- p.inlined = append(p.inlined, sym.Def.Func)
+ f = sym.Def.Func
// TODO(gri) re-examine reexportdeplist:
// Because we can trivially export types
// in-place, we don't need to collect types
@@ -460,23 +487,48 @@ func (p *exporter) obj(sym *Sym) {
// With an adjusted reexportdeplist used only
// by the binary exporter, we can also avoid
// the global exportlist.
- reexportdeplist(sym.Def.Func.Inl)
+ reexportdeplist(f.Inl)
}
- p.int(index)
+ p.funcList = append(p.funcList, f)
} else {
// variable
p.tag(varTag)
+ p.pos(n)
p.qualifiedName(sym)
p.typ(sym.Def.Type)
}
default:
- Fatalf("exporter: unexpected export symbol: %v %v", Oconv(n.Op, 0), sym)
+ Fatalf("exporter: unexpected export symbol: %v %v", n.Op, sym)
}
}
+func (p *exporter) pos(n *Node) {
+ if !p.posInfoFormat {
+ return
+ }
+
+ var file string
+ var line int
+ if n != nil {
+ file, line = Ctxt.LineHist.AbsFileLine(int(n.Lineno))
+ }
+
+ if file == p.prevFile && line != p.prevLine {
+ // common case: write delta-encoded line number
+ p.int(line - p.prevLine) // != 0
+ } else {
+ // uncommon case: filename changed, or line didn't change
+ p.int(0)
+ p.string(file)
+ p.int(line)
+ p.prevFile = file
+ }
+ p.prevLine = line
+}
+
func isInlineable(n *Node) bool {
- if exportInlined && n != nil && n.Func != nil && len(n.Func.Inl.Slice()) != 0 {
+ if exportInlined && n != nil && n.Func != nil && n.Func.Inl.Len() != 0 {
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
if Debug['l'] < 2 {
@@ -515,19 +567,20 @@ func (p *exporter) typ(t *Type) {
p.typIndex[t] = len(p.typIndex)
// pick off named types
- if sym := t.Sym; sym != nil {
+ if tsym := t.Sym; tsym != nil {
// Predeclared types should have been found in the type map.
if t.Orig == t {
Fatalf("exporter: predeclared type missing from type map?")
}
- // TODO(gri) The assertion below seems incorrect (crashes during all.bash).
- // we expect the respective definition to point to us
- // if sym.Def.Type != t {
- // Fatalf("exporter: type definition doesn't point to us?")
- // }
+
+ n := typenod(t)
+ if n.Type != t {
+ Fatalf("exporter: named type definition incorrectly set up")
+ }
p.tag(namedTag)
- p.qualifiedName(sym)
+ p.pos(n)
+ p.qualifiedName(tsym)
// write underlying type
p.typ(t.Orig)
@@ -559,6 +612,7 @@ func (p *exporter) typ(t *Type) {
Fatalf("invalid symbol name: %s (%v)", m.Sym.Name, m.Sym)
}
+ p.pos(m.Sym.Def)
p.fieldSym(m.Sym, false)
sig := m.Type
@@ -569,13 +623,12 @@ func (p *exporter) typ(t *Type) {
p.paramList(sig.Params(), inlineable)
p.paramList(sig.Results(), inlineable)
- index := -1
+ var f *Func
if inlineable {
- index = len(p.inlined)
- p.inlined = append(p.inlined, mfn.Func)
+ f = mfn.Func
reexportdeplist(mfn.Func.Inl)
}
- p.int(index)
+ p.funcList = append(p.funcList, f)
}
if p.trace && len(methods) > 0 {
@@ -591,18 +644,18 @@ func (p *exporter) typ(t *Type) {
if t.isDDDArray() {
Fatalf("array bounds should be known at export time: %v", t)
}
- if t.IsArray() {
- p.tag(arrayTag)
- p.int64(t.NumElem())
- } else {
- p.tag(sliceTag)
- }
+ p.tag(arrayTag)
+ p.int64(t.NumElem())
+ p.typ(t.Elem())
+
+ case TSLICE:
+ p.tag(sliceTag)
p.typ(t.Elem())
case TDDDFIELD:
// see p.param use of TDDDFIELD
p.tag(dddTag)
- p.typ(t.Wrapped())
+ p.typ(t.DDDField())
case TSTRUCT:
p.tag(structTag)
@@ -664,17 +717,10 @@ func (p *exporter) fieldList(t *Type) {
}
func (p *exporter) field(f *Field) {
+ p.pos(f.Sym.Def)
p.fieldName(f.Sym, f)
p.typ(f.Type)
- p.note(f.Note)
-}
-
-func (p *exporter) note(n *string) {
- var s string
- if n != nil {
- s = *n
- }
- p.string(s)
+ p.string(f.Note)
}
func (p *exporter) methodList(t *Type) {
@@ -693,6 +739,7 @@ func (p *exporter) methodList(t *Type) {
}
func (p *exporter) method(m *Field) {
+ p.pos(m.Sym.Def)
p.fieldName(m.Sym, m)
p.paramList(m.Type.Params(), false)
p.paramList(m.Type.Results(), false)
@@ -742,7 +789,7 @@ func basetypeName(t *Type) string {
}
func (p *exporter) paramList(params *Type, numbered bool) {
- if !params.IsStruct() || !params.Funarg {
+ if !params.IsFuncArgStruct() {
Fatalf("exporter: parameter list expected")
}
@@ -768,7 +815,7 @@ func (p *exporter) param(q *Field, n int, numbered bool) {
t := q.Type
if q.Isddd {
// create a fake type to encode ... just for the p.typ call
- t = typWrapper(TDDDFIELD, t.Elem())
+ t = typDDDField(t.Elem())
}
p.typ(t)
if n > 0 {
@@ -779,16 +826,17 @@ func (p *exporter) param(q *Field, n int, numbered bool) {
// supply the parameter package here. We need the package
// when the function is inlined so we can properly resolve
// the name.
- // TODO(gri) should do this only once per function/method
+ // TODO(gri) This is compiler-specific. Try using importpkg
+ // here and then update the symbols if we find an inlined
+ // body only. Otherwise, the parameter name is ignored and
+ // the package doesn't matter. This would remove an int
+ // (likely 1 byte) for each named parameter.
p.pkg(q.Sym.Pkg)
}
// TODO(gri) This is compiler-specific (escape info).
// Move into compiler-specific section eventually?
// (Not having escape info causes tests to fail, e.g. runtime GCInfoTest)
- //
- // TODO(gri) The q.Note is much more verbose that necessary and
- // adds significantly to export data size. FIX THIS.
- p.note(q.Note)
+ p.string(q.Note)
}
func parName(f *Field, numbered bool) string {
@@ -827,7 +875,7 @@ func parName(f *Field, numbered bool) string {
// Functions that can be inlined use numbered parameters so we can distingish them
// from other names in their context after inlining (i.e., the parameter numbering
// is a form of parameter rewriting). See issue 4326 for an example and test case.
- if numbered {
+ if forceObjFileStability || numbered {
if !strings.Contains(name, "·") && f.Nname != nil && f.Nname.Name != nil && f.Nname.Name.Vargen > 0 {
name = fmt.Sprintf("%s·%d", name, f.Nname.Name.Vargen) // append Vargen
}
@@ -1132,12 +1180,15 @@ func (p *exporter) expr(n *Node) {
case OSLICE, OSLICESTR, OSLICEARR:
p.op(OSLICE)
p.expr(n.Left)
- p.expr(n.Right)
+ low, high, _ := n.SliceBounds()
+ p.exprsOrNil(low, high)
case OSLICE3, OSLICE3ARR:
p.op(OSLICE3)
p.expr(n.Left)
- p.expr(n.Right)
+ low, high, max := n.SliceBounds()
+ p.exprsOrNil(low, high)
+ p.expr(max)
case OCOPY, OCOMPLEX:
p.op(op)
@@ -1215,7 +1266,7 @@ func (p *exporter) expr(n *Node) {
p.op(ODCLCONST)
default:
- Fatalf("exporter: CANNOT EXPORT: %s\nPlease notify gri@\n", opnames[n.Op])
+ Fatalf("exporter: CANNOT EXPORT: %s\nPlease notify gri@\n", n.Op)
}
}
@@ -1262,12 +1313,11 @@ func (p *exporter) stmt(n *Node) {
// unimplemented - handled by default case
case OAS, OASWB:
- p.op(op)
// Don't export "v = <N>" initializing statements, hope they're always
// preceded by the DCL which will be re-parsed and typecheck to reproduce
// the "v = <N>" again.
- // TODO(gri) if n.Right == nil, don't emit anything
- if p.bool(n.Right != nil) {
+ if n.Right != nil {
+ p.op(OAS)
p.expr(n.Left)
p.expr(n.Right)
}
@@ -1280,16 +1330,14 @@ func (p *exporter) stmt(n *Node) {
p.expr(n.Right)
}
+ case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+ fallthrough
+
case OAS2:
p.op(OAS2)
p.exprList(n.List)
p.exprList(n.Rlist)
- case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
- p.op(op)
- p.exprList(n.List)
- p.exprList(n.Rlist)
-
case ORETURN:
p.op(ORETURN)
p.exprList(n.List)
@@ -1328,11 +1376,15 @@ func (p *exporter) stmt(n *Node) {
p.stmtList(n.List)
case OCASE, OXCASE:
- p.op(op)
+ p.op(OXCASE)
p.stmtList(n.List)
p.stmtList(n.Nbody)
- case OBREAK, OCONTINUE, OGOTO, OFALL, OXFALL:
+ case OFALL:
+ op = OXFALL
+ fallthrough
+
+ case OBREAK, OCONTINUE, OGOTO, OXFALL:
p.op(op)
p.exprsOrNil(n.Left, nil)
@@ -1344,7 +1396,7 @@ func (p *exporter) stmt(n *Node) {
p.expr(n.Left)
default:
- Fatalf("exporter: CANNOT EXPORT: %s\nPlease notify gri@\n", opnames[n.Op])
+ Fatalf("exporter: CANNOT EXPORT: %s\nPlease notify gri@\n", n.Op)
}
}
@@ -1432,7 +1484,7 @@ func (p *exporter) bool(b bool) bool {
func (p *exporter) op(op Op) {
if p.trace {
p.tracef("[")
- defer p.tracef("= %s] ", opnames[op])
+ defer p.tracef("= %s] ", op)
}
p.int(int(op))
@@ -1488,9 +1540,17 @@ func (p *exporter) string(s string) {
if p.trace {
p.tracef("%q ", s)
}
- p.rawInt64(int64(len(s)))
+ // if we saw the string before, write its index (>= 0)
+ // (the empty string is mapped to 0)
+ if i, ok := p.strIndex[s]; ok {
+ p.rawInt64(int64(i))
+ return
+ }
+ // otherwise, remember string and write its negative length and bytes
+ p.strIndex[s] = len(p.strIndex)
+ p.rawInt64(-int64(len(s)))
for i := 0; i < len(s); i++ {
- p.byte(s[i])
+ p.rawByte(s[i])
}
}
@@ -1498,7 +1558,7 @@ func (p *exporter) string(s string) {
// it easy for a reader to detect if it is "out of sync". Used only
// if debugFormat is set.
func (p *exporter) marker(m byte) {
- p.byte(m)
+ p.rawByte(m)
// Uncomment this for help tracking down the location
// of an incorrect marker when running in debugFormat.
// if p.trace {
@@ -1512,12 +1572,12 @@ func (p *exporter) rawInt64(x int64) {
var tmp [binary.MaxVarintLen64]byte
n := binary.PutVarint(tmp[:], x)
for i := 0; i < n; i++ {
- p.byte(tmp[i])
+ p.rawByte(tmp[i])
}
}
-// byte is the bottleneck interface to write to p.out.
-// byte escapes b as follows (any encoding does that
+// rawByte is the bottleneck interface to write to p.out.
+// rawByte escapes b as follows (any encoding does that
// hides '$'):
//
// '$' => '|' 'S'
@@ -1525,7 +1585,8 @@ func (p *exporter) rawInt64(x int64) {
//
// Necessary so other tools can find the end of the
// export data by searching for "$$".
-func (p *exporter) byte(b byte) {
+// rawByte should only be used by low-level encoders.
+func (p *exporter) rawByte(b byte) {
switch b {
case '$':
// write '$' as '|' 'S'
@@ -1533,10 +1594,10 @@ func (p *exporter) byte(b byte) {
fallthrough
case '|':
// write '|' as '|' '|'
- obj.Bputc(p.out, '|')
+ p.out.WriteByte('|')
p.written++
}
- obj.Bputc(p.out, b)
+ p.out.WriteByte(b)
p.written++
}
diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go
index 8c53372b80..6fe30cdba9 100644
--- a/src/cmd/compile/internal/gc/bimport.go
+++ b/src/cmd/compile/internal/gc/bimport.go
@@ -20,12 +20,19 @@ import (
// changes to bimport.go and bexport.go.
type importer struct {
- in *bufio.Reader
- buf []byte // for reading strings
- bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib
+ in *bufio.Reader
+ buf []byte // reused for reading strings
+
+ // object lists, in order of deserialization
+ strList []string
pkgList []*Pkg
typList []*Type
- inlined []*Node // functions with pending inlined function bodies
+ funcList []*Node // nil entry means already declared
+
+ // position encoding
+ posInfoFormat bool
+ prevFile string
+ prevLine int
// debugging support
debugFormat bool
@@ -34,11 +41,13 @@ type importer struct {
// Import populates importpkg from the serialized package data.
func Import(in *bufio.Reader) {
- p := importer{in: in}
- p.buf = p.bufarray[:]
+ p := importer{
+ in: in,
+ strList: []string{""}, // empty string is mapped to 0
+ }
// read low-level encoding format
- switch format := p.byte(); format {
+ switch format := p.rawByte(); format {
case 'c':
// compact format - nothing to do
case 'd':
@@ -47,6 +56,8 @@ func Import(in *bufio.Reader) {
Fatalf("importer: invalid encoding format in export data: got %q; want 'c' or 'd'", format)
}
+ p.posInfoFormat = p.bool()
+
// --- generic export data ---
if v := p.string(); v != exportVersion {
@@ -58,12 +69,6 @@ func Import(in *bufio.Reader) {
// read package data
p.pkg()
- if p.pkgList[0] != importpkg {
- Fatalf("importer: imported package not found in pkgList[0]")
- }
-
- // read compiler-specific flags
- importpkg.Safe = p.string() == "safe"
// defer some type-checking until all types are read in completely
// (parser.go:import_package)
@@ -73,7 +78,7 @@ func Import(in *bufio.Reader) {
// read objects
- // Phase 1
+ // phase 1
objcount := 0
for {
tag := p.tagOrIndex()
@@ -91,7 +96,10 @@ func Import(in *bufio.Reader) {
// --- compiler-specific export data ---
- // Phase 2
+ // read compiler-specific flags
+ importpkg.Safe = p.bool()
+
+ // phase 2
objcount = 0
for {
tag := p.tagOrIndex()
@@ -107,23 +115,46 @@ func Import(in *bufio.Reader) {
Fatalf("importer: got %d objects; want %d", objcount, count)
}
- // read inlined functions bodies
+ // read inlineable functions bodies
if dclcontext != PEXTERN {
Fatalf("importer: unexpected context %d", dclcontext)
}
- bcount := p.int() // consistency check only
- if bcount != len(p.inlined) {
- Fatalf("importer: expected %d inlined function bodies; got %d", bcount, len(p.inlined))
- }
- for _, f := range p.inlined {
+ objcount = 0
+ for i0 := -1; ; {
+ i := p.int() // index of function with inlineable body
+ if i < 0 {
+ break
+ }
+
+ // don't process the same function twice
+ if i <= i0 {
+ Fatalf("importer: index not increasing: %d <= %d", i, i0)
+ }
+ i0 = i
+
if Funcdepth != 0 {
Fatalf("importer: unexpected Funcdepth %d", Funcdepth)
}
- if f != nil {
- // function body not yet imported - read body and set it
+
+ // Note: In the original code, funchdr and funcbody are called for
+ // all functions (that were not yet imported). Now, we are calling
+ // them only for functions with inlineable bodies. funchdr does
+ // parameter renaming which doesn't matter if we don't have a body.
+
+ if f := p.funcList[i]; f != nil {
+ // function not yet imported - read body and set it
funchdr(f)
- f.Func.Inl.Set(p.stmtList())
+ body := p.stmtList()
+ if body == nil {
+ // Make sure empty body is not interpreted as
+ // no inlineable body (see also parser.fnbody)
+ // (not doing so can cause significant performance
+ // degradation due to unnecessary calls to empty
+ // functions).
+ body = []*Node{Nod(OEMPTY, nil, nil)}
+ }
+ f.Func.Inl.Set(body)
funcbody(f)
} else {
// function already imported - read body but discard declarations
@@ -131,6 +162,13 @@ func Import(in *bufio.Reader) {
p.stmtList()
dclcontext = PEXTERN
}
+
+ objcount++
+ }
+
+ // self-verification
+ if count := p.int(); count != objcount {
+ Fatalf("importer: got %d functions; want %d", objcount, count)
}
if dclcontext != PEXTERN {
@@ -171,7 +209,12 @@ func (p *importer) pkg() *Pkg {
Fatalf("importer: bad path in import: %q", path)
}
- // an empty path denotes the package we are currently importing
+ // an empty path denotes the package we are currently importing;
+ // it must be the first package we see
+ if (path == "") != (len(p.pkgList) == 0) {
+ panic(fmt.Sprintf("package path %q for pkg index %d", path, len(p.pkgList)))
+ }
+
pkg := importpkg
if path != "" {
pkg = mkpkg(path)
@@ -197,6 +240,7 @@ func idealType(typ *Type) *Type {
func (p *importer) obj(tag int) {
switch tag {
case constTag:
+ p.pos()
sym := p.qualifiedName()
typ := p.typ()
val := p.value(typ)
@@ -206,68 +250,66 @@ func (p *importer) obj(tag int) {
p.typ()
case varTag:
+ p.pos()
sym := p.qualifiedName()
typ := p.typ()
importvar(sym, typ)
case funcTag:
+ p.pos()
sym := p.qualifiedName()
params := p.paramList()
result := p.paramList()
- inl := p.int()
sig := functype(nil, params, result)
importsym(sym, ONAME)
if sym.Def != nil && sym.Def.Op == ONAME {
- if Eqtype(sig, sym.Def.Type) {
- // function was imported before (via another import)
- dclcontext = PDISCARD // since we skip funchdr below
- } else {
+ // function was imported before (via another import)
+ if !Eqtype(sig, sym.Def.Type) {
Fatalf("importer: inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, sig)
}
- }
-
- var n *Node
- if dclcontext != PDISCARD {
- n = newfuncname(sym)
- n.Type = sig
- declare(n, PFUNC)
- if inl < 0 {
- funchdr(n)
- }
- }
-
- if inl >= 0 {
- // function has inlined body - collect for later
- if inl != len(p.inlined) {
- Fatalf("importer: inlined index = %d; want %d", inl, len(p.inlined))
- }
- p.inlined = append(p.inlined, n)
- }
-
- // parser.go:hidden_import
- if dclcontext == PDISCARD {
- dclcontext = PEXTERN // since we skip the funcbody below
+ p.funcList = append(p.funcList, nil)
break
}
- if inl < 0 {
- funcbody(n)
- }
- importlist = append(importlist, n) // TODO(gri) may only be needed for inlineable functions
+ n := newfuncname(sym)
+ n.Type = sig
+ declare(n, PFUNC)
+ p.funcList = append(p.funcList, n)
+ importlist = append(importlist, n)
if Debug['E'] > 0 {
fmt.Printf("import [%q] func %v \n", importpkg.Path, n)
- if Debug['m'] > 2 && len(n.Func.Inl.Slice()) != 0 {
+ if Debug['m'] > 2 && n.Func.Inl.Len() != 0 {
fmt.Printf("inl body: %v\n", n.Func.Inl)
}
}
default:
- Fatalf("importer: unexpected object tag")
+ Fatalf("importer: unexpected object (tag = %d)", tag)
}
}
+func (p *importer) pos() {
+ if !p.posInfoFormat {
+ return
+ }
+
+ file := p.prevFile
+ line := p.prevLine
+
+ if delta := p.int(); delta != 0 {
+ line += delta
+ } else {
+ file = p.string()
+ line = p.int()
+ p.prevFile = file
+ }
+ p.prevLine = line
+
+ // TODO(gri) register new position
+}
+
func (p *importer) newtyp(etype EType) *Type {
t := typ(etype)
p.typList = append(p.typList, t)
@@ -286,6 +328,7 @@ func (p *importer) typ() *Type {
switch i {
case namedTag:
// parser.go:hidden_importsym
+ p.pos()
tsym := p.qualifiedName()
// parser.go:hidden_pkgtype
@@ -311,28 +354,19 @@ func (p *importer) typ() *Type {
for i := p.int(); i > 0; i-- {
// parser.go:hidden_fndcl
+ p.pos()
sym := p.fieldSym()
recv := p.paramList() // TODO(gri) do we need a full param list for the receiver?
params := p.paramList()
result := p.paramList()
- inl := p.int()
n := methodname1(newname(sym), recv[0].Right)
n.Type = functype(recv[0], params, result)
checkwidth(n.Type)
addmethod(sym, n.Type, tsym.Pkg, false, false)
- if inl < 0 {
- funchdr(n)
- }
-
- if inl >= 0 {
- // method has inlined body - collect for later
- if inl != len(p.inlined) {
- Fatalf("importer: inlined index = %d; want %d", inl, len(p.inlined))
- }
- p.inlined = append(p.inlined, n)
- }
+ p.funcList = append(p.funcList, n)
+ importlist = append(importlist, n)
// (comment from parser.go)
// inl.C's inlnode in on a dotmeth node expects to find the inlineable body as
@@ -341,15 +375,9 @@ func (p *importer) typ() *Type {
// this back link here we avoid special casing there.
n.Type.SetNname(n)
- // parser.go:hidden_import
- if inl < 0 {
- funcbody(n)
- }
- importlist = append(importlist, n) // TODO(gri) may only be needed for inlineable functions
-
if Debug['E'] > 0 {
fmt.Printf("import [%q] meth %v \n", importpkg.Path, n)
- if Debug['m'] > 2 && len(n.Func.Inl.Slice()) != 0 {
+ if Debug['m'] > 2 && n.Func.Inl.Len() != 0 {
fmt.Printf("inl body: %v\n", n.Func.Inl)
}
}
@@ -357,18 +385,20 @@ func (p *importer) typ() *Type {
dclcontext = savedContext
- case arrayTag, sliceTag:
+ case arrayTag:
t = p.newtyp(TARRAY)
- if i == arrayTag {
- t.SetNumElem(p.int64())
- } else {
- t.SetNumElem(sliceBound)
- }
- t.Type = p.typ()
+ bound := p.int64()
+ elem := p.typ()
+ t.Extra = &ArrayType{Elem: elem, Bound: bound}
+
+ case sliceTag:
+ t = p.newtyp(TSLICE)
+ elem := p.typ()
+ t.Extra = SliceType{Elem: elem}
case dddTag:
t = p.newtyp(TDDDFIELD)
- t.Type = p.typ()
+ t.Extra = DDDFieldType{T: p.typ()}
case structTag:
t = p.newtyp(TSTRUCT)
@@ -376,7 +406,7 @@ func (p *importer) typ() *Type {
case pointerTag:
t = p.newtyp(Tptr)
- t.Type = p.typ()
+ t.Extra = PtrType{Elem: p.typ()}
case signatureTag:
t = p.newtyp(TFUNC)
@@ -393,13 +423,15 @@ func (p *importer) typ() *Type {
case mapTag:
t = p.newtyp(TMAP)
- t.Down = p.typ() // key
- t.Type = p.typ() // val
+ mt := t.MapType()
+ mt.Key = p.typ()
+ mt.Val = p.typ()
case chanTag:
t = p.newtyp(TCHAN)
- t.Chan = ChanDir(p.int())
- t.Type = p.typ()
+ ct := t.ChanType()
+ ct.Dir = ChanDir(p.int())
+ ct.Elem = p.typ()
default:
Fatalf("importer: unexpected type (tag = %d)", i)
@@ -419,23 +451,22 @@ func (p *importer) qualifiedName() *Sym {
}
// parser.go:hidden_structdcl_list
-func (p *importer) fieldList() []*Node {
- i := p.int()
- if i == 0 {
- return nil
- }
- n := make([]*Node, i)
- for i := range n {
- n[i] = p.field()
+func (p *importer) fieldList() (fields []*Node) {
+ if n := p.int(); n > 0 {
+ fields = make([]*Node, n)
+ for i := range fields {
+ fields[i] = p.field()
+ }
}
- return n
+ return
}
// parser.go:hidden_structdcl
func (p *importer) field() *Node {
+ p.pos()
sym := p.fieldName()
typ := p.typ()
- note := p.note()
+ note := p.string()
var n *Node
if sym.Name != "" {
@@ -444,7 +475,7 @@ func (p *importer) field() *Node {
// anonymous field - typ must be T or *T and T must be a type name
s := typ.Sym
if s == nil && typ.IsPtr() {
- s = typ.Type.Sym // deref
+ s = typ.Elem().Sym // deref
}
pkg := importpkg
if sym != nil {
@@ -453,33 +484,25 @@ func (p *importer) field() *Node {
n = embedded(s, pkg)
n.Right = typenod(typ)
}
- n.SetVal(note)
+ n.SetVal(Val{U: note})
return n
}
-func (p *importer) note() (v Val) {
- if s := p.string(); s != "" {
- v.U = s
- }
- return
-}
-
// parser.go:hidden_interfacedcl_list
-func (p *importer) methodList() []*Node {
- i := p.int()
- if i == 0 {
- return nil
- }
- n := make([]*Node, i)
- for i := range n {
- n[i] = p.method()
+func (p *importer) methodList() (methods []*Node) {
+ if n := p.int(); n > 0 {
+ methods = make([]*Node, n)
+ for i := range methods {
+ methods[i] = p.method()
+ }
}
- return n
+ return
}
// parser.go:hidden_interfacedcl
func (p *importer) method() *Node {
+ p.pos()
sym := p.fieldName()
params := p.paramList()
result := p.paramList()
@@ -531,7 +554,7 @@ func (p *importer) param(named bool) *Node {
isddd := false
if typ.Etype == TDDDFIELD {
// TDDDFIELD indicates wrapped ... slice type
- typ = typSlice(typ.Wrapped())
+ typ = typSlice(typ.DDDField())
isddd = true
}
@@ -551,7 +574,7 @@ func (p *importer) param(named bool) *Node {
// TODO(gri) This is compiler-specific (escape info).
// Move into compiler-specific section eventually?
- n.SetVal(p.note())
+ n.SetVal(Val{U: p.string()})
return n
}
@@ -636,6 +659,10 @@ func (p *importer) float(x *Mpflt) {
// re-establish the syntax tree's invariants. At some future point we might be
// able to avoid this round-about way and create the rewritten nodes directly,
// possibly avoiding a lot of duplicate work (name resolution, type checking).
+//
+// Refined nodes (e.g., ODOTPTR as a refinement of OXDOT) are exported as their
+// unrefined nodes (since this is what the importer uses). The respective case
+// entries are unreachable in the importer.
func (p *importer) stmtList() []*Node {
var list []*Node
@@ -797,9 +824,19 @@ func (p *importer) node() *Node {
// case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
// unreachable - mapped to cases below by exporter
- case OINDEX, OSLICE, OSLICE3:
+ case OINDEX:
return Nod(op, p.expr(), p.expr())
+ case OSLICE, OSLICE3:
+ n := Nod(op, p.expr(), nil)
+ low, high := p.exprsOrNil()
+ var max *Node
+ if n.Op.IsSlice3() {
+ max = p.expr()
+ }
+ n.SetSliceBounds(low, high, max)
+ return n
+
case OCOPY, OCOMPLEX:
n := builtinCall(op)
n.List.Set([]*Node{p.expr(), p.expr()})
@@ -881,14 +918,11 @@ func (p *importer) node() *Node {
// case ODCLFIELD:
// unimplemented
- case OAS, OASWB:
- if p.bool() {
- lhs := p.expr()
- rhs := p.expr()
- return Nod(OAS, lhs, rhs)
- }
- // TODO(gri) we should not have emitted anything here
- return Nod(OEMPTY, nil, nil)
+ // case OAS, OASWB:
+ // unreachable - mapped to OAS case below by exporter
+
+ case OAS:
+ return Nod(OAS, p.expr(), p.expr())
case OASOP:
n := Nod(OASOP, nil, nil)
@@ -902,15 +936,10 @@ func (p *importer) node() *Node {
}
return n
- case OAS2:
- lhs := p.exprList()
- rhs := p.exprList()
- n := Nod(OAS2, nil, nil)
- n.List.Set(lhs)
- n.Rlist.Set(rhs)
- return n
+ // case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+ // unreachable - mapped to OAS2 case below by exporter
- case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+ case OAS2:
n := Nod(OAS2, nil, nil)
n.List.Set(p.exprList())
n.Rlist.Set(p.exprList())
@@ -964,7 +993,10 @@ func (p *importer) node() *Node {
popdcl()
return n
- case OCASE, OXCASE:
+ // case OCASE, OXCASE:
+ // unreachable - mapped to OXCASE case below by exporter
+
+ case OXCASE:
markdcl()
n := Nod(OXCASE, nil, nil)
n.List.Set(p.exprList())
@@ -974,10 +1006,10 @@ func (p *importer) node() *Node {
popdcl()
return n
- case OBREAK, OCONTINUE, OGOTO, OFALL, OXFALL:
- if op == OFALL {
- op = OXFALL
- }
+ // case OFALL:
+ // unreachable - mapped to OXFALL case below by exporter
+
+ case OBREAK, OCONTINUE, OGOTO, OXFALL:
left, _ := p.exprsOrNil()
return Nod(op, left, nil)
@@ -993,7 +1025,7 @@ func (p *importer) node() *Node {
return nil
default:
- Fatalf("importer: %s (%d) node not yet supported", opnames[op], op)
+ Fatalf("importer: %s (%d) node not yet supported", op, op)
panic("unreachable") // satisfy compiler
}
}
@@ -1067,29 +1099,31 @@ func (p *importer) int64() int64 {
}
func (p *importer) string() string {
- if p.debugFormat {
+ if debugFormat {
p.marker('s')
}
-
- // TODO(gri) should we intern strings here?
-
- if n := int(p.rawInt64()); n > 0 {
- if cap(p.buf) < n {
- p.buf = make([]byte, n)
- } else {
- p.buf = p.buf[:n]
- }
- for i := range p.buf {
- p.buf[i] = p.byte()
- }
- return string(p.buf)
+ // if the string was seen before, i is its index (>= 0)
+ // (the empty string is at index 0)
+ i := p.rawInt64()
+ if i >= 0 {
+ return p.strList[i]
}
-
- return ""
+ // otherwise, i is the negative string length (< 0)
+ if n := int(-i); n <= cap(p.buf) {
+ p.buf = p.buf[:n]
+ } else {
+ p.buf = make([]byte, n)
+ }
+ for i := range p.buf {
+ p.buf[i] = p.rawByte()
+ }
+ s := string(p.buf)
+ p.strList = append(p.strList, s)
+ return s
}
func (p *importer) marker(want byte) {
- if got := p.byte(); got != want {
+ if got := p.rawByte(); got != want {
Fatalf("importer: incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
}
@@ -1110,12 +1144,13 @@ func (p *importer) rawInt64() int64 {
// needed for binary.ReadVarint in rawInt64
func (p *importer) ReadByte() (byte, error) {
- return p.byte(), nil
+ return p.rawByte(), nil
}
-// byte is the bottleneck interface for reading from p.in.
+// rawByte is the bottleneck interface for reading from p.in.
// It unescapes '|' 'S' to '$' and '|' '|' to '|'.
-func (p *importer) byte() byte {
+// rawByte should only be used by low-level decoders.
+func (p *importer) rawByte() byte {
c, err := p.in.ReadByte()
p.read++
if err != nil {
diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
index 411c7b8605..cc64e73f25 100644
--- a/src/cmd/compile/internal/gc/builtin.go
+++ b/src/cmd/compile/internal/gc/builtin.go
@@ -3,135 +3,106 @@
package gc
const runtimeimport = "" +
- "package runtime safe\n" +
- "func @\"\".newobject (@\"\".typ·2 *byte) (? *any)\n" +
- "func @\"\".panicindex ()\n" +
- "func @\"\".panicslice ()\n" +
- "func @\"\".panicdivide ()\n" +
- "func @\"\".throwreturn ()\n" +
- "func @\"\".throwinit ()\n" +
- "func @\"\".panicwrap (? string, ? string, ? string)\n" +
- "func @\"\".gopanic (? interface {})\n" +
- "func @\"\".gorecover (? *int32) (? interface {})\n" +
- "func @\"\".printbool (? bool)\n" +
- "func @\"\".printfloat (? float64)\n" +
- "func @\"\".printint (? int64)\n" +
- "func @\"\".printhex (? uint64)\n" +
- "func @\"\".printuint (? uint64)\n" +
- "func @\"\".printcomplex (? complex128)\n" +
- "func @\"\".printstring (? string)\n" +
- "func @\"\".printpointer (? any)\n" +
- "func @\"\".printiface (? any)\n" +
- "func @\"\".printeface (? any)\n" +
- "func @\"\".printslice (? any)\n" +
- "func @\"\".printnl ()\n" +
- "func @\"\".printsp ()\n" +
- "func @\"\".printlock ()\n" +
- "func @\"\".printunlock ()\n" +
- "func @\"\".concatstring2 (? *[32]byte, ? string, ? string) (? string)\n" +
- "func @\"\".concatstring3 (? *[32]byte, ? string, ? string, ? string) (? string)\n" +
- "func @\"\".concatstring4 (? *[32]byte, ? string, ? string, ? string, ? string) (? string)\n" +
- "func @\"\".concatstring5 (? *[32]byte, ? string, ? string, ? string, ? string, ? string) (? string)\n" +
- "func @\"\".concatstrings (? *[32]byte, ? []string) (? string)\n" +
- "func @\"\".cmpstring (? string, ? string) (? int)\n" +
- "func @\"\".eqstring (? string, ? string) (? bool)\n" +
- "func @\"\".intstring (? *[4]byte, ? int64) (? string)\n" +
- "func @\"\".slicebytetostring (? *[32]byte, ? []byte) (? string)\n" +
- "func @\"\".slicebytetostringtmp (? []byte) (? string)\n" +
- "func @\"\".slicerunetostring (? *[32]byte, ? []rune) (? string)\n" +
- "func @\"\".stringtoslicebyte (? *[32]byte, ? string) (? []byte)\n" +
- "func @\"\".stringtoslicebytetmp (? string) (? []byte)\n" +
- "func @\"\".stringtoslicerune (? *[32]rune, ? string) (? []rune)\n" +
- "func @\"\".stringiter (? string, ? int) (? int)\n" +
- "func @\"\".stringiter2 (? string, ? int) (@\"\".retk·1 int, @\"\".retv·2 rune)\n" +
- "func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr \"unsafe-uintptr\") (? int)\n" +
- "func @\"\".slicestringcopy (@\"\".to·2 any, @\"\".fr·3 any) (? int)\n" +
- "func @\"\".convI2E (@\"\".elem·2 any) (@\"\".ret·1 any)\n" +
- "func @\"\".convI2I (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n" +
- "func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 *any, @\"\".buf·4 *any) (@\"\".ret·1 any)\n" +
- "func @\"\".convT2I (@\"\".tab·2 *byte, @\"\".elem·3 *any, @\"\".buf·4 *any) (@\"\".ret·1 any)\n" +
- "func @\"\".assertE2E (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
- "func @\"\".assertE2E2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
- "func @\"\".assertE2I (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
- "func @\"\".assertE2I2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
- "func @\"\".assertE2T (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
- "func @\"\".assertE2T2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
- "func @\"\".assertI2E (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
- "func @\"\".assertI2E2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
- "func @\"\".assertI2I (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
- "func @\"\".assertI2I2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
- "func @\"\".assertI2T (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
- "func @\"\".assertI2T2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
- "func @\"\".panicdottype (@\"\".have·1 *byte, @\"\".want·2 *byte, @\"\".iface·3 *byte)\n" +
- "func @\"\".ifaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" +
- "func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" +
- "func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64, @\"\".mapbuf·4 *any, @\"\".bucketbuf·5 *any) (@\"\".hmap·1 map[any]any)\n" +
- "func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n" +
- "func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" +
- "func @\"\".mapaccess1_fast64 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" +
- "func @\"\".mapaccess1_faststr (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" +
- "func @\"\".mapaccess2 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 *any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" +
- "func @\"\".mapaccess2_fast32 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" +
- "func @\"\".mapaccess2_fast64 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" +
- "func @\"\".mapaccess2_faststr (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" +
- "func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any, @\"\".val·4 *any)\n" +
- "func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *any)\n" +
- "func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any)\n" +
- "func @\"\".mapiternext (@\"\".hiter·1 *any)\n" +
- "func @\"\".makechan (@\"\".chanType·2 *byte, @\"\".hint·3 int64) (@\"\".hchan·1 chan any)\n" +
- "func @\"\".chanrecv1 (@\"\".chanType·1 *byte, @\"\".hchan·2 <-chan any, @\"\".elem·3 *any)\n" +
- "func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n" +
- "func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n" +
- "func @\"\".closechan (@\"\".hchan·1 any)\n" +
- "var @\"\".writeBarrier struct { @\"\".enabled bool; @\"\".needed bool; @\"\".cgo bool }\n" +
- "func @\"\".writebarrierptr (@\"\".dst·1 *any, @\"\".src·2 any)\n" +
- "func @\"\".typedmemmove (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n" +
- "func @\"\".typedslicecopy (@\"\".typ·2 *byte, @\"\".dst·3 any, @\"\".src·4 any) (? int)\n" +
- "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n" +
- "func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n" +
- "func @\"\".selectnbrecv2 (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".received·4 *bool, @\"\".hchan·5 <-chan any) (? bool)\n" +
- "func @\"\".newselect (@\"\".sel·1 *byte, @\"\".selsize·2 int64, @\"\".size·3 int32)\n" +
- "func @\"\".selectsend (@\"\".sel·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (@\"\".selected·1 bool)\n" +
- "func @\"\".selectrecv (@\"\".sel·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (@\"\".selected·1 bool)\n" +
- "func @\"\".selectrecv2 (@\"\".sel·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any, @\"\".received·5 *bool) (@\"\".selected·1 bool)\n" +
- "func @\"\".selectdefault (@\"\".sel·2 *byte) (@\"\".selected·1 bool)\n" +
- "func @\"\".selectgo (@\"\".sel·1 *byte)\n" +
- "func @\"\".block ()\n" +
- "func @\"\".makeslice (@\"\".typ·2 *byte, @\"\".nel·3 int64, @\"\".cap·4 int64) (@\"\".ary·1 []any)\n" +
- "func @\"\".growslice (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".cap·4 int) (@\"\".ary·1 []any)\n" +
- "func @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr \"unsafe-uintptr\")\n" +
- "func @\"\".memclr (@\"\".ptr·1 *byte, @\"\".length·2 uintptr \"unsafe-uintptr\")\n" +
- "func @\"\".memequal (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr \"unsafe-uintptr\") (? bool)\n" +
- "func @\"\".memequal8 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" +
- "func @\"\".memequal16 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" +
- "func @\"\".memequal32 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" +
- "func @\"\".memequal64 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" +
- "func @\"\".memequal128 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" +
- "func @\"\".int64div (? int64, ? int64) (? int64)\n" +
- "func @\"\".uint64div (? uint64, ? uint64) (? uint64)\n" +
- "func @\"\".int64mod (? int64, ? int64) (? int64)\n" +
- "func @\"\".uint64mod (? uint64, ? uint64) (? uint64)\n" +
- "func @\"\".float64toint64 (? float64) (? int64)\n" +
- "func @\"\".float64touint64 (? float64) (? uint64)\n" +
- "func @\"\".int64tofloat64 (? int64) (? float64)\n" +
- "func @\"\".uint64tofloat64 (? uint64) (? float64)\n" +
- "func @\"\".complex128div (@\"\".num·2 complex128, @\"\".den·3 complex128) (@\"\".quo·1 complex128)\n" +
- "func @\"\".racefuncenter (? uintptr \"unsafe-uintptr\")\n" +
- "func @\"\".racefuncexit ()\n" +
- "func @\"\".raceread (? uintptr \"unsafe-uintptr\")\n" +
- "func @\"\".racewrite (? uintptr \"unsafe-uintptr\")\n" +
- "func @\"\".racereadrange (@\"\".addr·1 uintptr \"unsafe-uintptr\", @\"\".size·2 uintptr \"unsafe-uintptr\")\n" +
- "func @\"\".racewriterange (@\"\".addr·1 uintptr \"unsafe-uintptr\", @\"\".size·2 uintptr \"unsafe-uintptr\")\n" +
- "func @\"\".msanread (@\"\".addr·1 uintptr \"unsafe-uintptr\", @\"\".size·2 uintptr \"unsafe-uintptr\")\n" +
- "func @\"\".msanwrite (@\"\".addr·1 uintptr \"unsafe-uintptr\", @\"\".size·2 uintptr \"unsafe-uintptr\")\n" +
- "\n" +
- "$$\n"
+ "c\x00\x03v0\x01\rruntime\x00\t\x11newobject\x00\x02\x17\"\vtyp·2\x00\x00\x01" +
+ "\x17:\x00\t\x13panicindex\x00\x00\x00\t\x13panicslice\x00\x00\x00\t\x15panic" +
+ "divide\x00\x00\x00\t\x15throwreturn\x00\x00\x00\t\x11throwinit\x00\x00\x00\t" +
+ "\x11panicwrap\x00\x05 \x00 \x00 \x00\x00\t\rgopanic\x00\x01\x1b\x00\x00\x00\x00\t\x11gor" +
+ "ecover\x00\x01\x17\b\x00\x01\x1b\x00\x00\x00\t\x11printbool\x00\x01\x00\x00\x00\t\x13printf" +
+ "loat\x00\x01\x1a\x00\x00\t\x0fprintint\x00\x01\n\x00\x00\t\x0fprinthex\x00\x01\x14\x00\x00\t" +
+ "\x11printuint\x00\x01\x14\x00\x00\t\x17printcomplex\x00\x01\x1e\x00\x00\t\x15prin" +
+ "tstring\x00\x01 \x00\x00\t\x17printpointer\x00\x01:\x00\x00\t\x13printif" +
+ "ace\x00\x01:\x00\x00\t\x13printeface\x00\x01:\x00\x00\t\x13printslice\x00\x01:" +
+ "\x00\x00\t\rprintnl\x00\x00\x00\t\rprintsp\x00\x00\x00\t\x11printlock\x00\x00\x00" +
+ "\t\x15printunlock\x00\x00\x00\t\x19concatstring2\x00\x05\x17\x0f@\"\x00 \x00" +
+ " \x00\x01 \x00\t\x19concatstring3\x00\a\x17\x0f@\"\x00 \x00 \x00 \x00\x01 \x00\t\x19co" +
+ "ncatstring4\x00\t\x17\x0f@\"\x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatstr" +
+ "ing5\x00\v\x17\x0f@\"\x00 \x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatstrings\x00" +
+ "\x03\x17\x0f@\"\x00\x11 \x00\x01 \x00\t\x11cmpstring\x00\x03 \x00 \x00\x01\x02\x00\t\x0feqstri" +
+ "ng\x00\x03 \x00 \x00\x01\x00\x00\t\x11intstring\x00\x03\x17\x0f\b\"\x00\n\x00\x01 \x00\t!slic" +
+ "ebytetostring\x00\x03\x17\x0f@\"\x00\x11\"\x00\x01 \x00\t'slicebytetos" +
+ "tringtmp\x00\x01\x11\"\x00\x01 \x00\t!slicerunetostring\x00\x03\x17\x0f@" +
+ "\"\x00\x11|S\x00\x01 \x00\t!stringtoslicebyte\x00\x03\x17\x0f@\"\x00 \x00\x01\x11\"" +
+ "\x00\t'stringtoslicebytetmp\x00\x01 \x00\x01\x11\"\x00\t!stringt" +
+ "oslicerune\x00\x03\x17\x0f@|S\x00 \x00\x01\x11|S\x00\t\x13stringiter\x00\x03 " +
+ "\x00\x02\x00\x01\x02\x00\t\x15stringiter2\x00\x03 \x00\x02\x00\x04\x02\rretk·1\x00\x00|S\r" +
+ "retv·2\x00\x00\t\x11slicecopy\x00\x06:\tto·2\x00\x00:\tfr·3\x00\x00" +
+ "\x16\vwid·4\x00\x1bunsafe-uintptr\x01\x02\x00\t\x1dslicestring" +
+ "copy\x00\x04:^\x00\x00:`\x00\x00\x01\x02\x00\t\rconvI2E\x00\x02:\relem·2\x00\x00\x02" +
+ ":\vret·1\x00\x00\t\rconvI2I\x00\x04\x17\"\b\x00\x00:\relem·3\x00\x00\x02:l" +
+ "\x00\x00\t\rconvT2E\x00\x06\x17\"\b\x00\x00>p\x00\x00>\vbuf·4\x00\x00\x02:l\x00\x00\t\rc" +
+ "onvT2I\x00\x06\x17\"\vtab·2\x00\x00>p\x00\x00>t\x00\x00\x02:l\x00\x00\t\x11assert" +
+ "E2E\x00\x06\x17\"\vtyp·1\x00\x00:\x0fiface·2\x00\x00>\vret·3\x00\x00\x00\t" +
+ "\x13assertE2E2\x00\x06\x17\"\b\x00\x00:\x0fiface·3\x00\x00>\vret·4\x00\x00" +
+ "\x01\x00\x00\t\x11assertE2I\x00\x06\x17\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13assert" +
+ "E2I2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01\x00\x00\x01\x00\x00\t\x11assertE2T\x00\x06\x17\"|" +
+ "|\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13assertE2T2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01" +
+ "\x00\x00\x01\x00\x00\t\x11assertI2E\x00\x06\x17\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13asse" +
+ "rtI2E2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2I\x00\x06\x17" +
+ "\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13assertI2I2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>" +
+ "\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2T\x00\x06\x17\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13as" +
+ "sertI2T2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01\x00\x00\x01\x00\x00\t\x17panicdotty" +
+ "pe\x00\x06\x17\"\rhave·1\x00\x00\x9a\x01\rwant·2\x00\x00\x9a\x01\x84\x01\x00\x00\x00\t\rifa" +
+ "ceeq\x00\x04:\ti1·2\x00\x00:\ti2·3\x00\x00\x02\x00l\x00\x00\t\refaceeq\x00\x04" +
+ ":\xa4\x01\x00\x00:\xa6\x01\x00\x00\x02\x00l\x00\x00\t\rmakemap\x00\b\x17\"\x13mapType·2\x00" +
+ "\x00\n\rhint·3\x00\x00>\x11mapbuf·4\x00\x00>\x17bucketbuf·5\x00" +
+ "\x00\x02\x1d::\rhmap·1\x00\x00\t\x13mapaccess1\x00\x06\x17\"\xac\x01\x00\x00\x1d::\rh" +
+ "map·3\x00\x00>\vkey·4\x00\x00\x02>\vval·1\x00\x00\t!mapaccess" +
+ "1_fast32\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02>\xbc\x01\x00\x00\t!mapa" +
+ "ccess1_fast64\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02>\xbc\x01\x00\x00\t" +
+ "#mapaccess1_faststr\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02" +
+ ">\xbc\x01\x00\x00\t\x1bmapaccess1_fat\x00\b\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00>\xba\x01\x00" +
+ "\x00\x17\"\rzero·5\x00\x00\x02>\xbc\x01\x00\x00\t\x13mapaccess2\x00\x06\x17\"\x13mapT" +
+ "ype·3\x00\x00\x1d::\rhmap·4\x00\x00>\vkey·5\x00\x00\x04>\xbc\x01\x00\x00\x00\rp" +
+ "res·2\x00\x00\t!mapaccess2_fast32\x00\x06\x17\"\xca\x01\x00\x00\x1d::\xcc\x01" +
+ "\x00\x00:\xce\x01\x00\x00\x04>\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t!mapaccess2_fast64\x00\x06\x17" +
+ "\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00:\xce\x01\x00\x00\x04>\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t#mapaccess2" +
+ "_faststr\x00\x06\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00:\xce\x01\x00\x00\x04>\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t" +
+ "\x1bmapaccess2_fat\x00\b\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00>\xce\x01\x00\x00\x17\"\rze" +
+ "ro·6\x00\x00\x04>\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t\x13mapassign1\x00\b\x17\"\x13mapTy" +
+ "pe·1\x00\x00\x1d::\rhmap·2\x00\x00>\vkey·3\x00\x00>\vval·4\x00\x00" +
+ "\x00\t\x15mapiterinit\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00>\x0fhiter·3\x00" +
+ "\x00\x00\t\x11mapdelete\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00>\xe2\x01\x00\x00\x00\t\x15mapi" +
+ "ternext\x00\x02>\x0fhiter·1\x00\x00\x00\t\x0fmakechan\x00\x04\x17\"\x15cha" +
+ "nType·2\x00\x00\n\xae\x01\x00\x00\x02\x1f\x06:\x0fhchan·1\x00\x00\t\x11chanrecv" +
+ "1\x00\x06\x17\"\x15chanType·1\x00\x00\x1f\x02:\x0fhchan·2\x00\x00>p\x00\x00\x00\t\x11" +
+ "chanrecv2\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x02:\x0fhchan·3\x00\x00>\relem·4" +
+ "\x00\x00\x01\x00\x00\t\x11chansend1\x00\x06\x17\"\xf8\x01\x00\x00\x1f\x04:\xfa\x01\x00\x00>p\x00\x00\x00\t\x11cl" +
+ "osechan\x00\x02:\xf4\x01\x00\x00\x00\a\x17writeBarrier\x00\x15\x06\renabled" +
+ "\x00\x00\x00\vneeded\x00\x00\x00\x05cgo\x00\x00\x00\t\x1dwritebarrierptr\x00\x04>" +
+ "\vdst·1\x00\x00:\vsrc·2\x00\x00\x00\t\x17typedmemmove\x00\x06\x17\"||" +
+ "\x00\x00>\vdst·2\x00\x00>\vsrc·3\x00\x00\x00\t\x1btypedslicecopy\x00" +
+ "\x06\x17\"\b\x00\x00:\vdst·3\x00\x00:\vsrc·4\x00\x00\x01\x02\x00\t\x17selectnbs" +
+ "end\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x04:\xfe\x01\x00\x00>\x80\x02\x00\x00\x01\x00\x00\t\x17selectnbrecv" +
+ "\x00\x06\x17\"\xf2\x01\x00\x00>p\x00\x00\x1f\x02:\x0fhchan·4\x00\x00\x01\x00\x00\t\x19selectnbr" +
+ "ecv2\x00\b\x17\"\xf2\x01\x00\x00>p\x00\x00\x17\x00\x15received·4\x00\x00\x1f\x02:\x0fhcha" +
+ "n·5\x00\x00\x01\x00\x00\t\x11newselect\x00\x06\x17\"\vsel·1\x00\x00\n\x13selsi" +
+ "ze·2\x00\x00\b\rsize·3\x00\x00\x00\t\x13selectsend\x00\x06\x17\"\vsel\xc2" +
+ "\xb72\x00\x00\x1f\x04:\xfe\x01\x00\x00>\x80\x02\x00\x00\x02\x00\x15selected·1\x00\x00\t\x13select" +
+ "recv\x00\x06\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00>\x80\x02\x00\x00\x02\x00\xb8\x02\x00\x00\t\x15selectre" +
+ "cv2\x00\b\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00>\x80\x02\x00\x00\xf8\x01\x15received·5\x00\x00\x02" +
+ "\x00\xb8\x02\x00\x00\t\x19selectdefault\x00\x02\x17\"\xb6\x02\x00\x00\x02\x00\xb8\x02\x00\x00\t\x0fsele" +
+ "ctgo\x00\x02\x17\"\xae\x02\x00\x00\x00\t\tblock\x00\x00\x00\t\x11makeslice\x00\x06\x17\"\b\x00" +
+ "\x00\n\vnel·3\x00\x00\n\vcap·4\x00\x00\x02\x11:\vary·1\x00\x00\t\x11grows" +
+ "lice\x00\x06\x17\"\b\x00\x00\x11:\vold·3\x00\x00\x02\xca\x02\x00\x00\x02\x11:\xcc\x02\x00\x00\t\rmemm" +
+ "ove\x00\x06>\tto·1\x00\x00>\vfrm·2\x00\x00\x16\x11length·3\x00d\x00\t\v" +
+ "memclr\x00\x04\x17\"\vptr·1\x00\x00\x16\x11length·2\x00d\x00\t\x0fmemeq" +
+ "ual\x00\x06>\ax·2\x00\x00>\ay·3\x00\x00\x16\rsize·4\x00d\x01\x00\x00\t\x11mem" +
+ "equal8\x00\x04>\xe2\x02\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal16\x00\x04>\xe2\x02\x00\x00" +
+ ">\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal32\x00\x04>\xe2\x02\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x13mem" +
+ "equal64\x00\x04>\xe2\x02\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x15memequal128\x00\x04>\xe2\x02" +
+ "\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x0fint64div\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64div" +
+ "\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x0fint64mod\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64mod\x00" +
+ "\x03\x14\x00\x14\x00\x01\x14\x00\t\x1bfloat64toint64\x00\x01\x1a\x00\x01\n\x00\t\x1dfloat64" +
+ "touint64\x00\x01\x1a\x00\x01\x14\x00\t\x1bint64tofloat64\x00\x01\n\x00\x01\x1a\x00\t\x1d" +
+ "uint64tofloat64\x00\x01\x14\x00\x01\x1a\x00\t\x19complex128div\x00\x04\x1e" +
+ "\vnum·2\x00\x00\x1e\vden·3\x00\x00\x02\x1e\vquo·1\x00\x00\t\x19racefunc" +
+ "enter\x00\x01\x16d\x00\t\x17racefuncexit\x00\x00\x00\t\x0fraceread\x00\x01\x16" +
+ "d\x00\t\x11racewrite\x00\x01\x16d\x00\t\x19racereadrange\x00\x04\x16\radd" +
+ "r·1\x00d\x16\rsize·2\x00d\x00\t\x1bracewriterange\x00\x04\x16\x94\x03\x00" +
+ "d\x16\x96\x03\x00d\x00\t\x0fmsanread\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\t\x11msanwrit" +
+ "e\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\v\xf4\x01\x02\v\x00\x01\x00\n$$\n"
const unsafeimport = "" +
- "package unsafe\n" +
- "type @\"\".Pointer uintptr\n" +
- "func @\"\".Offsetof (? any) (? uintptr)\n" +
- "func @\"\".Sizeof (? any) (? uintptr)\n" +
- "func @\"\".Alignof (? any) (? uintptr)\n" +
- "\n" +
- "$$\n"
+ "c\x00\x03v0\x01\vunsafe\x00\x05\r\rPointer\x00\x16\x00\t\x0fOffsetof\x00\x01:" +
+ "\x00\x01\x16\x00\t\vSizeof\x00\x01:\x00\x01\x16\x00\t\rAlignof\x00\x01:\x00\x01\x16\x00\v\b\x00\v\x00" +
+ "\x01\x00\n$$\n"
diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
index 584368a144..e9316cb313 100644
--- a/src/cmd/compile/internal/gc/builtin/runtime.go
+++ b/src/cmd/compile/internal/gc/builtin/runtime.go
@@ -89,10 +89,12 @@ func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any)
func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any)
func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any)
func mapaccess1_faststr(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapaccess1_fat(mapType *byte, hmap map[any]any, key *any, zero *byte) (val *any)
func mapaccess2(mapType *byte, hmap map[any]any, key *any) (val *any, pres bool)
func mapaccess2_fast32(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
func mapaccess2_faststr(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
+func mapaccess2_fat(mapType *byte, hmap map[any]any, key *any, zero *byte) (val *any, pres bool)
func mapassign1(mapType *byte, hmap map[any]any, key *any, val *any)
func mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
func mapdelete(mapType *byte, hmap map[any]any, key *any)
diff --git a/src/cmd/compile/internal/gc/cgen.go b/src/cmd/compile/internal/gc/cgen.go
index c594ad4c11..fd57fbd4a7 100644
--- a/src/cmd/compile/internal/gc/cgen.go
+++ b/src/cmd/compile/internal/gc/cgen.go
@@ -7,6 +7,7 @@ package gc
import (
"cmd/internal/obj"
"cmd/internal/obj/ppc64"
+ "cmd/internal/sys"
"fmt"
)
@@ -88,7 +89,7 @@ func cgen_wb(n, res *Node, wb bool) {
if !res.Addable {
if n.Ullman > res.Ullman {
- if Ctxt.Arch.Regsize == 4 && Is64(n.Type) {
+ if Ctxt.Arch.RegSize == 4 && Is64(n.Type) {
var n1 Node
Tempname(&n1, n.Type)
Cgen(n, &n1)
@@ -127,7 +128,7 @@ func cgen_wb(n, res *Node, wb bool) {
f = false
}
- if !n.Type.IsComplex() && Ctxt.Arch.Regsize == 8 && !wb {
+ if !n.Type.IsComplex() && Ctxt.Arch.RegSize == 8 && !wb {
a := Thearch.Optoas(OAS, res.Type)
var addr obj.Addr
if Thearch.Sudoaddable(a, res, &addr) {
@@ -151,7 +152,7 @@ func cgen_wb(n, res *Node, wb bool) {
}
}
- if Ctxt.Arch.Thechar == '8' {
+ if Ctxt.Arch.Family == sys.I386 {
// no registers to speak of
var n1, n2 Node
Tempname(&n1, n.Type)
@@ -203,7 +204,7 @@ func cgen_wb(n, res *Node, wb bool) {
// Write barrier now handled. Code below this line can ignore wb.
- if Ctxt.Arch.Thechar == '5' { // TODO(rsc): Maybe more often?
+ if Ctxt.Arch.Family == sys.ARM { // TODO(rsc): Maybe more often?
// if both are addressable, move
if n.Addable && res.Addable {
if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || n.Type.IsComplex() || res.Type.IsComplex() {
@@ -246,12 +247,12 @@ func cgen_wb(n, res *Node, wb bool) {
return
}
- if (Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8') && n.Addable {
+ if Ctxt.Arch.InFamily(sys.AMD64, sys.I386, sys.S390X) && n.Addable {
Thearch.Gmove(n, res)
return
}
- if Ctxt.Arch.Thechar == '0' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
+ if Ctxt.Arch.InFamily(sys.ARM64, sys.MIPS64, sys.PPC64) {
// if both are addressable, move
if n.Addable {
if n.Op == OREGISTER || res.Op == OREGISTER {
@@ -268,7 +269,7 @@ func cgen_wb(n, res *Node, wb bool) {
}
// if n is sudoaddable generate addr and move
- if Ctxt.Arch.Thechar == '5' && !Is64(n.Type) && !Is64(res.Type) && !n.Type.IsComplex() && !res.Type.IsComplex() {
+ if Ctxt.Arch.Family == sys.ARM && !Is64(n.Type) && !Is64(res.Type) && !n.Type.IsComplex() && !res.Type.IsComplex() {
a := Thearch.Optoas(OAS, n.Type)
var addr obj.Addr
if Thearch.Sudoaddable(a, n, &addr) {
@@ -310,7 +311,7 @@ func cgen_wb(n, res *Node, wb bool) {
}
// 64-bit ops are hard on 32-bit machine.
- if Ctxt.Arch.Regsize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) {
+ if Ctxt.Arch.RegSize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) {
switch n.Op {
// math goes to cgen64.
case OMINUS,
@@ -334,7 +335,7 @@ func cgen_wb(n, res *Node, wb bool) {
return
}
- if !n.Type.IsComplex() && Ctxt.Arch.Regsize == 8 {
+ if !n.Type.IsComplex() && Ctxt.Arch.RegSize == 8 {
a := Thearch.Optoas(OAS, n.Type)
var addr obj.Addr
if Thearch.Sudoaddable(a, n, &addr) {
@@ -401,11 +402,11 @@ func cgen_wb(n, res *Node, wb bool) {
Regalloc(&n1, nl.Type, res)
Cgen(nl, &n1)
- if Ctxt.Arch.Thechar == '5' {
+ if Ctxt.Arch.Family == sys.ARM {
var n2 Node
Nodconst(&n2, nl.Type, 0)
Thearch.Gins(a, &n2, &n1)
- } else if Ctxt.Arch.Thechar == '7' {
+ } else if Ctxt.Arch.Family == sys.ARM64 {
Thearch.Gins(a, &n1, &n1)
} else {
Thearch.Gins(a, nil, &n1)
@@ -452,7 +453,7 @@ func cgen_wb(n, res *Node, wb bool) {
return
}
- if Ctxt.Arch.Thechar == '8' {
+ if Ctxt.Arch.Family == sys.I386 {
var n1 Node
var n2 Node
Tempname(&n2, n.Type)
@@ -465,7 +466,7 @@ func cgen_wb(n, res *Node, wb bool) {
var n1 Node
var n2 Node
- if Ctxt.Arch.Thechar == '5' {
+ if Ctxt.Arch.Family == sys.ARM {
if nl.Addable && !Is64(nl.Type) {
Regalloc(&n1, nl.Type, res)
Thearch.Gmove(nl, &n1)
@@ -707,7 +708,7 @@ sbop: // symmetric binary
abop: // asymmetric binary
var n1 Node
var n2 Node
- if Ctxt.Arch.Thechar == '8' {
+ if Ctxt.Arch.Family == sys.I386 {
// no registers, sigh
if Smallintconst(nr) {
var n1 Node
@@ -751,14 +752,14 @@ abop: // asymmetric binary
Regalloc(&n1, nl.Type, res)
Cgen(nl, &n1)
- if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
+ if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.ARM && Ctxt.Arch.Family != sys.ARM64 && Ctxt.Arch.Family != sys.PPC64 { // TODO(rsc): Check opcode for arm
n2 = *nr
} else {
Regalloc(&n2, nr.Type, nil)
Cgen(nr, &n2)
}
} else {
- if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
+ if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.ARM && Ctxt.Arch.Family != sys.ARM64 && Ctxt.Arch.Family != sys.PPC64 { // TODO(rsc): Check opcode for arm
n2 = *nr
} else {
Regalloc(&n2, nr.Type, res)
@@ -876,8 +877,8 @@ func cgen_wbfat(n, res *Node) {
// cgen_norm moves n1 to res, truncating to expected type if necessary.
// n1 is a register, and cgen_norm frees it.
func cgen_norm(n, n1, res *Node) {
- switch Ctxt.Arch.Thechar {
- case '6', '8':
+ switch Ctxt.Arch.Family {
+ case sys.AMD64, sys.I386:
// We use sized math, so the result is already truncated.
default:
switch n.Op {
@@ -945,7 +946,7 @@ func Cgenr(n *Node, a *Node, res *Node) {
OCALLINTER:
var n1 Node
Igen(n, &n1, res)
- Regalloc(a, Types[Tptr], &n1)
+ Regalloc(a, n.Type, &n1)
Thearch.Gmove(&n1, a)
Regfree(&n1)
@@ -977,10 +978,14 @@ func Agenr(n *Node, a *Node, res *Node) {
case OIND:
Cgenr(n.Left, a, res)
- Cgen_checknil(a)
+ if !n.Left.NonNil {
+ Cgen_checknil(a)
+ } else if Debug_checknil != 0 && n.Lineno > 1 {
+ Warnl(n.Lineno, "removed nil check")
+ }
case OINDEX:
- if Ctxt.Arch.Thechar == '5' {
+ if Ctxt.Arch.Family == sys.ARM {
var p2 *obj.Prog // to be patched to panicindex.
w := uint32(n.Type.Width)
bounded := Debug['B'] != 0 || n.Bounded
@@ -1127,7 +1132,7 @@ func Agenr(n *Node, a *Node, res *Node) {
Regfree(&n2)
break
}
- if Ctxt.Arch.Thechar == '8' {
+ if Ctxt.Arch.Family == sys.I386 {
var p2 *obj.Prog // to be patched to panicindex.
w := uint32(n.Type.Width)
bounded := Debug['B'] != 0 || n.Bounded
@@ -1586,7 +1591,11 @@ func Agen(n *Node, res *Node) {
case OIND:
Cgen(nl, res)
- Cgen_checknil(res)
+ if !nl.NonNil {
+ Cgen_checknil(res)
+ } else if Debug_checknil != 0 && n.Lineno > 1 {
+ Warnl(n.Lineno, "removed nil check")
+ }
case ODOT:
Agen(nl, res)
@@ -1596,7 +1605,11 @@ func Agen(n *Node, res *Node) {
case ODOTPTR:
Cgen(nl, res)
- Cgen_checknil(res)
+ if !nl.NonNil {
+ Cgen_checknil(res)
+ } else if Debug_checknil != 0 && n.Lineno > 1 {
+ Warnl(n.Lineno, "removed nil check")
+ }
if n.Xoffset != 0 {
addOffset(res, n.Xoffset)
}
@@ -1604,7 +1617,7 @@ func Agen(n *Node, res *Node) {
}
func addOffset(res *Node, offset int64) {
- if Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8' {
+ if Ctxt.Arch.InFamily(sys.AMD64, sys.I386) {
Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), Nodintconst(offset), res)
return
}
@@ -1657,7 +1670,11 @@ func Igen(n *Node, a *Node, res *Node) {
case ODOTPTR:
Cgenr(n.Left, a, res)
- Cgen_checknil(a)
+ if !n.Left.NonNil {
+ Cgen_checknil(a)
+ } else if Debug_checknil != 0 && n.Lineno > 1 {
+ Warnl(n.Lineno, "removed nil check")
+ }
a.Op = OINDREG
a.Xoffset += n.Xoffset
a.Type = n.Type
@@ -1790,7 +1807,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
}
if !n.Type.IsBoolean() {
- Fatalf("bgen: bad type %v for %v", n.Type, Oconv(n.Op, 0))
+ Fatalf("bgen: bad type %v for %v", n.Type, n.Op)
}
for n.Op == OCONVNOP {
@@ -1825,13 +1842,14 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
return
case ONAME:
+ // Some architectures might need a temporary or other help here,
+ // but they don't support direct generation of a bool value yet.
+ // We can fix that as we go.
+ mayNeedTemp := Ctxt.Arch.InFamily(sys.ARM, sys.ARM64, sys.MIPS64, sys.PPC64, sys.S390X)
+
if genval {
- // 5g, 7g, and 9g might need a temporary or other help here,
- // but they don't support direct generation of a bool value yet.
- // We can fix that as we go.
- switch Ctxt.Arch.Thechar {
- case '0', '5', '7', '9':
- Fatalf("genval 0g, 5g, 7g, 9g ONAMES not fully implemented")
+ if mayNeedTemp {
+ Fatalf("genval ONAMES not fully implemented")
}
Cgen(n, res)
if !wantTrue {
@@ -1840,7 +1858,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
return
}
- if n.Addable && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' {
+ if n.Addable && !mayNeedTemp {
// no need for a temporary
bgenNonZero(n, nil, wantTrue, likely, to)
return
@@ -1977,7 +1995,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
return
}
- if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) {
+ if Ctxt.Arch.RegSize == 4 && Is64(nr.Type) {
if genval {
// TODO: Teach Cmp64 to generate boolean values and remove this.
bvgenjump(n, res, wantTrue, false)
@@ -2015,7 +2033,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
Regfree(&n2)
} else {
var n1 Node
- if !nl.Addable && Ctxt.Arch.Thechar == '8' {
+ if !nl.Addable && Ctxt.Arch.Family == sys.I386 {
Tempname(&n1, nl.Type)
} else {
Regalloc(&n1, nl.Type, nil)
@@ -2024,13 +2042,13 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
Cgen(nl, &n1)
nl = &n1
- if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '9' {
+ if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.PPC64 {
Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr)
bins(nr.Type, res, op, likely, to)
return
}
- if !nr.Addable && Ctxt.Arch.Thechar == '8' {
+ if !nr.Addable && Ctxt.Arch.Family == sys.I386 {
nr = CgenTemp(nr)
}
@@ -2044,13 +2062,13 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
l, r := nl, nr
// On x86, only < and <= work right with NaN; reverse if needed
- if Ctxt.Arch.Thechar == '6' && nl.Type.IsFloat() && (op == OGT || op == OGE) {
+ if Ctxt.Arch.Family == sys.AMD64 && nl.Type.IsFloat() && (op == OGT || op == OGE) {
l, r = r, l
op = Brrev(op)
}
// MIPS does not have CMP instruction
- if Ctxt.Arch.Thechar == '0' {
+ if Ctxt.Arch.Family == sys.MIPS64 {
p := Thearch.Ginscmp(op, nr.Type, l, r, likely)
Patch(p, to)
return
@@ -2062,8 +2080,8 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
// Handle floating point special cases.
// Note that 8g has Bgen_float and is handled above.
if nl.Type.IsFloat() {
- switch Ctxt.Arch.Thechar {
- case '5':
+ switch Ctxt.Arch.Family {
+ case sys.ARM:
if genval {
Fatalf("genval 5g Isfloat special cases not implemented")
}
@@ -2077,7 +2095,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
Patch(p, Pc)
}
return
- case '6':
+ case sys.AMD64:
switch n.Op {
case OEQ:
// neither NE nor P
@@ -2111,7 +2129,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
}
return
}
- case '7', '9':
+ case sys.ARM64, sys.PPC64:
if genval {
Fatalf("genval 7g, 9g Isfloat special cases not implemented")
}
@@ -2143,7 +2161,7 @@ func bgenNonZero(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
}
// MIPS does not have CMP instruction
- if Thearch.Thechar == '0' {
+ if Thearch.LinkArch.Family == sys.MIPS64 {
p := Gbranch(Thearch.Optoas(op, n.Type), n.Type, likely)
Naddr(&p.From, n)
Patch(p, to)
@@ -2352,7 +2370,7 @@ func Ginscall(f *Node, proc int) {
// into the instruction stream.
Thearch.Ginsnop()
- if Thearch.Thechar == '9' {
+ if Thearch.LinkArch.Family == sys.PPC64 {
// On ppc64, when compiling Go into position
// independent code on ppc64le we insert an
// instruction to reload the TOC pointer from the
@@ -2361,7 +2379,7 @@ func Ginscall(f *Node, proc int) {
// If the MOVD is not needed, insert a hardware NOP
// so that the same number of instructions are used
// on ppc64 in both shared and non-shared modes.
- if Ctxt.Flag_shared != 0 {
+ if Ctxt.Flag_shared {
p := Thearch.Gins(ppc64.AMOVD, nil, nil)
p.From.Type = obj.TYPE_MEM
p.From.Offset = 24
@@ -2436,7 +2454,7 @@ func Ginscall(f *Node, proc int) {
func cgen_callinter(n *Node, res *Node, proc int) {
i := n.Left
if i.Op != ODOTINTER {
- Fatalf("cgen_callinter: not ODOTINTER %v", Oconv(i.Op, 0))
+ Fatalf("cgen_callinter: not ODOTINTER %v", i.Op)
}
i = i.Left // interface
@@ -2620,24 +2638,70 @@ func cgen_ret(n *Node) {
}
}
+// hasHMUL64 reports whether the architecture supports 64-bit
+// signed and unsigned high multiplication (OHMUL).
+func hasHMUL64() bool {
+ switch Ctxt.Arch.Family {
+ case sys.AMD64, sys.S390X, sys.ARM64:
+ return true
+ case sys.ARM, sys.I386, sys.MIPS64, sys.PPC64:
+ return false
+ }
+ Fatalf("unknown architecture")
+ return false
+}
+
+// hasRROTC64 reports whether the architecture supports 64-bit
+// rotate through carry instructions (ORROTC).
+func hasRROTC64() bool {
+ switch Ctxt.Arch.Family {
+ case sys.AMD64:
+ return true
+ case sys.ARM, sys.ARM64, sys.I386, sys.MIPS64, sys.PPC64, sys.S390X:
+ return false
+ }
+ Fatalf("unknown architecture")
+ return false
+}
+
+func hasRightShiftWithCarry() bool {
+ switch Ctxt.Arch.Family {
+ case sys.ARM64:
+ return true
+ case sys.AMD64, sys.ARM, sys.I386, sys.MIPS64, sys.PPC64, sys.S390X:
+ return false
+ }
+ Fatalf("unknown architecture")
+ return false
+}
+
+func hasAddSetCarry() bool {
+ switch Ctxt.Arch.Family {
+ case sys.ARM64:
+ return true
+ case sys.AMD64, sys.ARM, sys.I386, sys.MIPS64, sys.PPC64, sys.S390X:
+ return false
+ }
+ Fatalf("unknown architecture")
+ return false
+}
+
// generate division according to op, one of:
// res = nl / nr
// res = nl % nr
func cgen_div(op Op, nl *Node, nr *Node, res *Node) {
var w int
- // TODO(rsc): arm64 needs to support the relevant instructions
- // in peep and optoas in order to enable this.
- // TODO(rsc): ppc64 needs to support the relevant instructions
- // in peep and optoas in order to enable this.
- if nr.Op != OLITERAL || Ctxt.Arch.Thechar == '0' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
+ // Architectures need to support 64-bit high multiplications
+ // (OHMUL) in order to perform divide by constant optimizations.
+ if nr.Op != OLITERAL || !hasHMUL64() {
goto longdiv
}
w = int(nl.Type.Width * 8)
// Front end handled 32-bit division. We only need to handle 64-bit.
- // try to do division by multiply by (2^w)/d
- // see hacker's delight chapter 10
+ // Try to do division using multiplication: (2^w)/d.
+ // See Hacker's Delight, chapter 10.
switch Simtype[nl.Type.Etype] {
default:
goto longdiv
@@ -2650,6 +2714,18 @@ func cgen_div(op Op, nl *Node, nr *Node, res *Node) {
if m.Bad != 0 {
break
}
+
+ // In order to add the numerator we need to be able to
+ // avoid overflow. This is done by shifting the result of the
+ // addition right by 1 and inserting the carry bit into
+ // the MSB. For now this needs the RROTC instruction.
+ // TODO(mundaym): Hacker's Delight 2nd ed. chapter 10 proposes
+ // an alternative sequence of instructions for architectures
+ // (TODO: MIPS64, PPC64, S390X) that do not have a shift
+ // right with carry instruction.
+ if m.Ua != 0 && !hasRROTC64() && !hasRightShiftWithCarry() {
+ goto longdiv
+ }
if op == OMOD {
goto longmod
}
@@ -2663,13 +2739,21 @@ func cgen_div(op Op, nl *Node, nr *Node, res *Node) {
Thearch.Cgen_hmul(&n1, &n2, &n3)
if m.Ua != 0 {
- // need to add numerator accounting for overflow
- Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3)
+ // Need to add numerator accounting for overflow.
+ if hasAddSetCarry() {
+ Thearch.AddSetCarry(&n1, &n3, &n3)
+ } else {
+ Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3)
+ }
- Nodconst(&n2, nl.Type, 1)
- Thearch.Gins(Thearch.Optoas(ORROTC, nl.Type), &n2, &n3)
- Nodconst(&n2, nl.Type, int64(m.S)-1)
- Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3)
+ if !hasRROTC64() {
+ Thearch.RightShiftWithCarry(&n3, uint(m.S), &n3)
+ } else {
+ Nodconst(&n2, nl.Type, 1)
+ Thearch.Gins(Thearch.Optoas(ORROTC, nl.Type), &n2, &n3)
+ Nodconst(&n2, nl.Type, int64(m.S)-1)
+ Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3)
+ }
} else {
Nodconst(&n2, nl.Type, int64(m.S))
Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift dx
@@ -2701,7 +2785,7 @@ func cgen_div(op Op, nl *Node, nr *Node, res *Node) {
Thearch.Cgen_hmul(&n1, &n2, &n3)
if m.Sm < 0 {
- // need to add numerator
+ // Need to add numerator (cannot overflow).
Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3)
}
@@ -2714,8 +2798,8 @@ func cgen_div(op Op, nl *Node, nr *Node, res *Node) {
Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n1, &n3) // added
if m.Sd < 0 {
- // this could probably be removed
- // by factoring it into the multiplier
+ // This could probably be removed by factoring it into
+ // the multiplier.
Thearch.Gins(Thearch.Optoas(OMINUS, nl.Type), nil, &n3)
}
@@ -2727,14 +2811,14 @@ func cgen_div(op Op, nl *Node, nr *Node, res *Node) {
goto longdiv
- // division and mod using (slow) hardware instruction
+ // Division and mod using (slow) hardware instruction.
longdiv:
Thearch.Dodiv(op, nl, nr, res)
return
- // mod using formula A%B = A-(A/B*B) but
- // we know that there is a fast algorithm for A/B
+ // Mod using formula A%B = A-(A/B*B) but
+ // we know that there is a fast algorithm for A/B.
longmod:
var n1 Node
Regalloc(&n1, nl.Type, res)
@@ -2744,11 +2828,6 @@ longmod:
Regalloc(&n2, nl.Type, nil)
cgen_div(ODIV, &n1, nr, &n2)
a := Thearch.Optoas(OMUL, nl.Type)
- if w == 8 {
- // use 2-operand 16-bit multiply
- // because there is no 2-operand 8-bit multiply
- a = Thearch.Optoas(OMUL, Types[TINT16]) // XXX was IMULW
- }
if !Smallintconst(nr) {
var n3 Node
@@ -2844,7 +2923,7 @@ func cgen_append(n, res *Node) {
arg.Addable = true
arg.Xoffset = Ctxt.FixedFrameSize()
arg.Type = Ptrto(Types[TUINT8])
- Cgen(typename(res.Type), &arg)
+ Cgen(typename(res.Type.Elem()), &arg)
arg.Xoffset += int64(Widthptr)
arg.Type = Types[Tptr]
@@ -2995,7 +3074,7 @@ func cgen_slice(n, res *Node, wb bool) {
regalloc := Regalloc
ginscon := Thearch.Ginscon
gins := Thearch.Gins
- if Thearch.Thechar == '8' {
+ if Thearch.LinkArch.Family == sys.I386 {
regalloc = func(n *Node, t *Type, reuse *Node) {
Tempname(n, t)
}
@@ -3058,15 +3137,7 @@ func cgen_slice(n, res *Node, wb bool) {
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
- }
+ x1, x2, x3 := n.SliceBounds() // unevaluated index arguments
// 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.
@@ -3238,7 +3309,7 @@ func cgen_slice(n, res *Node, wb bool) {
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 Ctxt.Arch.RegSize == 4 && Is64(n1.Type) {
if n1.Val().U.(*Mpint).CmpInt64(1<<31) >= 0 {
Fatalf("missed slice out of bounds check")
}
diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
index 80c8d309af..d2cb9ebf1e 100644
--- a/src/cmd/compile/internal/gc/closure.go
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -194,7 +194,7 @@ func makeclosure(func_ *Node) *Node {
xfunc.Nbody.Set(func_.Nbody.Slice())
xfunc.Func.Dcl = append(func_.Func.Dcl, xfunc.Func.Dcl...)
func_.Func.Dcl = nil
- if len(xfunc.Nbody.Slice()) == 0 {
+ if xfunc.Nbody.Len() == 0 {
Fatalf("empty body - won't generate any code")
}
xfunc = typecheck(xfunc, Etop)
@@ -419,7 +419,7 @@ func closuredebugruntimecheck(r *Node) {
Warnl(r.Lineno, "stack closure, captured vars = %v", r.Func.Cvars)
}
}
- if compiling_runtime > 0 && r.Esc == EscHeap {
+ if compiling_runtime && r.Esc == EscHeap {
yyerrorl(r.Lineno, "heap-allocated closure, not allowed in runtime.")
}
}
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index 5c9a67c8b5..e0f5e977fe 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -10,6 +10,59 @@ import (
"strings"
)
+// Ctype describes the constant kind of an "ideal" (untyped) constant.
+type Ctype int8
+
+const (
+ CTxxx Ctype = iota
+
+ CTINT
+ CTRUNE
+ CTFLT
+ CTCPLX
+ CTSTR
+ CTBOOL
+ CTNIL
+)
+
+type Val struct {
+ // U contains one of:
+ // bool bool when n.ValCtype() == CTBOOL
+ // *Mpint int when n.ValCtype() == CTINT, rune when n.ValCtype() == CTRUNE
+ // *Mpflt float when n.ValCtype() == CTFLT
+ // *Mpcplx pair of floats when n.ValCtype() == CTCPLX
+ // string string when n.ValCtype() == CTSTR
+ // *Nilval when n.ValCtype() == CTNIL
+ U interface{}
+}
+
+func (v Val) Ctype() Ctype {
+ switch x := v.U.(type) {
+ default:
+ Fatalf("unexpected Ctype for %T", v.U)
+ panic("not reached")
+ case nil:
+ return 0
+ case *NilVal:
+ return CTNIL
+ case bool:
+ return CTBOOL
+ case *Mpint:
+ if x.Rune {
+ return CTRUNE
+ }
+ return CTINT
+ case *Mpflt:
+ return CTFLT
+ case *Mpcplx:
+ return CTCPLX
+ case string:
+ return CTSTR
+ }
+}
+
+type NilVal struct{}
+
// IntLiteral returns the Node's literal value as an integer.
func (n *Node) IntLiteral() (x int64, ok bool) {
switch {
@@ -173,16 +226,13 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
case OCOMPLEX:
if n.Type.Etype == TIDEAL {
switch t.Etype {
- // If trying to convert to non-complex type,
- // leave as complex128 and let typechecker complain.
default:
+ // If trying to convert to non-complex type,
+ // leave as complex128 and let typechecker complain.
t = Types[TCOMPLEX128]
fallthrough
-
- //fallthrough
case TCOMPLEX128:
n.Type = t
-
n.Left = convlit(n.Left, Types[TFLOAT64])
n.Right = convlit(n.Right, Types[TFLOAT64])
@@ -231,9 +281,7 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
return n
case TARRAY:
- if !t.IsSlice() {
- goto bad
- }
+ goto bad
case TPTR32,
TPTR64,
@@ -241,6 +289,7 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
TMAP,
TCHAN,
TFUNC,
+ TSLICE,
TUNSAFEPTR:
break
@@ -326,22 +375,22 @@ bad:
}
func copyval(v Val) Val {
- switch v.Ctype() {
- case CTINT, CTRUNE:
+ switch u := v.U.(type) {
+ case *Mpint:
i := new(Mpint)
- i.Set(v.U.(*Mpint))
- i.Rune = v.U.(*Mpint).Rune
+ i.Set(u)
+ i.Rune = u.Rune
v.U = i
- case CTFLT:
+ case *Mpflt:
f := newMpflt()
- f.Set(v.U.(*Mpflt))
+ f.Set(u)
v.U = f
- case CTCPLX:
+ case *Mpcplx:
c := new(Mpcplx)
- c.Real.Set(&v.U.(*Mpcplx).Real)
- c.Imag.Set(&v.U.(*Mpcplx).Imag)
+ c.Real.Set(&u.Real)
+ c.Imag.Set(&u.Imag)
v.U = c
}
@@ -349,16 +398,16 @@ func copyval(v Val) Val {
}
func tocplx(v Val) Val {
- switch v.Ctype() {
- case CTINT, CTRUNE:
+ switch u := v.U.(type) {
+ case *Mpint:
c := new(Mpcplx)
- c.Real.SetInt(v.U.(*Mpint))
+ c.Real.SetInt(u)
c.Imag.SetFloat64(0.0)
v.U = c
- case CTFLT:
+ case *Mpflt:
c := new(Mpcplx)
- c.Real.Set(v.U.(*Mpflt))
+ c.Real.Set(u)
c.Imag.SetFloat64(0.0)
v.U = c
}
@@ -367,17 +416,17 @@ func tocplx(v Val) Val {
}
func toflt(v Val) Val {
- switch v.Ctype() {
- case CTINT, CTRUNE:
+ switch u := v.U.(type) {
+ case *Mpint:
f := newMpflt()
- f.SetInt(v.U.(*Mpint))
+ f.SetInt(u)
v.U = f
- case CTCPLX:
+ case *Mpcplx:
f := newMpflt()
- f.Set(&v.U.(*Mpcplx).Real)
- if v.U.(*Mpcplx).Imag.CmpFloat64(0) != 0 {
- Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, FmtSharp|FmtSign))
+ f.Set(&u.Real)
+ if u.Imag.CmpFloat64(0) != 0 {
+ Yyerror("constant %v%vi truncated to real", Fconv(&u.Real, FmtSharp), Fconv(&u.Imag, FmtSharp|FmtSign))
}
v.U = f
}
@@ -386,31 +435,33 @@ func toflt(v Val) Val {
}
func toint(v Val) Val {
- switch v.Ctype() {
- case CTRUNE:
- i := new(Mpint)
- i.Set(v.U.(*Mpint))
- v.U = i
+ switch u := v.U.(type) {
+ case *Mpint:
+ if u.Rune {
+ i := new(Mpint)
+ i.Set(u)
+ v.U = i
+ }
- case CTFLT:
+ case *Mpflt:
i := new(Mpint)
- if f := v.U.(*Mpflt); i.SetFloat(f) < 0 {
+ if i.SetFloat(u) < 0 {
msg := "constant %v truncated to integer"
// provide better error message if SetFloat failed because f was too large
- if f.Val.IsInt() {
+ if u.Val.IsInt() {
msg = "constant %v overflows integer"
}
- Yyerror(msg, Fconv(f, FmtSharp))
+ Yyerror(msg, Fconv(u, FmtSharp))
}
v.U = i
- case CTCPLX:
+ case *Mpcplx:
i := new(Mpint)
- if i.SetFloat(&v.U.(*Mpcplx).Real) < 0 {
- Yyerror("constant %v%vi truncated to integer", Fconv(&v.U.(*Mpcplx).Real, FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, FmtSharp|FmtSign))
+ if i.SetFloat(&u.Real) < 0 {
+ Yyerror("constant %v%vi truncated to integer", Fconv(&u.Real, FmtSharp), Fconv(&u.Imag, FmtSharp|FmtSign))
}
- if v.U.(*Mpcplx).Imag.CmpFloat64(0) != 0 {
- Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, FmtSharp|FmtSign))
+ if u.Imag.CmpFloat64(0) != 0 {
+ Yyerror("constant %v%vi truncated to real", Fconv(&u.Real, FmtSharp), Fconv(&u.Imag, FmtSharp|FmtSign))
}
v.U = i
}
@@ -419,30 +470,25 @@ func toint(v Val) Val {
}
func doesoverflow(v Val, t *Type) bool {
- switch v.Ctype() {
- case CTINT, CTRUNE:
+ switch u := v.U.(type) {
+ case *Mpint:
if !t.IsInteger() {
Fatalf("overflow: %v integer constant", t)
}
- if v.U.(*Mpint).Cmp(Minintval[t.Etype]) < 0 || v.U.(*Mpint).Cmp(Maxintval[t.Etype]) > 0 {
- return true
- }
+ return u.Cmp(Minintval[t.Etype]) < 0 || u.Cmp(Maxintval[t.Etype]) > 0
- case CTFLT:
+ case *Mpflt:
if !t.IsFloat() {
Fatalf("overflow: %v floating-point constant", t)
}
- if v.U.(*Mpflt).Cmp(minfltval[t.Etype]) <= 0 || v.U.(*Mpflt).Cmp(maxfltval[t.Etype]) >= 0 {
- return true
- }
+ return u.Cmp(minfltval[t.Etype]) <= 0 || u.Cmp(maxfltval[t.Etype]) >= 0
- case CTCPLX:
+ case *Mpcplx:
if !t.IsComplex() {
Fatalf("overflow: %v complex constant", t)
}
- if v.U.(*Mpcplx).Real.Cmp(minfltval[t.Etype]) <= 0 || v.U.(*Mpcplx).Real.Cmp(maxfltval[t.Etype]) >= 0 || v.U.(*Mpcplx).Imag.Cmp(minfltval[t.Etype]) <= 0 || v.U.(*Mpcplx).Imag.Cmp(maxfltval[t.Etype]) >= 0 {
- return true
- }
+ return u.Real.Cmp(minfltval[t.Etype]) <= 0 || u.Real.Cmp(maxfltval[t.Etype]) >= 0 ||
+ u.Imag.Cmp(minfltval[t.Etype]) <= 0 || u.Imag.Cmp(maxfltval[t.Etype]) >= 0
}
return false
@@ -466,21 +512,16 @@ func overflow(v Val, t *Type) {
}
func tostr(v Val) Val {
- switch v.Ctype() {
- case CTINT, CTRUNE:
+ switch u := v.U.(type) {
+ case *Mpint:
var i int64 = 0xFFFD
- if u := v.U.(*Mpint); u.Cmp(Minintval[TUINT32]) >= 0 && u.Cmp(Maxintval[TUINT32]) <= 0 {
+ if u.Cmp(Minintval[TUINT32]) >= 0 && u.Cmp(Maxintval[TUINT32]) <= 0 {
i = u.Int64()
}
- v = Val{}
v.U = string(i)
- case CTFLT:
- Yyerror("no float -> string")
- fallthrough
-
- case CTNIL:
- v = Val{}
+ case *NilVal:
+ // Can happen because of string([]byte(nil)).
v.U = ""
}
@@ -654,7 +695,7 @@ func evconst(n *Node) {
switch uint32(n.Op)<<16 | uint32(v.Ctype()) {
default:
if n.Diag == 0 {
- Yyerror("illegal constant expression %v %v", Oconv(n.Op, 0), nl.Type)
+ Yyerror("illegal constant expression %v %v", n.Op, nl.Type)
n.Diag = 1
}
return
@@ -667,8 +708,6 @@ func evconst(n *Node) {
break
}
fallthrough
-
- // fall through
case OCONV_ | CTINT_,
OCONV_ | CTRUNE_,
OCONV_ | CTFLT_,
@@ -1140,7 +1179,7 @@ setfalse:
illegal:
if n.Diag == 0 {
- Yyerror("illegal constant expression: %v %v %v", nl.Type, Oconv(n.Op, 0), nr.Type)
+ Yyerror("illegal constant expression: %v %v %v", nl.Type, n.Op, nr.Type)
n.Diag = 1
}
}
diff --git a/src/cmd/compile/internal/gc/cplx.go b/src/cmd/compile/internal/gc/cplx.go
index b0fa70b0ad..9bb2027520 100644
--- a/src/cmd/compile/internal/gc/cplx.go
+++ b/src/cmd/compile/internal/gc/cplx.go
@@ -89,8 +89,9 @@ func subnode(nr *Node, ni *Node, nc *Node) {
t := Types[tc]
if nc.Op == OLITERAL {
- nodfconst(nr, t, &nc.Val().U.(*Mpcplx).Real)
- nodfconst(ni, t, &nc.Val().U.(*Mpcplx).Imag)
+ u := nc.Val().U.(*Mpcplx)
+ nodfconst(nr, t, &u.Real)
+ nodfconst(ni, t, &u.Imag)
return
}
@@ -398,7 +399,7 @@ func Complexgen(n *Node, res *Node) {
switch n.Op {
default:
Dump("complexgen: unknown op", n)
- Fatalf("complexgen: unknown op %v", Oconv(n.Op, 0))
+ Fatalf("complexgen: unknown op %v", n.Op)
case ODOT,
ODOTPTR,
@@ -457,7 +458,7 @@ func Complexgen(n *Node, res *Node) {
switch n.Op {
default:
- Fatalf("complexgen: unknown op %v", Oconv(n.Op, 0))
+ Fatalf("complexgen: unknown op %v", n.Op)
case OCONV:
Complexmove(nl, res)
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
index bd5a1f6f07..6d46d9a73c 100644
--- a/src/cmd/compile/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -11,21 +11,29 @@ import (
"strings"
)
-func dflag() bool {
- if Debug['d'] == 0 {
- return false
- }
- if Debug['y'] != 0 {
- return true
- }
- if incannedimport != 0 {
- return false
- }
- return true
-}
+// Declaration stack & operations
+
+var externdcl []*Node
-// declaration stack & operations
-func dcopy(a *Sym, b *Sym) {
+var blockgen int32 // max block number
+
+var block int32 // current block number
+
+// dclstack maintains a stack of shadowed symbol declarations so that
+// popdcl can restore their declarations when a block scope ends.
+// The stack is maintained as a linked list, using Sym's Link field.
+//
+// In practice, the "stack" actually ends up forming a tree: goto and label
+// statements record the current state of dclstack so that checkgoto can
+// validate that a goto statement does not jump over any declarations or
+// into a new block scope.
+//
+// Finally, the Syms in this list are not "real" Syms as they don't actually
+// represent object names. Sym is just a convenient type for saving shadowed
+// Sym definitions, and only a subset of its fields are actually used.
+var dclstack *Sym
+
+func dcopy(a, b *Sym) {
a.Pkg = b.Pkg
a.Name = b.Name
a.Def = b.Def
@@ -41,15 +49,16 @@ func push() *Sym {
return d
}
+// pushdcl pushes the current declaration for symbol s (if any) so that
+// it can be shadowed by a new declaration within a nested block scope.
func pushdcl(s *Sym) *Sym {
d := push()
dcopy(d, s)
- if dflag() {
- fmt.Printf("\t%v push %v %p\n", linestr(lineno), s, s.Def)
- }
return d
}
+// popdcl pops the innermost block scope and restores all symbol declarations
+// to their previous state.
func popdcl() {
d := dclstack
for ; d != nil && d.Name != ""; d = d.Link {
@@ -57,9 +66,6 @@ func popdcl() {
lno := s.Lastlineno
dcopy(s, d)
d.Lastlineno = lno
- if dflag() {
- fmt.Printf("\t%v pop %v %p\n", linestr(lineno), s, s.Def)
- }
}
if d == nil {
@@ -70,6 +76,7 @@ func popdcl() {
block = d.Block
}
+// markdcl records the start of a new block scope for declarations.
func markdcl() {
d := push()
d.Name = "" // used as a mark in fifo
@@ -104,6 +111,7 @@ func testdclstack() {
}
}
+// redeclare emits a diagnostic about symbol s being redeclared somewhere.
func redeclare(s *Sym, where string) {
if s.Lastlineno == 0 {
var tmp string
@@ -137,6 +145,8 @@ var vargen int
var declare_typegen int
+// declare records that Node n declares symbol n.Sym in the specified
+// declaration context.
func declare(n *Node, ctxt Class) {
if ctxt == PDISCARD {
return
@@ -165,9 +175,6 @@ func declare(n *Node, ctxt Class) {
gen := 0
if ctxt == PEXTERN {
externdcl = append(externdcl, n)
- if dflag() {
- fmt.Printf("\t%v global decl %v %p\n", linestr(lineno), s, n)
- }
} else {
if Curfn == nil && ctxt == PAUTO {
Fatalf("automatic outside function")
@@ -318,8 +325,7 @@ func constiter(vl []*Node, t *Node, cl []*Node) []*Node {
return vv
}
-// this generates a new name node,
-// typically for labels or other one-off names.
+// newname returns a new ONAME Node associated with symbol s.
func newname(s *Sym) *Node {
if s == nil {
Fatalf("newname nil")
@@ -364,17 +370,14 @@ func typenod(t *Type) *Node {
return t.Nod
}
-// this will return an old name
-// that has already been pushed on the
-// declaration list. a diagnostic is
-// generated if no name has been defined.
+// oldname returns the Node that declares symbol s in the current scope.
+// If no such Node currently exists, an ONONAME Node is returned instead.
func oldname(s *Sym) *Node {
n := s.Def
if n == nil {
- // maybe a top-level name will come along
- // to give this a definition later.
- // walkdef will check s->def again once
- // all the input source has been processed.
+ // Maybe a top-level declaration will come along later to
+ // define s. resolve will check s.Def again once all input
+ // source has been processed.
n = newname(s)
n.Op = ONONAME
n.Name.Iota = iota_ // save current iota value in const declarations
@@ -548,7 +551,7 @@ func funchdr(n *Node) {
func funcargs(nt *Node) {
if nt.Op != OTFUNC {
- Fatalf("funcargs %v", Oconv(nt.Op, 0))
+ Fatalf("funcargs %v", nt.Op)
}
// re-start the variable generation number
@@ -562,7 +565,7 @@ func funcargs(nt *Node) {
if nt.Left != nil {
n := nt.Left
if n.Op != ODCLFIELD {
- Fatalf("funcargs receiver %v", Oconv(n.Op, 0))
+ Fatalf("funcargs receiver %v", n.Op)
}
if n.Left != nil {
n.Left.Op = ONAME
@@ -577,7 +580,7 @@ func funcargs(nt *Node) {
for _, n := range nt.List.Slice() {
if n.Op != ODCLFIELD {
- Fatalf("funcargs in %v", Oconv(n.Op, 0))
+ Fatalf("funcargs in %v", n.Op)
}
if n.Left != nil {
n.Left.Op = ONAME
@@ -595,7 +598,7 @@ func funcargs(nt *Node) {
var i int = 0
for _, n := range nt.Rlist.Slice() {
if n.Op != ODCLFIELD {
- Fatalf("funcargs out %v", Oconv(n.Op, 0))
+ Fatalf("funcargs out %v", n.Op)
}
if n.Left == nil {
@@ -716,10 +719,10 @@ func checkembeddedtype(t *Type) {
}
}
- if t.IsPtr() {
+ if t.IsPtr() || t.IsUnsafePtr() {
Yyerror("embedded type cannot be a pointer")
- } else if t.Etype == TFORW && t.Embedlineno == 0 {
- t.Embedlineno = lineno
+ } else if t.Etype == TFORW && t.ForwardType().Embedlineno == 0 {
+ t.ForwardType().Embedlineno = lineno
}
}
@@ -752,17 +755,13 @@ func structfield(n *Node) *Field {
f.Broke = true
}
- switch n.Val().Ctype() {
- case CTSTR:
- f.Note = new(string)
- *f.Note = n.Val().U.(string)
-
+ switch u := n.Val().U.(type) {
+ case string:
+ f.Note = u
default:
Yyerror("field annotation must be string")
- fallthrough
-
- case CTxxx:
- f.Note = nil
+ case nil:
+ // noop
}
if n.Left != nil && n.Left.Op == ONAME {
@@ -830,7 +829,7 @@ func tostruct0(t *Type, l []*Node) {
func tofunargs(l []*Node) *Type {
t := typ(TSTRUCT)
- t.Funarg = true
+ t.StructType().Funarg = true
fields := make([]*Field, len(l))
for i, n := range l {
@@ -1036,11 +1035,11 @@ func functype0(t *Type, this *Node, in, out []*Node) {
t.Broke = true
}
- t.Outnamed = false
+ t.FuncType().Outnamed = false
if len(out) > 0 && out[0].Left != nil && out[0].Left.Orig != nil {
s := out[0].Left.Orig.Sym
if s != nil && (s.Name[0] != '~' || s.Name[1] != 'r') { // ~r%d is the name invented for an unnamed result
- t.Outnamed = true
+ t.FuncType().Outnamed = true
}
}
}
@@ -1305,7 +1304,7 @@ func makefuncsym(s *Sym) {
if isblanksym(s) {
return
}
- if compiling_runtime != 0 && s.Name == "getg" {
+ if compiling_runtime && s.Name == "getg" {
// runtime.getg() is not a real function and so does
// not get a funcsym.
return
@@ -1415,7 +1414,7 @@ func (c *nowritebarrierrecChecker) visitcall(n *Node) {
if fn == nil || fn.Op != ONAME || fn.Class != PFUNC || fn.Name.Defn == nil {
return
}
- if (compiling_runtime != 0 || fn.Sym.Pkg == Runtimepkg) && fn.Sym.Name == "allocm" {
+ if (compiling_runtime || fn.Sym.Pkg == Runtimepkg) && fn.Sym.Name == "allocm" {
return
}
defn := fn.Name.Defn
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index 9b8f134178..52c09e47f9 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -522,7 +522,7 @@ func escfunc(e *EscState, func_ *Node) {
if ln.Type != nil && !haspointers(ln.Type) {
break
}
- if len(Curfn.Nbody.Slice()) == 0 && !Curfn.Noescape {
+ if Curfn.Nbody.Len() == 0 && !Curfn.Noescape {
ln.Esc = EscHeap
} else {
ln.Esc = EscNone // prime for escflood later
@@ -998,8 +998,8 @@ func escassign(e *EscState, dst, src *Node, step *EscStep) {
if Debug['m'] > 2 {
fmt.Printf("%v:[%d] %v escassign: %v(%v)[%v] = %v(%v)[%v]\n",
linestr(lineno), e.loopdepth, funcSym(Curfn),
- Nconv(dst, FmtShort), Jconv(dst, FmtShort), Oconv(dst.Op, 0),
- Nconv(src, FmtShort), Jconv(src, FmtShort), Oconv(src.Op, 0))
+ Nconv(dst, FmtShort), Jconv(dst, FmtShort), dst.Op,
+ Nconv(src, FmtShort), Jconv(src, FmtShort), src.Op)
}
setlineno(dst)
@@ -1181,7 +1181,7 @@ func escassign(e *EscState, dst, src *Node, step *EscStep) {
var tags [1 << (bitsPerOutputInTag + EscReturnBits)]string
// mktag returns the string representation for an escape analysis tag.
-func mktag(mask int) *string {
+func mktag(mask int) string {
switch mask & EscMask {
case EscNone, EscReturn:
break
@@ -1191,22 +1191,22 @@ func mktag(mask int) *string {
}
if mask < len(tags) && tags[mask] != "" {
- return &tags[mask]
+ return tags[mask]
}
s := fmt.Sprintf("esc:0x%x", mask)
if mask < len(tags) {
tags[mask] = s
}
- return &s
+ return s
}
// parsetag decodes an escape analysis tag and returns the esc value.
-func parsetag(note *string) uint16 {
- if note == nil || !strings.HasPrefix(*note, "esc:") {
+func parsetag(note string) uint16 {
+ if !strings.HasPrefix(note, "esc:") {
return EscUnknown
}
- n, _ := strconv.ParseInt((*note)[4:], 0, 0)
+ n, _ := strconv.ParseInt(note[4:], 0, 0)
em := uint16(n)
if em == 0 {
return EscNone
@@ -1268,7 +1268,7 @@ func describeEscape(em uint16) string {
// escassignfromtag models the input-to-output assignment flow of one of a function
// calls arguments, where the flow is encoded in "note".
-func escassignfromtag(e *EscState, note *string, dsts Nodes, src *Node) uint16 {
+func escassignfromtag(e *EscState, note string, dsts Nodes, src *Node) uint16 {
em := parsetag(note)
if src.Op == OLITERAL {
return em
@@ -1435,7 +1435,7 @@ func esccall(e *EscState, n *Node, up *Node) {
ll := n.List
if n.List.Len() == 1 {
a := n.List.First()
- if a.Type.IsStruct() && a.Type.Funarg { // f(g()).
+ if a.Type.IsFuncArgStruct() { // f(g())
ll = e.nodeEscState(a).Escretval
}
}
@@ -1469,7 +1469,7 @@ func esccall(e *EscState, n *Node, up *Node) {
nE := e.nodeEscState(n)
if fn != nil && fn.Op == ONAME && fn.Class == PFUNC &&
- fn.Name.Defn != nil && len(fn.Name.Defn.Nbody.Slice()) != 0 && fn.Name.Param.Ntype != nil && fn.Name.Defn.Esc < EscFuncTagged {
+ fn.Name.Defn != nil && fn.Name.Defn.Nbody.Len() != 0 && fn.Name.Param.Ntype != nil && fn.Name.Defn.Esc < EscFuncTagged {
if Debug['m'] > 3 {
fmt.Printf("%v::esccall:: %v in recursive group\n", linestr(lineno), Nconv(n, FmtShort))
}
@@ -1741,7 +1741,7 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep,
if Debug['m'] > 2 {
fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %v(%v) scope:%v[%d] extraloopdepth=%v\n",
- level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Oconv(src.Op, 0), Nconv(src, FmtShort), Jconv(src, FmtShort), e.curfnSym(src), srcE.Escloopdepth, extraloopdepth)
+ level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", src.Op, Nconv(src, FmtShort), Jconv(src, FmtShort), e.curfnSym(src), srcE.Escloopdepth, extraloopdepth)
}
e.pdepth++
@@ -1969,7 +1969,7 @@ func esctag(e *EscState, func_ *Node) {
// External functions are assumed unsafe,
// unless //go:noescape is given before the declaration.
- if len(func_.Nbody.Slice()) == 0 {
+ if func_.Nbody.Len() == 0 {
if func_.Noescape {
for _, t := range func_.Type.Params().Fields().Slice() {
if haspointers(t.Type) {
@@ -1997,7 +1997,7 @@ func esctag(e *EscState, func_ *Node) {
}
Warnl(func_.Lineno, "%v assuming %v is unsafe uintptr", funcSym(func_), name)
}
- t.Note = &unsafeUintptrTag
+ t.Note = unsafeUintptrTag
}
}
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
index 9fc6e56275..4b48c53b91 100644
--- a/src/cmd/compile/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -7,7 +7,7 @@ package gc
import (
"bufio"
"bytes"
- "cmd/internal/obj"
+ "cmd/internal/bio"
"fmt"
"sort"
"unicode"
@@ -15,8 +15,8 @@ import (
)
var (
- newexport int // if set, use new export format
- Debug_export int // if set, print debugging information about export data
+ newexport bool // if set, use new export format
+ Debug_export int // if set, print debugging information about export data
exportsize int
)
@@ -203,7 +203,7 @@ func reexportdep(n *Node) {
t := n.Type
switch t.Etype {
- case TARRAY, TCHAN, TPTR32, TPTR64:
+ case TARRAY, TCHAN, TPTR32, TPTR64, TSLICE:
if t.Sym == nil {
t = t.Elem()
}
@@ -252,7 +252,7 @@ func dumpexportvar(s *Sym) {
dumpexporttype(t)
if t.Etype == TFUNC && n.Class == PFUNC {
- if n.Func != nil && len(n.Func.Inl.Slice()) != 0 {
+ if n.Func != nil && n.Func.Inl.Len() != 0 {
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
if Debug['l'] < 2 {
@@ -303,7 +303,7 @@ func dumpexporttype(t *Type) {
case TMAP:
dumpexporttype(t.Val())
dumpexporttype(t.Key())
- case TARRAY, TCHAN, TPTR32, TPTR64:
+ case TARRAY, TCHAN, TPTR32, TPTR64, TSLICE:
dumpexporttype(t.Elem())
}
@@ -323,7 +323,7 @@ func dumpexporttype(t *Type) {
if f.Nointerface {
exportf("\t//go:nointerface\n")
}
- if f.Type.Nname() != nil && len(f.Type.Nname().Func.Inl.Slice()) != 0 { // nname was set by caninl
+ if f.Type.Nname() != nil && f.Type.Nname().Func.Inl.Len() != 0 { // nname was set by caninl
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
@@ -354,7 +354,7 @@ func dumpsym(s *Sym) {
switch s.Def.Op {
default:
- Yyerror("unexpected export symbol: %v %v", Oconv(s.Def.Op, 0), s)
+ Yyerror("unexpected export symbol: %v %v", s.Def.Op, s)
case OLITERAL:
dumpexportconst(s)
@@ -377,15 +377,15 @@ func dumpexport() {
}
size := 0 // size of export section without enclosing markers
- if forceNewExport || newexport != 0 {
+ if newexport {
// binary export
// The linker also looks for the $$ marker - use char after $$ to distinguish format.
exportf("\n$$B\n") // indicate binary format
if debugFormat {
// save a copy of the export data
var copy bytes.Buffer
- bcopy := obj.Binitw(&copy)
- size = Export(bcopy, Debug_export != 0)
+ bcopy := bufio.NewWriter(&copy)
+ size = export(bcopy, Debug_export != 0)
bcopy.Flush() // flushing to bytes.Buffer cannot fail
if n, err := bout.Write(copy.Bytes()); n != size || err != nil {
Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err)
@@ -407,7 +407,7 @@ func dumpexport() {
pkgs = savedPkgs
pkgMap = savedPkgMap
} else {
- size = Export(bout, Debug_export != 0)
+ size = export(bout.Writer, Debug_export != 0)
}
exportf("\n$$\n")
} else {
@@ -417,7 +417,7 @@ func dumpexport() {
exportf("\n$$\n") // indicate textual format
exportsize = 0
exportf("package %s", localpkg.Name)
- if safemode != 0 {
+ if safemode {
exportf(" safe")
}
exportf("\n")
@@ -577,7 +577,7 @@ func importtype(pt *Type, t *Type) {
}
func dumpasmhdr() {
- b, err := obj.Bopenw(asmhdr)
+ b, err := bio.Create(asmhdr)
if err != nil {
Fatalf("%v", err)
}
@@ -592,7 +592,7 @@ func dumpasmhdr() {
case OTYPE:
t := n.Type
- if !t.IsStruct() || t.Map != nil || t.Funarg {
+ if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
break
}
fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width))
@@ -604,5 +604,5 @@ func dumpasmhdr() {
}
}
- obj.Bterm(b)
+ b.Close()
}
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index ab9bad3c2a..2c3afb0ecc 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -193,7 +193,7 @@ var goopnames = []string{
}
// Fmt "%O": Node opcodes
-func Oconv(o Op, flag FmtFlag) string {
+func oconv(o Op, flag FmtFlag) string {
if (flag&FmtSharp != 0) || fmtmode != FDbg {
if o >= 0 && int(o) < len(goopnames) && goopnames[o] != "" {
return goopnames[o]
@@ -319,6 +319,12 @@ func Jconv(n *Node, flag FmtFlag) string {
if n.Assigned {
buf.WriteString(" assigned")
}
+ if n.Bounded {
+ buf.WriteString(" bounded")
+ }
+ if n.NonNil {
+ buf.WriteString(" nonnil")
+ }
if c == 0 && n.Used {
fmt.Fprintf(&buf, " used(%v)", n.Used)
@@ -328,16 +334,17 @@ func Jconv(n *Node, flag FmtFlag) string {
// Fmt "%V": Values
func Vconv(v Val, flag FmtFlag) string {
- switch v.Ctype() {
- case CTINT:
- if (flag&FmtSharp != 0) || fmtmode == FExp {
- return Bconv(v.U.(*Mpint), FmtSharp)
+ switch u := v.U.(type) {
+ case *Mpint:
+ if !u.Rune {
+ if (flag&FmtSharp != 0) || fmtmode == FExp {
+ return Bconv(u, FmtSharp)
+ }
+ return Bconv(u, 0)
}
- return Bconv(v.U.(*Mpint), 0)
- case CTRUNE:
- x := v.U.(*Mpint).Int64()
- if ' ' <= x && x < 0x80 && x != '\\' && x != '\'' {
+ x := u.Int64()
+ if ' ' <= x && x < utf8.RuneSelf && x != '\\' && x != '\'' {
return fmt.Sprintf("'%c'", int(x))
}
if 0 <= x && x < 1<<16 {
@@ -346,39 +353,39 @@ func Vconv(v Val, flag FmtFlag) string {
if 0 <= x && x <= utf8.MaxRune {
return fmt.Sprintf("'\\U%08x'", uint64(x))
}
- return fmt.Sprintf("('\\x00' + %v)", v.U.(*Mpint))
+ return fmt.Sprintf("('\\x00' + %v)", u)
- case CTFLT:
+ case *Mpflt:
if (flag&FmtSharp != 0) || fmtmode == FExp {
- return Fconv(v.U.(*Mpflt), 0)
+ return Fconv(u, 0)
}
- return Fconv(v.U.(*Mpflt), FmtSharp)
+ return Fconv(u, FmtSharp)
- case CTCPLX:
+ case *Mpcplx:
if (flag&FmtSharp != 0) || fmtmode == FExp {
- return fmt.Sprintf("(%v+%vi)", &v.U.(*Mpcplx).Real, &v.U.(*Mpcplx).Imag)
+ return fmt.Sprintf("(%v+%vi)", &u.Real, &u.Imag)
}
if v.U.(*Mpcplx).Real.CmpFloat64(0) == 0 {
- return fmt.Sprintf("%vi", Fconv(&v.U.(*Mpcplx).Imag, FmtSharp))
+ return fmt.Sprintf("%vi", Fconv(&u.Imag, FmtSharp))
}
if v.U.(*Mpcplx).Imag.CmpFloat64(0) == 0 {
- return Fconv(&v.U.(*Mpcplx).Real, FmtSharp)
+ return Fconv(&u.Real, FmtSharp)
}
if v.U.(*Mpcplx).Imag.CmpFloat64(0) < 0 {
- return fmt.Sprintf("(%v%vi)", Fconv(&v.U.(*Mpcplx).Real, FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, FmtSharp))
+ return fmt.Sprintf("(%v%vi)", Fconv(&u.Real, FmtSharp), Fconv(&u.Imag, FmtSharp))
}
- return fmt.Sprintf("(%v+%vi)", Fconv(&v.U.(*Mpcplx).Real, FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, FmtSharp))
+ return fmt.Sprintf("(%v+%vi)", Fconv(&u.Real, FmtSharp), Fconv(&u.Imag, FmtSharp))
- case CTSTR:
- return strconv.Quote(v.U.(string))
+ case string:
+ return strconv.Quote(u)
- case CTBOOL:
- if v.U.(bool) {
+ case bool:
+ if u {
return "true"
}
return "false"
- case CTNIL:
+ case *NilVal:
return "nil"
}
@@ -416,6 +423,7 @@ var etnames = []string{
TPTR64: "PTR64",
TFUNC: "FUNC",
TARRAY: "ARRAY",
+ TSLICE: "SLICE",
TSTRUCT: "STRUCT",
TCHAN: "CHAN",
TMAP: "MAP",
@@ -445,6 +453,10 @@ func (e EType) String() string {
return Econv(e)
}
+func (o Op) String() string {
+ return oconv(o, 0)
+}
+
// Fmt "%S": syms
func symfmt(s *Sym, flag FmtFlag) string {
if s.Pkg != nil && flag&FmtShort == 0 {
@@ -574,7 +586,7 @@ func typefmt(t *Type, flag FmtFlag) string {
if fmtmode == FDbg {
fmtmode = 0
- str := Econv(t.Etype) + "-" + typefmt(t, flag)
+ str := t.Etype.String() + "-" + typefmt(t, flag)
fmtmode = FDbg
return str
}
@@ -587,12 +599,12 @@ func typefmt(t *Type, flag FmtFlag) string {
return "*" + t.Elem().String()
case TARRAY:
- if t.IsArray() {
- return fmt.Sprintf("[%d]%v", t.NumElem(), t.Elem())
- }
if t.isDDDArray() {
return "[...]" + t.Elem().String()
}
+ return fmt.Sprintf("[%d]%v", t.NumElem(), t.Elem())
+
+ case TSLICE:
return "[]" + t.Elem().String()
case TCHAN:
@@ -671,26 +683,27 @@ func typefmt(t *Type, flag FmtFlag) string {
return buf.String()
case TSTRUCT:
- if t.Map != nil {
+ if m := t.StructType().Map; m != nil {
+ mt := m.MapType()
// Format the bucket struct for map[x]y as map.bucket[x]y.
// This avoids a recursive print that generates very long names.
- if t.Map.Bucket == t {
- return "map.bucket[" + t.Map.Key().String() + "]" + t.Map.Val().String()
+ if mt.Bucket == t {
+ return "map.bucket[" + m.Key().String() + "]" + m.Val().String()
}
- if t.Map.Hmap == t {
- return "map.hdr[" + t.Map.Key().String() + "]" + t.Map.Val().String()
+ if mt.Hmap == t {
+ return "map.hdr[" + m.Key().String() + "]" + m.Val().String()
}
- if t.Map.Hiter == t {
- return "map.iter[" + t.Map.Key().String() + "]" + t.Map.Val().String()
+ if mt.Hiter == t {
+ return "map.iter[" + m.Key().String() + "]" + m.Val().String()
}
Yyerror("unknown internal map type")
}
var buf bytes.Buffer
- if t.Funarg {
+ if t.IsFuncArgStruct() {
buf.WriteString("(")
var flag1 FmtFlag
if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags
@@ -735,15 +748,18 @@ func typefmt(t *Type, flag FmtFlag) string {
if fmtmode == FExp {
Fatalf("cannot use TDDDFIELD with old exporter")
}
- return fmt.Sprintf("%v <%v> %v", Econv(t.Etype), t.Sym, t.Wrapped())
+ return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.DDDField())
+
+ case Txxx:
+ return "Txxx"
}
if fmtmode == FExp {
- Fatalf("missing %v case during export", Econv(t.Etype))
+ Fatalf("missing %v case during export", t.Etype)
}
// Don't know how to handle - fall back to detailed prints.
- return fmt.Sprintf("%v <%v> %v", Econv(t.Etype), t.Sym, t.Elem())
+ return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.Elem())
}
// Statements which may be rendered with a simplestmt as init.
@@ -824,7 +840,7 @@ func stmtfmt(n *Node) string {
break
}
- f += fmt.Sprintf("%v %v= %v", n.Left, Oconv(Op(n.Etype), FmtSharp), n.Right)
+ f += fmt.Sprintf("%v %v= %v", n.Left, oconv(Op(n.Etype), FmtSharp), n.Right)
case OAS2:
if n.Colas && !complexinit {
@@ -898,11 +914,11 @@ func stmtfmt(n *Node) string {
case OSELECT, OSWITCH:
if fmtmode == FErr {
- f += fmt.Sprintf("%v statement", Oconv(n.Op, 0))
+ f += fmt.Sprintf("%v statement", n.Op)
break
}
- f += Oconv(n.Op, FmtSharp)
+ f += oconv(n.Op, FmtSharp)
if simpleinit {
f += fmt.Sprintf(" %v;", n.Ninit.First())
}
@@ -925,9 +941,9 @@ func stmtfmt(n *Node) string {
OFALL,
OXFALL:
if n.Left != nil {
- f += fmt.Sprintf("%v %v", Oconv(n.Op, FmtSharp), n.Left)
+ f += fmt.Sprintf("%v %v", oconv(n.Op, FmtSharp), n.Left)
} else {
- f += Oconv(n.Op, FmtSharp)
+ f += oconv(n.Op, FmtSharp)
}
case OEMPTY:
@@ -1180,7 +1196,7 @@ func exprfmt(n *Node, prec int) string {
if fmtmode == FErr {
return "func literal"
}
- if len(n.Nbody.Slice()) != 0 {
+ if n.Nbody.Len() != 0 {
return fmt.Sprintf("%v { %v }", n.Type, n.Nbody)
}
return fmt.Sprintf("%v { %v }", n.Type, n.Name.Param.Closure.Nbody)
@@ -1296,20 +1312,32 @@ func exprfmt(n *Node, prec int) string {
f += fmt.Sprintf(".(%v)", n.Type)
return f
- case OINDEX,
- OINDEXMAP,
- OSLICE,
- OSLICESTR,
- OSLICEARR,
- OSLICE3,
- OSLICE3ARR:
- var f string
- f += exprfmt(n.Left, nprec)
- f += fmt.Sprintf("[%v]", n.Right)
- return f
+ case OINDEX, OINDEXMAP:
+ return fmt.Sprintf("%s[%v]", exprfmt(n.Left, nprec), n.Right)
+
+ case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
+ var buf bytes.Buffer
+ buf.WriteString(exprfmt(n.Left, nprec))
+ buf.WriteString("[")
+ low, high, max := n.SliceBounds()
+ if low != nil {
+ buf.WriteString(low.String())
+ }
+ buf.WriteString(":")
+ if high != nil {
+ buf.WriteString(high.String())
+ }
+ if n.Op.IsSlice3() {
+ buf.WriteString(":")
+ if max != nil {
+ buf.WriteString(max.String())
+ }
+ }
+ buf.WriteString("]")
+ return buf.String()
case OCOPY, OCOMPLEX:
- return fmt.Sprintf("%v(%v, %v)", Oconv(n.Op, FmtSharp), n.Left, n.Right)
+ return fmt.Sprintf("%v(%v, %v)", oconv(n.Op, FmtSharp), n.Left, n.Right)
case OCONV,
OCONVIFACE,
@@ -1341,12 +1369,12 @@ func exprfmt(n *Node, prec int) string {
OPRINT,
OPRINTN:
if n.Left != nil {
- return fmt.Sprintf("%v(%v)", Oconv(n.Op, FmtSharp), n.Left)
+ return fmt.Sprintf("%v(%v)", oconv(n.Op, FmtSharp), n.Left)
}
if n.Isddd {
- return fmt.Sprintf("%v(%v...)", Oconv(n.Op, FmtSharp), Hconv(n.List, FmtComma))
+ return fmt.Sprintf("%v(%v...)", oconv(n.Op, FmtSharp), Hconv(n.List, FmtComma))
}
- return fmt.Sprintf("%v(%v)", Oconv(n.Op, FmtSharp), Hconv(n.List, FmtComma))
+ return fmt.Sprintf("%v(%v)", oconv(n.Op, FmtSharp), Hconv(n.List, FmtComma))
case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
var f string
@@ -1380,9 +1408,9 @@ func exprfmt(n *Node, prec int) string {
ORECV:
var f string
if n.Left.Op == n.Op {
- f += fmt.Sprintf("%v ", Oconv(n.Op, FmtSharp))
+ f += fmt.Sprintf("%v ", oconv(n.Op, FmtSharp))
} else {
- f += Oconv(n.Op, FmtSharp)
+ f += oconv(n.Op, FmtSharp)
}
f += exprfmt(n.Left, nprec+1)
return f
@@ -1411,7 +1439,7 @@ func exprfmt(n *Node, prec int) string {
var f string
f += exprfmt(n.Left, nprec)
- f += fmt.Sprintf(" %v ", Oconv(n.Op, FmtSharp))
+ f += fmt.Sprintf(" %v ", oconv(n.Op, FmtSharp))
f += exprfmt(n.Right, nprec+1)
return f
@@ -1432,7 +1460,7 @@ func exprfmt(n *Node, prec int) string {
var f string
f += exprfmt(n.Left, nprec)
// TODO(marvin): Fix Node.EType type union.
- f += fmt.Sprintf(" %v ", Oconv(Op(n.Etype), FmtSharp))
+ f += fmt.Sprintf(" %v ", oconv(Op(n.Etype), FmtSharp))
f += exprfmt(n.Right, nprec+1)
return f
@@ -1444,7 +1472,7 @@ func exprfmt(n *Node, prec int) string {
}
}
- return fmt.Sprintf("<node %v>", Oconv(n.Op, 0))
+ return fmt.Sprintf("<node %v>", n.Op)
}
func nodefmt(n *Node, flag FmtFlag) string {
@@ -1499,40 +1527,40 @@ func nodedump(n *Node, flag FmtFlag) string {
}
if n.Ninit.Len() != 0 {
- fmt.Fprintf(&buf, "%v-init%v", Oconv(n.Op, 0), n.Ninit)
+ fmt.Fprintf(&buf, "%v-init%v", n.Op, n.Ninit)
indent(&buf)
}
}
switch n.Op {
default:
- fmt.Fprintf(&buf, "%v%v", Oconv(n.Op, 0), Jconv(n, 0))
+ fmt.Fprintf(&buf, "%v%v", n.Op, Jconv(n, 0))
case OREGISTER, OINDREG:
- fmt.Fprintf(&buf, "%v-%v%v", Oconv(n.Op, 0), obj.Rconv(int(n.Reg)), Jconv(n, 0))
+ fmt.Fprintf(&buf, "%v-%v%v", n.Op, obj.Rconv(int(n.Reg)), Jconv(n, 0))
case OLITERAL:
- fmt.Fprintf(&buf, "%v-%v%v", Oconv(n.Op, 0), Vconv(n.Val(), 0), Jconv(n, 0))
+ fmt.Fprintf(&buf, "%v-%v%v", n.Op, Vconv(n.Val(), 0), Jconv(n, 0))
case ONAME, ONONAME:
if n.Sym != nil {
- fmt.Fprintf(&buf, "%v-%v%v", Oconv(n.Op, 0), n.Sym, Jconv(n, 0))
+ fmt.Fprintf(&buf, "%v-%v%v", n.Op, n.Sym, Jconv(n, 0))
} else {
- fmt.Fprintf(&buf, "%v%v", Oconv(n.Op, 0), Jconv(n, 0))
+ fmt.Fprintf(&buf, "%v%v", n.Op, Jconv(n, 0))
}
if recur && n.Type == nil && n.Name != nil && n.Name.Param != nil && n.Name.Param.Ntype != nil {
indent(&buf)
- fmt.Fprintf(&buf, "%v-ntype%v", Oconv(n.Op, 0), n.Name.Param.Ntype)
+ fmt.Fprintf(&buf, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
}
case OASOP:
- fmt.Fprintf(&buf, "%v-%v%v", Oconv(n.Op, 0), Oconv(Op(n.Etype), 0), Jconv(n, 0))
+ fmt.Fprintf(&buf, "%v-%v%v", n.Op, Op(n.Etype), Jconv(n, 0))
case OTYPE:
- fmt.Fprintf(&buf, "%v %v%v type=%v", Oconv(n.Op, 0), n.Sym, Jconv(n, 0), n.Type)
+ fmt.Fprintf(&buf, "%v %v%v type=%v", n.Op, n.Sym, Jconv(n, 0), n.Type)
if recur && n.Type == nil && n.Name.Param.Ntype != nil {
indent(&buf)
- fmt.Fprintf(&buf, "%v-ntype%v", Oconv(n.Op, 0), n.Name.Param.Ntype)
+ fmt.Fprintf(&buf, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
}
}
@@ -1553,17 +1581,17 @@ func nodedump(n *Node, flag FmtFlag) string {
}
if n.List.Len() != 0 {
indent(&buf)
- fmt.Fprintf(&buf, "%v-list%v", Oconv(n.Op, 0), n.List)
+ fmt.Fprintf(&buf, "%v-list%v", n.Op, n.List)
}
if n.Rlist.Len() != 0 {
indent(&buf)
- fmt.Fprintf(&buf, "%v-rlist%v", Oconv(n.Op, 0), n.Rlist)
+ fmt.Fprintf(&buf, "%v-rlist%v", n.Op, n.Rlist)
}
- if len(n.Nbody.Slice()) != 0 {
+ if n.Nbody.Len() != 0 {
indent(&buf)
- fmt.Fprintf(&buf, "%v-body%v", Oconv(n.Op, 0), n.Nbody)
+ fmt.Fprintf(&buf, "%v-body%v", n.Op, n.Nbody)
}
}
@@ -1672,8 +1700,8 @@ func Fldconv(f *Field, flag FmtFlag) string {
// (The escape analysis tags do not apply to func vars.)
// But it must not suppress struct field tags.
// See golang.org/issue/13777 and golang.org/issue/14331.
- if flag&FmtShort == 0 && (!fmtbody || !f.Funarg) && f.Note != nil {
- str += " " + strconv.Quote(*f.Note)
+ if flag&FmtShort == 0 && (!fmtbody || !f.Funarg) && f.Note != "" {
+ str += " " + strconv.Quote(f.Note)
}
if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go
index 4a98f41bcb..275e6a7507 100644
--- a/src/cmd/compile/internal/gc/gen.go
+++ b/src/cmd/compile/internal/gc/gen.go
@@ -8,6 +8,7 @@ package gc
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"fmt"
)
@@ -217,7 +218,7 @@ func Genlist(l Nodes) {
func cgen_proc(n *Node, proc int) {
switch n.Left.Op {
default:
- Fatalf("cgen_proc: unknown call %v", Oconv(n.Left.Op, 0))
+ Fatalf("cgen_proc: unknown call %v", n.Left.Op)
case OCALLMETH:
cgen_callmeth(n.Left, proc)
@@ -245,7 +246,7 @@ func cgen_dcl(n *Node) {
if n.Class&PHEAP == 0 {
return
}
- if compiling_runtime != 0 {
+ if compiling_runtime {
Yyerror("%v escapes to heap, not allowed in runtime.", n)
}
if prealloc[n] == nil {
@@ -1030,7 +1031,7 @@ func componentgen_wb(nr, nl *Node, wb bool) bool {
// Emit vardef if needed.
if nl.Op == ONAME {
switch nl.Type.Etype {
- case TARRAY, TSTRING, TINTER, TSTRUCT:
+ case TARRAY, TSLICE, TSTRING, TINTER, TSTRUCT:
Gvardef(nl)
}
}
@@ -1174,7 +1175,7 @@ func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset i
}
// NOTE: Assuming little endian (signed top half at offset 4).
// We don't have any 32-bit big-endian systems.
- if Thearch.Thechar != '5' && Thearch.Thechar != '8' {
+ if !Thearch.LinkArch.InFamily(sys.ARM, sys.I386) {
Fatalf("unknown 32-bit architecture")
}
return f(Types[TUINT32], startOffset) &&
@@ -1203,13 +1204,12 @@ func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset i
return f(Ptrto(Types[TUINT8]), startOffset) &&
f(Types[Simtype[TUINT]], startOffset+int64(Widthptr))
- case TARRAY:
- if t.IsSlice() {
- return f(Ptrto(t.Elem()), startOffset+int64(Array_array)) &&
- f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) &&
- f(Types[Simtype[TUINT]], startOffset+int64(Array_cap))
- }
+ case TSLICE:
+ return f(Ptrto(t.Elem()), startOffset+int64(Array_array)) &&
+ f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) &&
+ f(Types[Simtype[TUINT]], startOffset+int64(Array_cap))
+ case TARRAY:
// Short-circuit [1e6]struct{}.
if t.Elem().Width == 0 {
return true
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index fdea1f2fba..f9a372dcce 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -5,8 +5,9 @@
package gc
import (
- "bytes"
+ "bufio"
"cmd/compile/internal/ssa"
+ "cmd/internal/bio"
"cmd/internal/obj"
)
@@ -16,48 +17,10 @@ const (
MaxStackVarSize = 10 * 1024 * 1024
)
-type Val struct {
- // U contains one of:
- // bool bool when n.ValCtype() == CTBOOL
- // *Mpint int when n.ValCtype() == CTINT, rune when n.ValCtype() == CTRUNE
- // *Mpflt float when n.ValCtype() == CTFLT
- // *Mpcplx pair of floats when n.ValCtype() == CTCPLX
- // string string when n.ValCtype() == CTSTR
- // *Nilval when n.ValCtype() == CTNIL
- U interface{}
-}
-
-type NilVal struct{}
-
-func (v Val) Ctype() Ctype {
- switch x := v.U.(type) {
- default:
- Fatalf("unexpected Ctype for %T", v.U)
- panic("not reached")
- case nil:
- return 0
- case *NilVal:
- return CTNIL
- case bool:
- return CTBOOL
- case *Mpint:
- if x.Rune {
- return CTRUNE
- }
- return CTINT
- case *Mpflt:
- return CTFLT
- case *Mpcplx:
- return CTCPLX
- case string:
- return CTSTR
- }
-}
-
type Pkg struct {
Name string // package name, e.g. "sys"
Path string // string literal used in import statement, e.g. "runtime/internal/sys"
- Pathsym *Sym
+ Pathsym *obj.LSym
Prefix string // escaped path for use in symbol table
Imported bool // export data of this package was parsed
Exported bool // import line written in export data
@@ -66,6 +29,14 @@ type Pkg struct {
Syms map[string]*Sym
}
+// Sym represents an object name. Most commonly, this is a Go identifier naming
+// an object declared within a package, but Syms are also used to name internal
+// synthesized objects.
+//
+// As a special exception, field and method names that are exported use the Sym
+// associated with localpkg instead of the package that declared them. This
+// allows using Sym pointer equality to test for Go identifier uniqueness when
+// handling selector expressions.
type Sym struct {
Flags SymFlags
Link *Sym
@@ -111,37 +82,6 @@ const (
SymAlgGen
)
-var dclstack *Sym
-
-// Ctype describes the constant kind of an "ideal" (untyped) constant.
-type Ctype int8
-
-const (
- CTxxx Ctype = iota
-
- CTINT
- CTRUNE
- CTFLT
- CTCPLX
- CTSTR
- CTBOOL
- CTNIL
-)
-
-// ChanDir is whether a channel can send, receive, or both.
-type ChanDir uint8
-
-func (c ChanDir) CanRecv() bool { return c&Crecv != 0 }
-func (c ChanDir) CanSend() bool { return c&Csend != 0 }
-
-const (
- // types of channel
- // must match ../../../../reflect/type.go:/ChanDir
- Crecv ChanDir = 1 << 0
- Csend ChanDir = 1 << 1
- Cboth ChanDir = Crecv | Csend
-)
-
// The Class of a variable/function describes the "storage class"
// of a variable or function. During parsing, storage classes are
// called declaration contexts.
@@ -161,30 +101,6 @@ const (
PHEAP = 1 << 7 // an extra bit to identify an escaped variable
)
-const (
- Etop = 1 << 1 // evaluated at statement level
- Erv = 1 << 2 // evaluated in value context
- Etype = 1 << 3
- Ecall = 1 << 4 // call-only expressions are ok
- Efnstruct = 1 << 5 // multivalue function returns are ok
- Eiota = 1 << 6 // iota is ok
- Easgn = 1 << 7 // assigning to expression
- Eindir = 1 << 8 // indirecting through expression
- Eaddr = 1 << 9 // taking address of expression
- Eproc = 1 << 10 // inside a go statement
- Ecomplit = 1 << 11 // type in composite literal
-)
-
-type Sig struct {
- name string
- pkg *Pkg
- isym *Sym
- tsym *Sym
- type_ *Type
- mtype *Type
- offset int32
-}
-
// note this is the runtime representation
// of the compilers arrays.
//
@@ -212,20 +128,13 @@ var sizeof_Array int // runtime sizeof(Array)
// } String;
var sizeof_String int // runtime sizeof(String)
-// lexlineno is the line number _after_ the most recently read rune.
-// In particular, it's advanced (or rewound) as newlines are read (or unread).
-var lexlineno int32
-
-// lineno is the line number at the start of the most recently lexed token.
-var lineno int32
-
var pragcgobuf string
var infile string
var outfile string
-var bout *obj.Biobuf
+var bout *bio.Writer
var nerrors int
@@ -235,13 +144,9 @@ var nsyntaxerrors int
var decldepth int32
-var safemode int
-
-var nolocalimports int
+var safemode bool
-var lexbuf bytes.Buffer
-var strbuf bytes.Buffer
-var litbuf string // LLITERAL value for use in syntax error messages
+var nolocalimports bool
var Debug [256]int
@@ -266,12 +171,13 @@ var msanpkg *Pkg // package runtime/msan
var typepkg *Pkg // fake package for runtime type info (headers)
-var typelinkpkg *Pkg // fake package for runtime type info (data)
-
var unsafepkg *Pkg // package unsafe
var trackpkg *Pkg // fake package for field tracking
+var mappkg *Pkg // fake package for map zero value
+var zerosize int64
+
var Tptr EType // either TPTR32 or TPTR64
var myimportpath string
@@ -318,8 +224,6 @@ var maxfltval [NTYPE]*Mpflt
var xtop []*Node
-var externdcl []*Node
-
var exportlist []*Node
var importlist []*Node // imported functions and methods with inlinable bodies
@@ -344,10 +248,6 @@ var Stksize int64 // stack size for current frame
var stkptrsize int64 // prefix of stack containing pointers
-var blockgen int32 // max block number
-
-var block int32 // current block number
-
var hasdefer bool // flag that curfn has defer statement
var Curfn *Node
@@ -364,21 +264,21 @@ var Funcdepth int32
var typecheckok bool
-var compiling_runtime int
+var compiling_runtime bool
var compiling_wrappers int
-var use_writebarrier int
+var use_writebarrier bool
-var pure_go int
+var pure_go bool
var flag_installsuffix string
-var flag_race int
+var flag_race bool
-var flag_msan int
+var flag_msan bool
-var flag_largemodel int
+var flag_largemodel bool
// Whether we are adding any sort of code instrumentation, such as
// when the race detector is enabled.
@@ -388,9 +288,9 @@ var debuglive int
var Ctxt *obj.Link
-var writearchive int
+var writearchive bool
-var bstdout obj.Biobuf
+var bstdout *bufio.Writer
var Nacl bool
@@ -404,34 +304,6 @@ var nodfp *Node
var Disable_checknil int
-type Flow struct {
- Prog *obj.Prog // actual instruction
- P1 *Flow // predecessors of this instruction: p1,
- P2 *Flow // and then p2 linked though p2link.
- P2link *Flow
- S1 *Flow // successors of this instruction (at most two: s1 and s2).
- S2 *Flow
- Link *Flow // next instruction in function code
-
- Active int32 // usable by client
-
- Id int32 // sequence number in flow graph
- Rpo int32 // reverse post ordering
- Loop uint16 // x5 for every loop
- Refset bool // diagnostic generated
-
- Data interface{} // for use by client
-}
-
-type Graph struct {
- Start *Flow
- Num int
-
- // After calling flowrpo, rpo lists the flow nodes in reverse postorder,
- // and each non-dead Flow node f has g->rpo[f->rpo] == f.
- Rpo []*Flow
-}
-
// interface to back end
const (
@@ -491,9 +363,8 @@ const (
)
type Arch struct {
- Thechar int
- Thestring string
- Thelinkarch *obj.LinkArch
+ LinkArch *obj.LinkArch
+
REGSP int
REGCTXT int
REGCALLX int // BX
@@ -507,23 +378,25 @@ type Arch struct {
MAXWIDTH int64
ReservedRegs []int
- AddIndex func(*Node, int64, *Node) bool // optional
- Betypeinit func()
- Bgen_float func(*Node, bool, int, *obj.Prog) // optional
- Cgen64 func(*Node, *Node) // only on 32-bit systems
- Cgenindex func(*Node, *Node, bool) *obj.Prog
- Cgen_bmul func(Op, *Node, *Node, *Node) bool
- Cgen_float func(*Node, *Node) // optional
- Cgen_hmul func(*Node, *Node, *Node)
- Cgen_shift func(Op, bool, *Node, *Node, *Node)
- Clearfat func(*Node)
- Cmp64 func(*Node, *Node, Op, int, *obj.Prog) // only on 32-bit systems
- Defframe func(*obj.Prog)
- Dodiv func(Op, *Node, *Node, *Node)
- Excise func(*Flow)
- Expandchecks func(*obj.Prog)
- Getg func(*Node)
- Gins func(obj.As, *Node, *Node) *obj.Prog
+ AddIndex func(*Node, int64, *Node) bool // optional
+ Betypeinit func()
+ Bgen_float func(*Node, bool, int, *obj.Prog) // optional
+ Cgen64 func(*Node, *Node) // only on 32-bit systems
+ Cgenindex func(*Node, *Node, bool) *obj.Prog
+ Cgen_bmul func(Op, *Node, *Node, *Node) bool
+ Cgen_float func(*Node, *Node) // optional
+ Cgen_hmul func(*Node, *Node, *Node)
+ RightShiftWithCarry func(*Node, uint, *Node) // only on systems without RROTC instruction
+ AddSetCarry func(*Node, *Node, *Node) // only on systems when ADD does not update carry flag
+ Cgen_shift func(Op, bool, *Node, *Node, *Node)
+ Clearfat func(*Node)
+ Cmp64 func(*Node, *Node, Op, int, *obj.Prog) // only on 32-bit systems
+ Defframe func(*obj.Prog)
+ Dodiv func(Op, *Node, *Node, *Node)
+ Excise func(*Flow)
+ Expandchecks func(*obj.Prog)
+ Getg func(*Node)
+ Gins func(obj.As, *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.
diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
index 353d90f593..7e64194957 100644
--- a/src/cmd/compile/internal/gc/gsubr.go
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -32,6 +32,7 @@ package gc
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"fmt"
"runtime"
"strings"
@@ -57,7 +58,9 @@ func Ismem(n *Node) bool {
return true
case OADDR:
- return Thearch.Thechar == '6' || Thearch.Thechar == '9' // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too
+ // amd64 and s390x use PC relative addressing.
+ // TODO(rsc): not sure why ppc64 needs this too.
+ return Thearch.LinkArch.InFamily(sys.AMD64, sys.PPC64, sys.S390X)
}
return false
@@ -83,7 +86,7 @@ func Gbranch(as obj.As, t *Type, likely int) *obj.Prog {
p := Prog(as)
p.To.Type = obj.TYPE_BRANCH
p.To.Val = nil
- if as != obj.AJMP && likely != 0 && Thearch.Thechar != '9' && Thearch.Thechar != '7' && Thearch.Thechar != '0' {
+ if as != obj.AJMP && likely != 0 && !Thearch.LinkArch.InFamily(sys.PPC64, sys.ARM64, sys.MIPS64, sys.S390X) {
p.From.Type = obj.TYPE_CONST
if likely > 0 {
p.From.Offset = 1
@@ -274,7 +277,7 @@ func gused(n *Node) {
func Isfat(t *Type) bool {
if t != nil {
switch t.Etype {
- case TSTRUCT, TARRAY, TSTRING,
+ case TSTRUCT, TARRAY, TSLICE, TSTRING,
TINTER: // maybe remove later
return true
}
@@ -324,13 +327,13 @@ func Naddr(a *obj.Addr, n *Node) {
a := a // copy to let escape into Ctxt.Dconv
Debug['h'] = 1
Dump("naddr", n)
- Fatalf("naddr: bad %v %v", Oconv(n.Op, 0), Ctxt.Dconv(a))
+ Fatalf("naddr: bad %v %v", n.Op, Ctxt.Dconv(a))
case OREGISTER:
a.Type = obj.TYPE_REG
a.Reg = n.Reg
a.Sym = nil
- if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width.
+ if Thearch.LinkArch.Family == sys.I386 { // TODO(rsc): Never clear a->width.
a.Width = 0
}
@@ -342,7 +345,7 @@ func Naddr(a *obj.Addr, n *Node) {
if a.Offset != int64(int32(a.Offset)) {
Yyerror("offset %d too large for OINDREG", a.Offset)
}
- if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width.
+ if Thearch.LinkArch.Family == sys.I386 { // TODO(rsc): Never clear a->width.
a.Width = 0
}
@@ -419,36 +422,36 @@ func Naddr(a *obj.Addr, n *Node) {
if !n.Left.Type.IsStruct() || n.Left.Type.Field(0).Sym != n.Sym {
Debug['h'] = 1
Dump("naddr", n)
- Fatalf("naddr: bad %v %v", Oconv(n.Op, 0), Ctxt.Dconv(a))
+ Fatalf("naddr: bad %v %v", n.Op, Ctxt.Dconv(a))
}
Naddr(a, n.Left)
case OLITERAL:
- if Thearch.Thechar == '8' {
+ if Thearch.LinkArch.Family == sys.I386 {
a.Width = 0
}
- switch n.Val().Ctype() {
+ switch u := n.Val().U.(type) {
default:
Fatalf("naddr: const %v", Tconv(n.Type, FmtLong))
- case CTFLT:
+ case *Mpflt:
a.Type = obj.TYPE_FCONST
- a.Val = n.Val().U.(*Mpflt).Float64()
+ a.Val = u.Float64()
- case CTINT, CTRUNE:
+ case *Mpint:
a.Sym = nil
a.Type = obj.TYPE_CONST
- a.Offset = n.Int64()
+ a.Offset = u.Int64()
- case CTSTR:
- datagostring(n.Val().U.(string), a)
+ case string:
+ datagostring(u, a)
- case CTBOOL:
+ case bool:
a.Sym = nil
a.Type = obj.TYPE_CONST
- a.Offset = int64(obj.Bool2int(n.Val().U.(bool)))
+ a.Offset = int64(obj.Bool2int(u))
- case CTNIL:
+ case *NilVal:
a.Sym = nil
a.Type = obj.TYPE_CONST
a.Offset = 0
@@ -457,12 +460,12 @@ func Naddr(a *obj.Addr, n *Node) {
case OADDR:
Naddr(a, n.Left)
a.Etype = uint8(Tptr)
- if Thearch.Thechar != '0' && Thearch.Thechar != '5' && Thearch.Thechar != '7' && Thearch.Thechar != '9' { // TODO(rsc): Do this even for arm, ppc64.
+ if !Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) { // TODO(rsc): Do this even for these architectures.
a.Width = int64(Widthptr)
}
if a.Type != obj.TYPE_MEM {
a := a // copy to let escape into Ctxt.Dconv
- Fatalf("naddr: OADDR %v (from %v)", Ctxt.Dconv(a), Oconv(n.Left.Op, 0))
+ Fatalf("naddr: OADDR %v (from %v)", Ctxt.Dconv(a), n.Left.Op)
}
a.Type = obj.TYPE_ADDR
@@ -496,7 +499,7 @@ func Naddr(a *obj.Addr, n *Node) {
}
a.Etype = uint8(Simtype[TUINT])
a.Offset += int64(Array_nel)
- if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm.
+ if Thearch.LinkArch.Family != sys.ARM { // TODO(rsc): Do this even on arm.
a.Width = int64(Widthint)
}
@@ -509,7 +512,7 @@ func Naddr(a *obj.Addr, n *Node) {
}
a.Etype = uint8(Simtype[TUINT])
a.Offset += int64(Array_cap)
- if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm.
+ if Thearch.LinkArch.Family != sys.ARM { // TODO(rsc): Do this even on arm.
a.Width = int64(Widthint)
}
}
@@ -541,7 +544,7 @@ func nodarg(t interface{}, fp int) *Node {
switch t := t.(type) {
case *Type:
// entire argument struct, not just one arg
- if !t.IsStruct() || !t.Funarg {
+ if !t.IsFuncArgStruct() {
Fatalf("nodarg: bad type %v", t)
}
n = Nod(ONAME, nil, nil)
@@ -695,7 +698,7 @@ func Regalloc(n *Node, t *Type, o *Node) {
Fatalf("regalloc: t nil")
}
et := Simtype[t.Etype]
- if Ctxt.Arch.Regsize == 4 && (et == TINT64 || et == TUINT64) {
+ if Ctxt.Arch.RegSize == 4 && (et == TINT64 || et == TUINT64) {
Fatalf("regalloc 64bit")
}
diff --git a/src/cmd/compile/internal/gc/init.go b/src/cmd/compile/internal/gc/init.go
index d355a46557..6c9223b57a 100644
--- a/src/cmd/compile/internal/gc/init.go
+++ b/src/cmd/compile/internal/gc/init.go
@@ -58,8 +58,6 @@ func anyinit(n []*Node) bool {
break
}
fallthrough
-
- // fall through
default:
return true
}
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index ea2394e7f9..10b61377ca 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -71,7 +71,7 @@ func typecheckinl(fn *Node) {
}
save_safemode := safemode
- safemode = 0
+ safemode = false
savefn := Curfn
Curfn = fn
@@ -100,7 +100,7 @@ func caninl(fn *Node) {
}
// If fn has no body (is defined outside of Go), cannot inline it.
- if len(fn.Nbody.Slice()) == 0 {
+ if fn.Nbody.Len() == 0 {
return
}
@@ -110,8 +110,9 @@ func caninl(fn *Node) {
// can't handle ... args yet
if Debug['l'] < 3 {
- for _, t := range fn.Type.Params().Fields().Slice() {
- if t.Isddd {
+ f := fn.Type.Params().Fields()
+ if len := f.Len(); len > 0 {
+ if t := f.Index(len - 1); t.Isddd {
return
}
}
@@ -128,7 +129,7 @@ func caninl(fn *Node) {
}
const maxBudget = 80
- budget := maxBudget // allowed hairyness
+ budget := int32(maxBudget) // allowed hairyness
if ishairylist(fn.Nbody, &budget) || budget < 0 {
return
}
@@ -136,27 +137,29 @@ func caninl(fn *Node) {
savefn := Curfn
Curfn = fn
- fn.Func.Nname.Func.Inl.Set(fn.Nbody.Slice())
- fn.Nbody.Set(inlcopylist(fn.Func.Nname.Func.Inl.Slice()))
- inldcl := inlcopylist(fn.Func.Nname.Name.Defn.Func.Dcl)
- fn.Func.Nname.Func.Inldcl.Set(inldcl)
- fn.Func.Nname.Func.InlCost = int32(maxBudget - budget)
+ n := fn.Func.Nname
+
+ n.Func.Inl.Set(fn.Nbody.Slice())
+ fn.Nbody.Set(inlcopylist(n.Func.Inl.Slice()))
+ inldcl := inlcopylist(n.Name.Defn.Func.Dcl)
+ n.Func.Inldcl.Set(inldcl)
+ n.Func.InlCost = maxBudget - budget
// hack, TODO, check for better way to link method nodes back to the thing with the ->inl
// this is so export can find the body of a method
- fn.Type.SetNname(fn.Func.Nname)
+ fn.Type.SetNname(n)
if Debug['m'] > 1 {
- fmt.Printf("%v: can inline %v as: %v { %v }\n", fn.Line(), Nconv(fn.Func.Nname, FmtSharp), Tconv(fn.Type, FmtSharp), Hconv(fn.Func.Nname.Func.Inl, FmtSharp))
+ fmt.Printf("%v: can inline %v as: %v { %v }\n", fn.Line(), Nconv(n, FmtSharp), Tconv(fn.Type, FmtSharp), Hconv(n.Func.Inl, FmtSharp))
} else if Debug['m'] != 0 {
- fmt.Printf("%v: can inline %v\n", fn.Line(), fn.Func.Nname)
+ fmt.Printf("%v: can inline %v\n", fn.Line(), n)
}
Curfn = savefn
}
// Look for anything we want to punt on.
-func ishairylist(ll Nodes, budget *int) bool {
+func ishairylist(ll Nodes, budget *int32) bool {
for _, n := range ll.Slice() {
if ishairy(n, budget) {
return true
@@ -165,7 +168,7 @@ func ishairylist(ll Nodes, budget *int) bool {
return false
}
-func ishairy(n *Node, budget *int) bool {
+func ishairy(n *Node, budget *int32) bool {
if n == nil {
return false
}
@@ -173,13 +176,13 @@ func ishairy(n *Node, budget *int) bool {
switch n.Op {
// Call is okay if inlinable and we have the budget for the body.
case OCALLFUNC:
- if n.Left.Func != nil && len(n.Left.Func.Inl.Slice()) != 0 {
- *budget -= int(n.Left.Func.InlCost)
+ if fn := n.Left.Func; fn != nil && fn.Inl.Len() != 0 {
+ *budget -= fn.InlCost
break
}
if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
- if n.Left.Sym.Def != nil && len(n.Left.Sym.Def.Func.Inl.Slice()) != 0 {
- *budget -= int(n.Left.Sym.Def.Func.InlCost)
+ if d := n.Left.Sym.Def; d != nil && d.Func.Inl.Len() != 0 {
+ *budget -= d.Func.InlCost
break
}
}
@@ -189,14 +192,15 @@ func ishairy(n *Node, budget *int) bool {
// Call is okay if inlinable and we have the budget for the body.
case OCALLMETH:
- if n.Left.Type == nil {
+ t := n.Left.Type
+ if t == nil {
Fatalf("no function type for [%p] %v\n", n.Left, Nconv(n.Left, FmtSign))
}
- if n.Left.Type.Nname() == nil {
- Fatalf("no function definition for [%p] %v\n", n.Left.Type, Tconv(n.Left.Type, FmtSign))
+ if t.Nname() == nil {
+ Fatalf("no function definition for [%p] %v\n", t, Tconv(t, FmtSign))
}
- if len(n.Left.Type.Nname().Func.Inl.Slice()) != 0 {
- *budget -= int(n.Left.Type.Nname().Func.InlCost)
+ if inlfn := t.Nname().Func; inlfn.Inl.Len() != 0 {
+ *budget -= inlfn.InlCost
break
}
if Debug['l'] < 4 {
@@ -453,7 +457,7 @@ func inlnode(n *Node) *Node {
if Debug['m'] > 3 {
fmt.Printf("%v:call to func %v\n", n.Line(), Nconv(n.Left, FmtSign))
}
- if n.Left.Func != nil && len(n.Left.Func.Inl.Slice()) != 0 && !isIntrinsicCall1(n) { // normal case
+ if n.Left.Func != nil && n.Left.Func.Inl.Len() != 0 && !isIntrinsicCall1(n) { // normal case
n = mkinlcall(n, n.Left, n.Isddd)
} else if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
if n.Left.Sym.Def != nil {
@@ -492,7 +496,7 @@ func mkinlcall(n *Node, fn *Node, isddd bool) *Node {
pkg := fnpkg(fn)
if pkg != localpkg && pkg != nil {
- safemode = 0
+ safemode = false
}
n = mkinlcall1(n, fn, isddd)
safemode = save_safemode
@@ -520,7 +524,7 @@ var inlgen int
// n.Left = mkinlcall1(n.Left, fn, isddd)
func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
// For variadic fn.
- if len(fn.Func.Inl.Slice()) == 0 {
+ if fn.Func.Inl.Len() == 0 {
return n
}
@@ -750,7 +754,7 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
vararrtype := typArray(varargtype.Elem(), int64(varargcount))
as.Right = Nod(OCOMPLIT, nil, typenod(vararrtype))
as.Right.List.Set(varargs)
- as.Right = Nod(OSLICE, as.Right, Nod(OKEY, nil, nil))
+ as.Right = Nod(OSLICE, as.Right, nil)
}
as = typecheck(as, Etop)
diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go
index 6f1331ca89..8608a6229c 100644
--- a/src/cmd/compile/internal/gc/lex.go
+++ b/src/cmd/compile/internal/gc/lex.go
@@ -6,6 +6,7 @@ package gc
import (
"bufio"
+ "bytes"
"cmd/internal/obj"
"fmt"
"io"
@@ -20,6 +21,17 @@ const (
BOM = 0xFEFF
)
+// lexlineno is the line number _after_ the most recently read rune.
+// In particular, it's advanced (or rewound) as newlines are read (or unread).
+var lexlineno int32
+
+// lineno is the line number at the start of the most recently lexed token.
+var lineno int32
+
+var lexbuf bytes.Buffer
+var strbuf bytes.Buffer
+var litbuf string // LLITERAL value for use in syntax error messages
+
func isSpace(c rune) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
}
@@ -32,6 +44,10 @@ func isDigit(c rune) bool {
return '0' <= c && c <= '9'
}
+func isQuoted(s string) bool {
+ return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"'
+}
+
func plan9quote(s string) string {
if s == "" {
return "''"
@@ -739,7 +755,7 @@ func (l *lexer) number(c rune) {
}
done:
- litbuf = "literal " + str
+ litbuf = "" // lazily initialized in (*parser).syntax_error
l.nlsemi = true
l.tok = LLITERAL
}
@@ -841,15 +857,6 @@ func internString(b []byte) string {
return s
}
-func more(pp *string) bool {
- p := *pp
- for p != "" && isSpace(rune(p[0])) {
- p = p[1:]
- }
- *pp = p
- return p != ""
-}
-
// read and interpret syntax that looks like
// //line parse.y:15
// as a discontinuity in sequential line numbers.
@@ -875,7 +882,7 @@ func (l *lexer) getlinepragma() rune {
text := strings.TrimSuffix(lexbuf.String(), "\r")
if strings.HasPrefix(text, "go:cgo_") {
- pragcgo(text)
+ pragcgobuf += pragcgo(text)
}
verb := text
@@ -907,17 +914,17 @@ func (l *lexer) getlinepragma() rune {
case "go:noinline":
l.pragma |= Noinline
case "go:systemstack":
- if compiling_runtime == 0 {
+ if !compiling_runtime {
Yyerror("//go:systemstack only allowed in runtime")
}
l.pragma |= Systemstack
case "go:nowritebarrier":
- if compiling_runtime == 0 {
+ if !compiling_runtime {
Yyerror("//go:nowritebarrier only allowed in runtime")
}
l.pragma |= Nowritebarrier
case "go:nowritebarrierrec":
- if compiling_runtime == 0 {
+ if !compiling_runtime {
Yyerror("//go:nowritebarrierrec only allowed in runtime")
}
l.pragma |= Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
@@ -979,139 +986,114 @@ func (l *lexer) getlinepragma() rune {
return c
}
-func getimpsym(pp *string) string {
- more(pp) // skip spaces
- p := *pp
- if p == "" || p[0] == '"' {
- return ""
- }
- i := 0
- for i < len(p) && !isSpace(rune(p[i])) && p[i] != '"' {
- i++
- }
- sym := p[:i]
- *pp = p[i:]
- return sym
-}
+func pragcgo(text string) string {
+ f := pragmaFields(text)
-func getquoted(pp *string) (string, bool) {
- more(pp) // skip spaces
- p := *pp
- if p == "" || p[0] != '"' {
- return "", false
- }
- p = p[1:]
- i := strings.Index(p, `"`)
- if i < 0 {
- return "", false
- }
- *pp = p[i+1:]
- return p[:i], true
-}
+ verb := f[0][3:] // skip "go:"
+ switch verb {
+ case "cgo_export_static", "cgo_export_dynamic":
+ switch {
+ case len(f) == 2 && !isQuoted(f[1]):
+ local := plan9quote(f[1])
+ return fmt.Sprintln(verb, local)
-// Copied nearly verbatim from the C compiler's #pragma parser.
-// TODO: Rewrite more cleanly once the compiler is written in Go.
-func pragcgo(text string) {
- var q string
+ case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]):
+ local := plan9quote(f[1])
+ remote := plan9quote(f[2])
+ return fmt.Sprintln(verb, local, remote)
- if i := strings.Index(text, " "); i >= 0 {
- text, q = text[:i], text[i:]
- }
-
- verb := text[3:] // skip "go:"
-
- if verb == "cgo_dynamic_linker" || verb == "dynlinker" {
- p, ok := getquoted(&q)
- if !ok {
- Yyerror("usage: //go:cgo_dynamic_linker \"path\"")
- return
+ default:
+ Yyerror(`usage: //go:%s local [remote]`, verb)
}
- pragcgobuf += fmt.Sprintf("cgo_dynamic_linker %v\n", plan9quote(p))
- return
+ case "cgo_import_dynamic":
+ switch {
+ case len(f) == 2 && !isQuoted(f[1]):
+ local := plan9quote(f[1])
+ return fmt.Sprintln(verb, local)
- }
+ case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]):
+ local := plan9quote(f[1])
+ remote := plan9quote(f[2])
+ return fmt.Sprintln(verb, local, remote)
- if verb == "dynexport" {
- verb = "cgo_export_dynamic"
- }
- if verb == "cgo_export_static" || verb == "cgo_export_dynamic" {
- local := getimpsym(&q)
- var remote string
- if local == "" {
- goto err2
- }
- if !more(&q) {
- pragcgobuf += fmt.Sprintf("%s %v\n", verb, plan9quote(local))
- return
- }
+ case len(f) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]):
+ local := plan9quote(f[1])
+ remote := plan9quote(f[2])
+ library := plan9quote(strings.Trim(f[3], `"`))
+ return fmt.Sprintln(verb, local, remote, library)
- remote = getimpsym(&q)
- if remote == "" {
- goto err2
+ default:
+ Yyerror(`usage: //go:cgo_import_dynamic local [remote ["library"]]`)
}
- pragcgobuf += fmt.Sprintf("%s %v %v\n", verb, plan9quote(local), plan9quote(remote))
- return
-
- err2:
- Yyerror("usage: //go:%s local [remote]", verb)
- return
- }
+ case "cgo_import_static":
+ switch {
+ case len(f) == 2 && !isQuoted(f[1]):
+ local := plan9quote(f[1])
+ return fmt.Sprintln(verb, local)
- if verb == "cgo_import_dynamic" || verb == "dynimport" {
- var ok bool
- local := getimpsym(&q)
- var p string
- var remote string
- if local == "" {
- goto err3
- }
- if !more(&q) {
- pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v\n", plan9quote(local))
- return
+ default:
+ Yyerror(`usage: //go:cgo_import_static local`)
}
+ case "cgo_dynamic_linker":
+ switch {
+ case len(f) == 2 && isQuoted(f[1]):
+ path := plan9quote(strings.Trim(f[1], `"`))
+ return fmt.Sprintln(verb, path)
- remote = getimpsym(&q)
- if remote == "" {
- goto err3
- }
- if !more(&q) {
- pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v %v\n", plan9quote(local), plan9quote(remote))
- return
+ default:
+ Yyerror(`usage: //go:cgo_dynamic_linker "path"`)
}
+ case "cgo_ldflag":
+ switch {
+ case len(f) == 2 && isQuoted(f[1]):
+ arg := plan9quote(strings.Trim(f[1], `"`))
+ return fmt.Sprintln(verb, arg)
- p, ok = getquoted(&q)
- if !ok {
- goto err3
+ default:
+ Yyerror(`usage: //go:cgo_ldflag "arg"`)
}
- pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v %v %v\n", plan9quote(local), plan9quote(remote), plan9quote(p))
- return
-
- err3:
- Yyerror("usage: //go:cgo_import_dynamic local [remote [\"library\"]]")
- return
}
+ return ""
+}
- if verb == "cgo_import_static" {
- local := getimpsym(&q)
- if local == "" || more(&q) {
- Yyerror("usage: //go:cgo_import_static local")
- return
+// pragmaFields is similar to strings.FieldsFunc(s, isSpace)
+// but does not split when inside double quoted regions and always
+// splits before the start and after the end of a double quoted region.
+// pragmaFields does not recognize escaped quotes. If a quote in s is not
+// closed the part after the opening quote will not be returned as a field.
+func pragmaFields(s string) []string {
+ var a []string
+ inQuote := false
+ fieldStart := -1 // Set to -1 when looking for start of field.
+ for i, c := range s {
+ switch {
+ case c == '"':
+ if inQuote {
+ inQuote = false
+ a = append(a, s[fieldStart:i+1])
+ fieldStart = -1
+ } else {
+ inQuote = true
+ if fieldStart >= 0 {
+ a = append(a, s[fieldStart:i])
+ }
+ fieldStart = i
+ }
+ case !inQuote && isSpace(c):
+ if fieldStart >= 0 {
+ a = append(a, s[fieldStart:i])
+ fieldStart = -1
+ }
+ default:
+ if fieldStart == -1 {
+ fieldStart = i
+ }
}
- pragcgobuf += fmt.Sprintf("cgo_import_static %v\n", plan9quote(local))
- return
-
}
-
- if verb == "cgo_ldflag" {
- p, ok := getquoted(&q)
- if !ok {
- Yyerror("usage: //go:cgo_ldflag \"arg\"")
- return
- }
- pragcgobuf += fmt.Sprintf("cgo_ldflag %v\n", plan9quote(p))
- return
-
+ if !inQuote && fieldStart >= 0 { // Last field might end at the end of the string.
+ a = append(a, s[fieldStart:])
}
+ return a
}
func (l *lexer) getr() rune {
diff --git a/src/cmd/compile/internal/gc/lex_test.go b/src/cmd/compile/internal/gc/lex_test.go
new file mode 100644
index 0000000000..9230b30dad
--- /dev/null
+++ b/src/cmd/compile/internal/gc/lex_test.go
@@ -0,0 +1,79 @@
+// Copyright 2016 The Go 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 gc
+
+import "testing"
+
+func eq(a, b []string) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := 0; i < len(a); i++ {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func TestPragmaFields(t *testing.T) {
+
+ var tests = []struct {
+ in string
+ want []string
+ }{
+ {"", []string{}},
+ {" \t ", []string{}},
+ {`""""`, []string{`""`, `""`}},
+ {" a'b'c ", []string{"a'b'c"}},
+ {"1 2 3 4", []string{"1", "2", "3", "4"}},
+ {"\n☺\t☹\n", []string{"☺", "☹"}},
+ {`"1 2 " 3 " 4 5"`, []string{`"1 2 "`, `3`, `" 4 5"`}},
+ {`"1""2 3""4"`, []string{`"1"`, `"2 3"`, `"4"`}},
+ {`12"34"`, []string{`12`, `"34"`}},
+ {`12"34 `, []string{`12`}},
+ }
+
+ for _, tt := range tests {
+ got := pragmaFields(tt.in)
+ if !eq(got, tt.want) {
+ t.Errorf("pragmaFields(%q) = %v; want %v", tt.in, got, tt.want)
+ continue
+ }
+ }
+}
+
+func TestPragcgo(t *testing.T) {
+
+ var tests = []struct {
+ in string
+ want string
+ }{
+ {`go:cgo_export_dynamic local`, "cgo_export_dynamic local\n"},
+ {`go:cgo_export_dynamic local remote`, "cgo_export_dynamic local remote\n"},
+ {`go:cgo_export_dynamic local' remote'`, "cgo_export_dynamic 'local''' 'remote'''\n"},
+ {`go:cgo_export_static local`, "cgo_export_static local\n"},
+ {`go:cgo_export_static local remote`, "cgo_export_static local remote\n"},
+ {`go:cgo_export_static local' remote'`, "cgo_export_static 'local''' 'remote'''\n"},
+ {`go:cgo_import_dynamic local`, "cgo_import_dynamic local\n"},
+ {`go:cgo_import_dynamic local remote`, "cgo_import_dynamic local remote\n"},
+ {`go:cgo_import_dynamic local remote "library"`, "cgo_import_dynamic local remote library\n"},
+ {`go:cgo_import_dynamic local' remote' "lib rary"`, "cgo_import_dynamic 'local''' 'remote''' 'lib rary'\n"},
+ {`go:cgo_import_static local`, "cgo_import_static local\n"},
+ {`go:cgo_import_static local'`, "cgo_import_static 'local'''\n"},
+ {`go:cgo_dynamic_linker "/path/"`, "cgo_dynamic_linker /path/\n"},
+ {`go:cgo_dynamic_linker "/p ath/"`, "cgo_dynamic_linker '/p ath/'\n"},
+ {`go:cgo_ldflag "arg"`, "cgo_ldflag arg\n"},
+ {`go:cgo_ldflag "a rg"`, "cgo_ldflag 'a rg'\n"},
+ }
+
+ for _, tt := range tests {
+ got := pragcgo(tt.in)
+ if got != tt.want {
+ t.Errorf("pragcgo(%q) = %q; want %q", tt.in, got, tt.want)
+ continue
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 73ecb09fa5..54211e4892 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -10,6 +10,7 @@ import (
"bufio"
"cmd/compile/internal/ssa"
"cmd/internal/obj"
+ "cmd/internal/sys"
"flag"
"fmt"
"io"
@@ -89,22 +90,21 @@ func doversion() {
os.Exit(0)
}
+// supportsDynlink reports whether or not the code generator for the given
+// architecture supports the -shared and -dynlink flags.
+func supportsDynlink(arch *sys.Arch) bool {
+ return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X)
+}
+
func Main() {
defer hidePanic()
- // Allow GOARCH=thearch.thestring or GOARCH=thearch.thestringsuffix,
- // but not other values.
- p := obj.Getgoarch()
-
- if !strings.HasPrefix(p, Thearch.Thestring) {
- log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.Thechar, p)
- }
- goarch = p
+ goarch = obj.Getgoarch()
- Ctxt = obj.Linknew(Thearch.Thelinkarch)
+ Ctxt = obj.Linknew(Thearch.LinkArch)
Ctxt.DiagFunc = Yyerror
- Ctxt.Bso = &bstdout
- bstdout = *obj.Binitw(os.Stdout)
+ bstdout = bufio.NewWriter(os.Stdout)
+ Ctxt.Bso = bstdout
localpkg = mkpkg("")
localpkg.Prefix = "\"\""
@@ -126,10 +126,6 @@ func Main() {
itabpkg.Name = "go.itab"
itabpkg.Prefix = "go.itab" // not go%2eitab
- typelinkpkg = mkpkg("go.typelink")
- typelinkpkg.Name = "go.typelink"
- typelinkpkg.Prefix = "go.typelink" // not go%2etypelink
-
itablinkpkg = mkpkg("go.itablink")
itablinkpkg.Name = "go.itablink"
itablinkpkg.Prefix = "go.itablink" // not go%2eitablink
@@ -141,24 +137,27 @@ func Main() {
typepkg = mkpkg("type")
typepkg.Name = "type"
+ // pseudo-package used for map zero values
+ mappkg = mkpkg("go.map")
+ mappkg.Name = "go.map"
+ mappkg.Prefix = "go.map"
+
goroot = obj.Getgoroot()
goos = obj.Getgoos()
Nacl = goos == "nacl"
if Nacl {
- flag_largemodel = 1
+ flag_largemodel = true
}
- outfile = ""
- obj.Flagcount("+", "compiling runtime", &compiling_runtime)
+ flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
obj.Flagcount("%", "debug non-static initializers", &Debug['%'])
obj.Flagcount("A", "for bootstrapping, allow 'any' type", &Debug['A'])
obj.Flagcount("B", "disable bounds checking", &Debug['B'])
- obj.Flagstr("D", "set relative `path` for local imports", &localimport)
+ flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
obj.Flagcount("E", "debug symbol export", &Debug['E'])
obj.Flagfn1("I", "add `directory` to import search path", addidir)
obj.Flagcount("K", "debug missing line numbers", &Debug['K'])
- obj.Flagcount("L", "use full (long) path in error messages", &Debug['L'])
obj.Flagcount("M", "debug move generation", &Debug['M'])
obj.Flagcount("N", "disable optimizations", &Debug['N'])
obj.Flagcount("P", "debug peephole optimizer", &Debug['P'])
@@ -166,61 +165,52 @@ func Main() {
obj.Flagcount("S", "print assembly listing", &Debug['S'])
obj.Flagfn0("V", "print compiler version", doversion)
obj.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
- obj.Flagstr("asmhdr", "write assembly header to `file`", &asmhdr)
- obj.Flagstr("buildid", "record `id` as the build id in the export metadata", &buildid)
- obj.Flagcount("complete", "compiling complete package (no C or assembly)", &pure_go)
- obj.Flagstr("d", "print debug information about items in `list`", &debugstr)
+ flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`")
+ flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata")
+ flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)")
+ flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`")
obj.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
obj.Flagcount("f", "debug stack frames", &Debug['f'])
obj.Flagcount("g", "debug code generation", &Debug['g'])
obj.Flagcount("h", "halt on error", &Debug['h'])
obj.Flagcount("i", "debug line number stack", &Debug['i'])
obj.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
- obj.Flagstr("installsuffix", "set pkg directory `suffix`", &flag_installsuffix)
+ flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
obj.Flagcount("l", "disable inlining", &Debug['l'])
obj.Flagcount("live", "debug liveness analysis", &debuglive)
obj.Flagcount("m", "print optimization decisions", &Debug['m'])
- obj.Flagcount("msan", "build code compatible with C/C++ memory sanitizer", &flag_msan)
- obj.Flagcount("newexport", "use new export format", &newexport) // TODO(gri) remove eventually (issue 13241)
- obj.Flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports)
- obj.Flagstr("o", "write output to `file`", &outfile)
- obj.Flagstr("p", "set expected package import `path`", &myimportpath)
- obj.Flagcount("pack", "write package file instead of object file", &writearchive)
+ flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
+ flag.BoolVar(&newexport, "newexport", true, "use new export format") // TODO(gri) remove eventually (issue 15323)
+ flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports")
+ flag.StringVar(&outfile, "o", "", "write output to `file`")
+ flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
+ flag.BoolVar(&writearchive, "pack", false, "write package file instead of object file")
obj.Flagcount("r", "debug generated wrappers", &Debug['r'])
- obj.Flagcount("race", "enable race detector", &flag_race)
+ flag.BoolVar(&flag_race, "race", false, "enable race detector")
obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
- obj.Flagstr("trimpath", "remove `prefix` from recorded source file paths", &Ctxt.LineHist.TrimPathPrefix)
- obj.Flagcount("u", "reject unsafe code", &safemode)
+ flag.StringVar(&Ctxt.LineHist.TrimPathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
+ flag.BoolVar(&safemode, "u", false, "reject unsafe code")
obj.Flagcount("v", "increase debug verbosity", &Debug['v'])
obj.Flagcount("w", "debug type checking", &Debug['w'])
- use_writebarrier = 1
- obj.Flagcount("wb", "enable write barrier", &use_writebarrier)
+ flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
obj.Flagcount("x", "debug lexer", &Debug['x'])
- obj.Flagcount("y", "debug declarations in canned imports (with -d)", &Debug['y'])
- var flag_shared int
+ var flag_shared bool
var flag_dynlink bool
- switch Thearch.Thechar {
- case '5', '6', '7', '8', '9':
- obj.Flagcount("shared", "generate code that can be linked into a shared library", &flag_shared)
- }
- if Thearch.Thechar == '6' {
- obj.Flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel)
- }
- switch Thearch.Thechar {
- case '5', '6', '7', '8', '9':
+ if supportsDynlink(Thearch.LinkArch.Arch) {
+ flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library")
flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
}
- obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile)
- obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile)
- obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate)
+ if Thearch.LinkArch.Family == sys.AMD64 {
+ flag.BoolVar(&flag_largemodel, "largemodel", false, "generate code that assumes a large memory model")
+ }
+ flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
+ flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
+ flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
flag.BoolVar(&ssaEnabled, "ssa", true, "use SSA backend to generate code")
obj.Flagparse(usage)
- if flag_dynlink {
- flag_shared = 1
- }
- Ctxt.Flag_shared = int32(flag_shared)
+ Ctxt.Flag_shared = flag_dynlink || flag_shared
Ctxt.Flag_dynlink = flag_dynlink
Ctxt.Flag_optimize = Debug['N'] == 0
@@ -233,17 +223,17 @@ func Main() {
startProfile()
- if flag_race != 0 {
+ if flag_race {
racepkg = mkpkg("runtime/race")
racepkg.Name = "race"
}
- if flag_msan != 0 {
+ if flag_msan {
msanpkg = mkpkg("runtime/msan")
msanpkg.Name = "msan"
}
- if flag_race != 0 && flag_msan != 0 {
+ if flag_race && flag_msan {
log.Fatal("cannot use both -race and -msan")
- } else if flag_race != 0 || flag_msan != 0 {
+ } else if flag_race || flag_msan {
instrumenting = true
}
@@ -301,9 +291,9 @@ func Main() {
}
Thearch.Betypeinit()
- if Widthptr == 0 {
- Fatalf("betypeinit failed")
- }
+ Widthint = Thearch.LinkArch.IntSize
+ Widthptr = Thearch.LinkArch.PtrSize
+ Widthreg = Thearch.LinkArch.RegSize
initUniverse()
@@ -422,7 +412,7 @@ func Main() {
// Typecheck imported function bodies if debug['l'] > 1,
// otherwise lazily when used or re-exported.
for _, n := range importlist {
- if len(n.Func.Inl.Slice()) != 0 {
+ if n.Func.Inl.Len() != 0 {
saveerrors()
typecheckinl(n)
}
@@ -479,7 +469,7 @@ func Main() {
fninit(xtop)
}
- if compiling_runtime != 0 {
+ if compiling_runtime {
checknowritebarrierrec()
}
@@ -577,7 +567,7 @@ func islocalname(name string) bool {
func findpkg(name string) (file string, ok bool) {
if islocalname(name) {
- if safemode != 0 || nolocalimports != 0 {
+ if safemode || nolocalimports {
return "", false
}
@@ -620,10 +610,10 @@ func findpkg(name string) (file string, ok bool) {
if flag_installsuffix != "" {
suffixsep = "_"
suffix = flag_installsuffix
- } else if flag_race != 0 {
+ } else if flag_race {
suffixsep = "_"
suffix = "race"
- } else if flag_msan != 0 {
+ } else if flag_msan {
suffixsep = "_"
suffix = "msan"
}
@@ -653,11 +643,24 @@ func loadsys() {
iota_ = -1000000
incannedimport = 1
- importpkg = Runtimepkg
- parse_import(bufio.NewReader(strings.NewReader(runtimeimport)), nil)
-
- importpkg = unsafepkg
- parse_import(bufio.NewReader(strings.NewReader(unsafeimport)), nil)
+ // The first byte in the binary export format is a 'c' or 'd'
+ // specifying the encoding format. We could just check that
+ // byte, but this is a perhaps more robust. Also, it is not
+ // speed-critical.
+ // TODO(gri) simplify once textual export format has gone
+ if strings.HasPrefix(runtimeimport, "package") {
+ // textual export format
+ importpkg = Runtimepkg
+ parse_import(bufio.NewReader(strings.NewReader(runtimeimport)), nil)
+ importpkg = unsafepkg
+ parse_import(bufio.NewReader(strings.NewReader(unsafeimport)), nil)
+ } else {
+ // binary export format
+ importpkg = Runtimepkg
+ Import(bufio.NewReader(strings.NewReader(runtimeimport)))
+ importpkg = unsafepkg
+ Import(bufio.NewReader(strings.NewReader(unsafeimport)))
+ }
importpkg = nil
incannedimport = 0
@@ -702,7 +705,7 @@ func importfile(f *Val, indent []byte) {
}
if path_ == "unsafe" {
- if safemode != 0 {
+ if safemode {
Yyerror("cannot import package unsafe")
errorexit()
}
@@ -826,7 +829,7 @@ func importfile(f *Val, indent []byte) {
errorexit()
}
- if safemode != 0 && !importpkg.Safe {
+ if safemode && !importpkg.Safe {
Yyerror("cannot import unsafe package %q", importpkg.Path)
}
}
@@ -904,7 +907,7 @@ func mkpackage(pkgname string) {
p = p[:i]
}
suffix := ".o"
- if writearchive > 0 {
+ if writearchive {
suffix = ".a"
}
outfile = p + suffix
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
index 99eb73bd94..c1132b6aac 100644
--- a/src/cmd/compile/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -5,6 +5,7 @@
package gc
import (
+ "cmd/internal/bio"
"cmd/internal/obj"
"crypto/sha256"
"fmt"
@@ -23,7 +24,7 @@ func formathdr(arhdr []byte, name string, size int64) {
func dumpobj() {
var err error
- bout, err = obj.Bopenw(outfile)
+ bout, err = bio.Create(outfile)
if err != nil {
Flusherrors()
fmt.Printf("can't create %s: %v\n", outfile, err)
@@ -32,36 +33,36 @@ func dumpobj() {
startobj := int64(0)
var arhdr [ArhdrSize]byte
- if writearchive != 0 {
- obj.Bwritestring(bout, "!<arch>\n")
+ if writearchive {
+ bout.WriteString("!<arch>\n")
arhdr = [ArhdrSize]byte{}
bout.Write(arhdr[:])
- startobj = obj.Boffset(bout)
+ startobj = bout.Offset()
}
fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
dumpexport()
- if writearchive != 0 {
+ if writearchive {
bout.Flush()
- size := obj.Boffset(bout) - startobj
+ size := bout.Offset() - startobj
if size&1 != 0 {
- obj.Bputc(bout, 0)
+ bout.WriteByte(0)
}
- obj.Bseek(bout, startobj-ArhdrSize, 0)
+ bout.Seek(startobj-ArhdrSize, 0)
formathdr(arhdr[:], "__.PKGDEF", size)
bout.Write(arhdr[:])
bout.Flush()
- obj.Bseek(bout, startobj+size+(size&1), 0)
+ bout.Seek(startobj+size+(size&1), 0)
arhdr = [ArhdrSize]byte{}
bout.Write(arhdr[:])
- startobj = obj.Boffset(bout)
+ startobj = bout.Offset()
fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
}
if pragcgobuf != "" {
- if writearchive != 0 {
+ if writearchive {
// write empty export section; must be before cgo section
fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
}
@@ -86,21 +87,26 @@ func dumpobj() {
dumpglobls()
externdcl = tmp
+ if zerosize > 0 {
+ zero := Pkglookup("zero", mappkg)
+ ggloblsym(zero, int32(zerosize), obj.DUPOK|obj.RODATA)
+ }
+
dumpdata()
- obj.Writeobjdirect(Ctxt, bout)
+ obj.Writeobjdirect(Ctxt, bout.Writer)
- if writearchive != 0 {
+ if writearchive {
bout.Flush()
- size := obj.Boffset(bout) - startobj
+ size := bout.Offset() - startobj
if size&1 != 0 {
- obj.Bputc(bout, 0)
+ bout.WriteByte(0)
}
- obj.Bseek(bout, startobj-ArhdrSize, 0)
+ bout.Seek(startobj-ArhdrSize, 0)
formathdr(arhdr[:], "_go_.o", size)
bout.Write(arhdr[:])
}
- obj.Bterm(bout)
+ bout.Close()
}
func dumpglobls() {
@@ -132,9 +138,9 @@ func dumpglobls() {
funcsyms = nil
}
-func Bputname(b *obj.Biobuf, s *obj.LSym) {
- obj.Bwritestring(b, s.Name)
- obj.Bputc(b, 0)
+func Bputname(b *bio.Writer, s *obj.LSym) {
+ b.WriteString(s.Name)
+ b.WriteByte(0)
}
func Linksym(s *Sym) *obj.LSym {
@@ -320,9 +326,15 @@ func dsymptrLSym(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
return off
}
+func dsymptrOffLSym(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
+ s.WriteOff(Ctxt, int64(off), x, int64(xoff))
+ off += 4
+ return off
+}
+
func gdata(nam *Node, nr *Node, wid int) {
if nam.Op != ONAME {
- Fatalf("gdata nam op %v", opnames[nam.Op])
+ Fatalf("gdata nam op %v", nam.Op)
}
if nam.Sym == nil {
Fatalf("gdata nil nam sym")
@@ -330,20 +342,23 @@ func gdata(nam *Node, nr *Node, wid int) {
switch nr.Op {
case OLITERAL:
- switch nr.Val().Ctype() {
- case CTCPLX:
- gdatacomplex(nam, nr.Val().U.(*Mpcplx))
+ switch u := nr.Val().U.(type) {
+ case *Mpcplx:
+ gdatacomplex(nam, u)
- case CTSTR:
- gdatastring(nam, nr.Val().U.(string))
+ case string:
+ gdatastring(nam, u)
- case CTINT, CTRUNE, CTBOOL:
- i, _ := nr.IntLiteral()
+ case bool:
+ i := int64(obj.Bool2int(u))
Linksym(nam.Sym).WriteInt(Ctxt, nam.Xoffset, wid, i)
- case CTFLT:
+ case *Mpint:
+ Linksym(nam.Sym).WriteInt(Ctxt, nam.Xoffset, wid, u.Int64())
+
+ case *Mpflt:
s := Linksym(nam.Sym)
- f := nr.Val().U.(*Mpflt).Float64()
+ f := u.Float64()
switch nam.Type.Etype {
case TFLOAT32:
s.WriteFloat32(Ctxt, nam.Xoffset, float32(f))
@@ -357,7 +372,7 @@ func gdata(nam *Node, nr *Node, wid int) {
case OADDR:
if nr.Left.Op != ONAME {
- Fatalf("gdata ADDR left op %s", opnames[nr.Left.Op])
+ Fatalf("gdata ADDR left op %s", nr.Left.Op)
}
to := nr.Left
Linksym(nam.Sym).WriteAddr(Ctxt, nam.Xoffset, wid, Linksym(to.Sym), to.Xoffset)
@@ -369,7 +384,7 @@ func gdata(nam *Node, nr *Node, wid int) {
Linksym(nam.Sym).WriteAddr(Ctxt, nam.Xoffset, wid, Linksym(funcsym(nr.Sym)), nr.Xoffset)
default:
- Fatalf("gdata unhandled op %v %v\n", nr, opnames[nr.Op])
+ Fatalf("gdata unhandled op %v %v\n", nr, nr.Op)
}
}
diff --git a/src/cmd/compile/internal/gc/opnames.go b/src/cmd/compile/internal/gc/opnames.go
index df0d8cb7fb..015baa2376 100644
--- a/src/cmd/compile/internal/gc/opnames.go
+++ b/src/cmd/compile/internal/gc/opnames.go
@@ -160,9 +160,9 @@ var opnames = []string{
OLROT: "LROT",
ORROTC: "RROTC",
ORETJMP: "RETJMP",
- OPS: "OPS",
- OPC: "OPC",
- OSQRT: "OSQRT",
- OGETG: "OGETG",
+ OPS: "PS",
+ OPC: "PC",
+ OSQRT: "SQRT",
+ OGETG: "GETG",
OEND: "END",
}
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index 8410a236cd..7026ad79ef 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -165,7 +165,7 @@ func ordersafeexpr(n *Node, order *Order) *Node {
a.Right = r
return typecheck(&a, Erv)
default:
- Fatalf("ordersafeexpr %v", Oconv(n.Op, 0))
+ Fatalf("ordersafeexpr %v", n.Op)
return nil // not reached
}
}
@@ -324,7 +324,7 @@ func ismulticall(l Nodes) bool {
// Copyret emits t1, t2, ... = n, where n is a function call,
// and then returns the list t1, t2, ....
func copyret(n *Node, order *Order) []*Node {
- if !n.Type.IsStruct() || !n.Type.Funarg {
+ if !n.Type.IsFuncArgStruct() {
Fatalf("copyret %v %d", n.Type, n.Left.Type.Results().NumFields())
}
@@ -373,7 +373,7 @@ func ordercall(n *Node, order *Order) {
if t == nil {
break
}
- if t.Note != nil && *t.Note == unsafeUintptrTag {
+ if t.Note == unsafeUintptrTag {
xp := n.List.Addr(i)
for (*xp).Op == OCONVNOP && !(*xp).Type.IsPtr() {
xp = &(*xp).Left
@@ -416,7 +416,7 @@ func ordercall(n *Node, order *Order) {
func ordermapassign(n *Node, order *Order) {
switch n.Op {
default:
- Fatalf("ordermapassign %v", Oconv(n.Op, 0))
+ Fatalf("ordermapassign %v", n.Op)
case OAS:
order.out = append(order.out, n)
@@ -478,7 +478,7 @@ func orderstmt(n *Node, order *Order) {
switch n.Op {
default:
- Fatalf("orderstmt %v", Oconv(n.Op, 0))
+ Fatalf("orderstmt %v", n.Op)
case OVARKILL, OVARLIVE:
order.out = append(order.out, n)
@@ -731,7 +731,7 @@ func orderstmt(n *Node, order *Order) {
default:
Fatalf("orderstmt range %v", n.Type)
- case TARRAY:
+ case TARRAY, TSLICE:
if n.List.Len() < 2 || isblank(n.List.Second()) {
// for i := range x will only use x once, to compute len(x).
// No need to copy it.
@@ -790,7 +790,7 @@ func orderstmt(n *Node, order *Order) {
var r *Node
for _, n2 := range n.List.Slice() {
if n2.Op != OXCASE {
- Fatalf("order select case %v", Oconv(n2.Op, 0))
+ Fatalf("order select case %v", n2.Op)
}
r = n2.Left
setlineno(n2)
@@ -803,7 +803,7 @@ func orderstmt(n *Node, order *Order) {
if r != nil {
switch r.Op {
default:
- Yyerror("unknown op in select %v", Oconv(r.Op, 0))
+ Yyerror("unknown op in select %v", r.Op)
Dump("select case", r)
// If this is case x := <-ch or case x, y := <-ch, the case has
@@ -943,7 +943,7 @@ func orderstmt(n *Node, order *Order) {
n.Left = orderexpr(n.Left, order, nil)
for _, n4 := range n.List.Slice() {
if n4.Op != OXCASE {
- Fatalf("order switch case %v", Oconv(n4.Op, 0))
+ Fatalf("order switch case %v", n4.Op)
}
orderexprlistinplace(n4.List, order)
orderblockNodes(&n4.Nbody)
@@ -1123,30 +1123,22 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
n = ordercopyexpr(n, n.Type, order, 0)
}
- case OSLICE, OSLICEARR, OSLICESTR:
+ case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
n.Left = orderexpr(n.Left, order, nil)
- n.Right.Left = orderexpr(n.Right.Left, order, nil)
- n.Right.Left = ordercheapexpr(n.Right.Left, order)
- n.Right.Right = 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:
- n.Left = orderexpr(n.Left, order, nil)
- n.Right.Left = orderexpr(n.Right.Left, order, nil)
- n.Right.Left = ordercheapexpr(n.Right.Left, order)
- n.Right.Right.Left = orderexpr(n.Right.Right.Left, order, nil)
- n.Right.Right.Left = ordercheapexpr(n.Right.Right.Left, order)
- n.Right.Right.Right = orderexpr(n.Right.Right.Right, order, nil)
- n.Right.Right.Right = ordercheapexpr(n.Right.Right.Right, order)
+ low, high, max := n.SliceBounds()
+ low = orderexpr(low, order, nil)
+ low = ordercheapexpr(low, order)
+ high = orderexpr(high, order, nil)
+ high = ordercheapexpr(high, order)
+ max = orderexpr(max, order, nil)
+ max = ordercheapexpr(max, order)
+ n.SetSliceBounds(low, high, max)
if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) {
n = ordercopyexpr(n, n.Type, order, 0)
}
case OCLOSURE:
- if n.Noescape && len(n.Func.Cvars.Slice()) > 0 {
+ if n.Noescape && n.Func.Cvars.Len() > 0 {
prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type
}
diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go
index 6538877e68..55f352590b 100644
--- a/src/cmd/compile/internal/gc/parser.go
+++ b/src/cmd/compile/internal/gc/parser.go
@@ -102,6 +102,9 @@ func (p *parser) syntax_error(msg string) {
tok = "name"
}
case LLITERAL:
+ if litbuf == "" {
+ litbuf = "literal " + lexbuf.String()
+ }
tok = litbuf
case LOPER:
tok = goopnames[p.op]
@@ -1408,20 +1411,17 @@ loop:
}
x = Nod(OINDEX, x, i)
case 1:
- i := index[0]
- j := index[1]
- x = Nod(OSLICE, x, Nod(OKEY, i, j))
+ x = Nod(OSLICE, x, nil)
+ x.SetSliceBounds(index[0], index[1], nil)
case 2:
- i := index[0]
- j := index[1]
- k := index[2]
- if j == nil {
+ if index[1] == nil {
Yyerror("middle index required in 3-index slice")
}
- if k == nil {
+ if index[2] == nil {
Yyerror("final index required in 3-index slice")
}
- x = Nod(OSLICE3, x, Nod(OKEY, i, Nod(OKEY, j, k)))
+ x = Nod(OSLICE3, x, nil)
+ x.SetSliceBounds(index[0], index[1], index[2])
default:
panic("unreachable")
@@ -2906,7 +2906,7 @@ func (p *parser) hidden_import() {
if Debug['E'] > 0 {
fmt.Printf("import [%q] func %v \n", importpkg.Path, s2)
- if Debug['m'] > 2 && len(s2.Func.Inl.Slice()) != 0 {
+ if Debug['m'] > 2 && s2.Func.Inl.Len() != 0 {
fmt.Printf("inl body:%v\n", s2.Func.Inl)
}
}
@@ -3246,17 +3246,14 @@ func (p *parser) hidden_literal() *Node {
if p.tok == LLITERAL {
ss := nodlit(p.val)
p.next()
- switch ss.Val().Ctype() {
- case CTINT, CTRUNE:
- ss.Val().U.(*Mpint).Neg()
- break
- case CTFLT:
- ss.Val().U.(*Mpflt).Neg()
- break
- case CTCPLX:
- ss.Val().U.(*Mpcplx).Real.Neg()
- ss.Val().U.(*Mpcplx).Imag.Neg()
- break
+ switch u := ss.Val().U.(type) {
+ case *Mpint:
+ u.Neg()
+ case *Mpflt:
+ u.Neg()
+ case *Mpcplx:
+ u.Real.Neg()
+ u.Imag.Neg()
default:
Yyerror("bad negated constant")
}
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
index efe10a419c..984d468bc6 100644
--- a/src/cmd/compile/internal/gc/pgen.go
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -7,6 +7,7 @@ package gc
import (
"cmd/compile/internal/ssa"
"cmd/internal/obj"
+ "cmd/internal/sys"
"crypto/md5"
"fmt"
"sort"
@@ -90,7 +91,7 @@ func gvardefx(n *Node, as obj.As) {
Fatalf("gvardef nil")
}
if n.Op != ONAME {
- Yyerror("gvardef %v; %v", Oconv(n.Op, FmtSharp), n)
+ Yyerror("gvardef %v; %v", oconv(n.Op, FmtSharp), n)
return
}
@@ -286,7 +287,7 @@ func allocauto(ptxt *obj.Prog) {
if haspointers(n.Type) {
stkptrsize = Stksize
}
- if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+ if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
Stksize = Rnd(Stksize, int64(Widthptr))
}
if Stksize >= 1<<31 {
@@ -323,7 +324,12 @@ func Cgen_checknil(n *Node) {
Fatalf("bad checknil")
}
- if ((Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
+ // Most architectures require that the address to be checked is
+ // in a register (it could be in memory).
+ needsReg := !Thearch.LinkArch.InFamily(sys.AMD64, sys.I386)
+
+ // Move the address to be checked into a register if necessary.
+ if (needsReg && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
var reg Node
Regalloc(&reg, Types[Tptr], n)
Cgen(n, &reg)
@@ -357,8 +363,8 @@ func compile(fn *Node) {
Curfn = fn
dowidth(Curfn.Type)
- if len(fn.Nbody.Slice()) == 0 {
- if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
+ if fn.Nbody.Len() == 0 {
+ if pure_go || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
return
}
@@ -375,7 +381,7 @@ func compile(fn *Node) {
// set up domain for labels
clearlabels()
- if Curfn.Type.Outnamed {
+ if Curfn.Type.FuncType().Outnamed {
// add clearing of the output parameters
for _, t := range Curfn.Type.Results().Fields().Slice() {
if t.Nname != nil {
diff --git a/src/cmd/compile/internal/gc/pgen_test.go b/src/cmd/compile/internal/gc/pgen_test.go
index fcb8bfa0c2..44dc1db12e 100644
--- a/src/cmd/compile/internal/gc/pgen_test.go
+++ b/src/cmd/compile/internal/gc/pgen_test.go
@@ -10,6 +10,14 @@ import (
"testing"
)
+func typeWithoutPointers() *Type {
+ return &Type{Etype: TSTRUCT, Extra: &StructType{Haspointers: 1}} // haspointers -> false
+}
+
+func typeWithPointers() *Type {
+ return &Type{Etype: TSTRUCT, Extra: &StructType{Haspointers: 2}} // haspointers -> true
+}
+
// Test all code paths for cmpstackvarlt.
func TestCmpstackvar(t *testing.T) {
testdata := []struct {
@@ -62,13 +70,13 @@ func TestCmpstackvar(t *testing.T) {
false,
},
{
- Node{Class: PAUTO, Type: &Type{Haspointers: 1}}, // haspointers -> false
- Node{Class: PAUTO, Type: &Type{Haspointers: 2}}, // haspointers -> true
+ Node{Class: PAUTO, Type: typeWithoutPointers()},
+ Node{Class: PAUTO, Type: typeWithPointers()},
false,
},
{
- Node{Class: PAUTO, Type: &Type{Haspointers: 2}}, // haspointers -> true
- Node{Class: PAUTO, Type: &Type{Haspointers: 1}}, // haspointers -> false
+ Node{Class: PAUTO, Type: typeWithPointers()},
+ Node{Class: PAUTO, Type: typeWithoutPointers()},
true,
},
{
@@ -127,7 +135,7 @@ func TestStackvarSort(t *testing.T) {
{Class: PFUNC, Xoffset: 10, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
{Class: PFUNC, Xoffset: 20, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
{Class: PAUTO, Used: true, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
- {Class: PAUTO, Type: &Type{Haspointers: 1}, Name: &Name{}, Sym: &Sym{}}, // haspointers -> false
+ {Class: PAUTO, Type: typeWithoutPointers(), Name: &Name{}, Sym: &Sym{}},
{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
{Class: PAUTO, Type: &Type{}, Name: &Name{Needzero: true}, Sym: &Sym{}},
{Class: PAUTO, Type: &Type{Width: 1}, Name: &Name{}, Sym: &Sym{}},
@@ -148,7 +156,7 @@ func TestStackvarSort(t *testing.T) {
{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "abc"}},
{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "xyz"}},
- {Class: PAUTO, Type: &Type{Haspointers: 1}, Name: &Name{}, Sym: &Sym{}}, // haspointers -> false
+ {Class: PAUTO, Type: typeWithoutPointers(), Name: &Name{}, Sym: &Sym{}},
}
// haspointers updates Type.Haspointers as a side effect, so
// exercise this function on all inputs so that reflect.DeepEqual
diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go
index 43f594e2ea..e04c8563b1 100644
--- a/src/cmd/compile/internal/gc/plive.go
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -17,6 +17,7 @@ package gc
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"fmt"
"sort"
"strings"
@@ -917,18 +918,17 @@ func onebitwalktype1(t *Type, xoffset *int64, bv Bvec) {
bvset(bv, int32(*xoffset/int64(Widthptr)+1)) // pointer in second slot
*xoffset += t.Width
+ case TSLICE:
+ // struct { byte *array; uintgo len; uintgo cap; }
+ if *xoffset&int64(Widthptr-1) != 0 {
+ Fatalf("onebitwalktype1: invalid TARRAY alignment, %v", t)
+ }
+ bvset(bv, int32(*xoffset/int64(Widthptr))) // pointer in first slot (BitsPointer)
+ *xoffset += t.Width
+
case TARRAY:
- if t.IsSlice() {
- // struct { byte *array; uintgo len; uintgo cap; }
- if *xoffset&int64(Widthptr-1) != 0 {
- Fatalf("onebitwalktype1: invalid TARRAY alignment, %v", t)
- }
- bvset(bv, int32(*xoffset/int64(Widthptr))) // pointer in first slot (BitsPointer)
- *xoffset += t.Width
- } else {
- for i := int64(0); i < t.NumElem(); i++ {
- onebitwalktype1(t.Elem(), xoffset, bv)
- }
+ for i := int64(0); i < t.NumElem(); i++ {
+ onebitwalktype1(t.Elem(), xoffset, bv)
}
case TSTRUCT:
@@ -1396,7 +1396,7 @@ func livenessepilogue(lv *Liveness) {
// The instruction before a call to deferreturn is always a
// no-op, to keep PC-specific data unambiguous.
prev := p.Opt.(*obj.Prog)
- if Ctxt.Arch.Thechar == '9' {
+ if Ctxt.Arch.Family == sys.PPC64 {
// On ppc64 there is an additional instruction
// (another no-op or reload of toc pointer) before
// the call.
diff --git a/src/cmd/compile/internal/gc/popt.go b/src/cmd/compile/internal/gc/popt.go
index 41f8ba9fcc..001a715f7b 100644
--- a/src/cmd/compile/internal/gc/popt.go
+++ b/src/cmd/compile/internal/gc/popt.go
@@ -235,6 +235,34 @@ func fixjmp(firstp *obj.Prog) {
// for every f.Data field, for use by the client.
// If newData is nil, f.Data will be nil.
+type Graph struct {
+ Start *Flow
+ Num int
+
+ // After calling flowrpo, rpo lists the flow nodes in reverse postorder,
+ // and each non-dead Flow node f has g->rpo[f->rpo] == f.
+ Rpo []*Flow
+}
+
+type Flow struct {
+ Prog *obj.Prog // actual instruction
+ P1 *Flow // predecessors of this instruction: p1,
+ P2 *Flow // and then p2 linked though p2link.
+ P2link *Flow
+ S1 *Flow // successors of this instruction (at most two: s1 and s2).
+ S2 *Flow
+ Link *Flow // next instruction in function code
+
+ Active int32 // usable by client
+
+ Id int32 // sequence number in flow graph
+ Rpo int32 // reverse post ordering
+ Loop uint16 // x5 for every loop
+ Refset bool // diagnostic generated
+
+ Data interface{} // for use by client
+}
+
var flowmark int
// MaxFlowProg is the maximum size program (counted in instructions)
diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go
index 09889a40f3..5bcaf89d50 100644
--- a/src/cmd/compile/internal/gc/racewalk.go
+++ b/src/cmd/compile/internal/gc/racewalk.go
@@ -54,14 +54,14 @@ func instrument(fn *Node) {
return
}
- if flag_race == 0 || !ispkgin(norace_inst_pkgs) {
+ if !flag_race || !ispkgin(norace_inst_pkgs) {
instrumentlist(fn.Nbody, nil)
// nothing interesting for race detector in fn->enter
instrumentlist(fn.Func.Exit, nil)
}
- if flag_race != 0 {
+ if flag_race {
// nodpc is the PC of the caller as extracted by
// getcallerpc. We use -widthptr(FP) for x86.
// BUG: this will not work on arm.
@@ -132,7 +132,7 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
switch n.Op {
default:
- Fatalf("instrument: unknown node type %v", Oconv(n.Op, 0))
+ Fatalf("instrument: unknown node type %v", n.Op)
case OAS, OASWB, OAS2FUNC:
instrumentnode(&n.Left, init, 1, 0)
@@ -164,7 +164,13 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
var outn Nodes
outn.Set(out)
instrumentnode(&ls[i], &outn, 0, 0)
- out = append(outn.Slice(), ls[i])
+ if ls[i].Op != OAS || ls[i].Ninit.Len() == 0 {
+ out = append(outn.Slice(), ls[i])
+ } else {
+ // Splice outn onto end of ls[i].Ninit
+ ls[i].Ninit.AppendNodes(&outn)
+ out = append(out, ls[i])
+ }
}
}
n.List.Set(out)
@@ -301,7 +307,11 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
instrumentnode(&n.Left, init, 0, 0)
- instrumentnode(&n.Right, init, 0, 0)
+ low, high, max := n.SliceBounds()
+ instrumentnode(&low, init, 0, 0)
+ instrumentnode(&high, init, 0, 0)
+ instrumentnode(&max, init, 0, 0)
+ n.SetSliceBounds(low, high, max)
goto ret
case OKEY:
@@ -364,13 +374,13 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
OAS2RECV,
OAS2MAPR,
OASOP:
- Yyerror("instrument: %v must be lowered by now", Oconv(n.Op, 0))
+ Yyerror("instrument: %v must be lowered by now", n.Op)
goto ret
// impossible nodes: only appear in backend.
case ORROTC, OEXTEND:
- Yyerror("instrument: %v cannot exist now", Oconv(n.Op, 0))
+ Yyerror("instrument: %v cannot exist now", n.Op)
goto ret
case OGETG:
@@ -497,7 +507,7 @@ func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
n = treecopy(n, 0)
makeaddable(n)
var f *Node
- if flag_msan != 0 {
+ if flag_msan {
name := "msanread"
if wr != 0 {
name = "msanwrite"
@@ -509,7 +519,7 @@ func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
Fatalf("instrument: %v badwidth", t)
}
f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(w))
- } else if flag_race != 0 && (t.IsStruct() || t.IsArray()) {
+ } else if flag_race && (t.IsStruct() || t.IsArray()) {
name := "racereadrange"
if wr != 0 {
name = "racewriterange"
@@ -521,7 +531,7 @@ func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
Fatalf("instrument: %v badwidth", t)
}
f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(w))
- } else if flag_race != 0 {
+ } else if flag_race {
name := "raceread"
if wr != 0 {
name = "racewrite"
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
index 6adf8e0d6d..9d3f79cdce 100644
--- a/src/cmd/compile/internal/gc/range.go
+++ b/src/cmd/compile/internal/gc/range.go
@@ -49,7 +49,7 @@ func typecheckrange(n *Node) {
Yyerror("cannot range over %v", Nconv(n.Right, FmtLong))
goto out
- case TARRAY:
+ case TARRAY, TSLICE:
t1 = Types[TINT]
t2 = t.Elem()
@@ -154,7 +154,7 @@ func walkrange(n *Node) {
v2 = n.List.Second()
}
- // n->list has no meaning anymore, clear it
+ // n.List has no meaning anymore, clear it
// to avoid erroneous processing by racewalk.
n.List.Set(nil)
@@ -164,7 +164,7 @@ func walkrange(n *Node) {
default:
Fatalf("walkrange")
- case TARRAY:
+ case TARRAY, TSLICE:
if memclrrange(n, v1, v2, a) {
lineno = lno
return
@@ -217,9 +217,9 @@ func walkrange(n *Node) {
n.Right.Ninit.Set1(a)
}
- // orderstmt allocated the iterator for us.
- // we only use a once, so no copy needed.
case TMAP:
+ // orderstmt allocated the iterator for us.
+ // we only use a once, so no copy needed.
ha := a
th := hiter(t)
@@ -254,8 +254,8 @@ func walkrange(n *Node) {
body = []*Node{a}
}
- // orderstmt arranged for a copy of the channel variable.
case TCHAN:
+ // orderstmt arranged for a copy of the channel variable.
ha := a
n.Left = nil
@@ -278,9 +278,13 @@ func walkrange(n *Node) {
} else {
body = []*Node{Nod(OAS, v1, hv1)}
}
+ // Zero hv1. This prevents hv1 from being the sole, inaccessible
+ // reference to an otherwise GC-able value during the next channel receive.
+ // See issue 15281.
+ body = append(body, Nod(OAS, hv1, nil))
- // orderstmt arranged for a copy of the string variable.
case TSTRING:
+ // orderstmt arranged for a copy of the string variable.
ha := a
ohv1 := temp(Types[TINT])
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index 11bcd4cdc6..ceed55a2a5 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -22,6 +22,16 @@ type itabEntry struct {
var signatlist []*Node
var itabs []itabEntry
+type Sig struct {
+ name string
+ pkg *Pkg
+ isym *Sym
+ tsym *Sym
+ type_ *Type
+ mtype *Type
+ offset int32
+}
+
// byMethodNameAndPackagePath sorts method signatures by name, then package path.
type byMethodNameAndPackagePath []*Sig
@@ -60,12 +70,12 @@ const (
)
func structfieldSize() int { return 3 * Widthptr } // Sizeof(runtime.structfield{})
-func imethodSize() int { return 2 * Widthptr } // Sizeof(runtime.imethod{})
+func imethodSize() int { return 4 + 4 } // Sizeof(runtime.imethod{})
func uncommonSize(t *Type) int { // Sizeof(runtime.uncommontype{})
if t.Sym == nil && len(methods(t)) == 0 {
return 0
}
- return 2*Widthptr + 2*Widthint
+ return 4 + 2 + 2
}
func makefield(name string, t *Type) *Field {
@@ -76,8 +86,8 @@ func makefield(name string, t *Type) *Field {
}
func mapbucket(t *Type) *Type {
- if t.Bucket != nil {
- return t.Bucket
+ if t.MapType().Bucket != nil {
+ return t.MapType().Bucket
}
bucket := typ(TSTRUCT)
@@ -92,13 +102,18 @@ func mapbucket(t *Type) *Type {
valtype = Ptrto(valtype)
}
+ field := make([]*Field, 0, 5)
+
// The first field is: uint8 topbits[BUCKETSIZE].
arr := typArray(Types[TUINT8], BUCKETSIZE)
- field := make([]*Field, 0, 5)
field = append(field, makefield("topbits", arr))
+
arr = typArray(keytype, BUCKETSIZE)
+ arr.Noalg = true
field = append(field, makefield("keys", arr))
+
arr = typArray(valtype, BUCKETSIZE)
+ arr.Noalg = true
field = append(field, makefield("values", arr))
// Make sure the overflow pointer is the last memory in the struct,
@@ -147,17 +162,17 @@ func mapbucket(t *Type) *Type {
Yyerror("bad math in mapbucket for %v", t)
}
- t.Bucket = bucket
+ t.MapType().Bucket = bucket
- bucket.Map = t
+ bucket.StructType().Map = t
return bucket
}
// Builds a type representing a Hmap structure for the given map type.
// Make sure this stays in sync with ../../../../runtime/hashmap.go!
func hmap(t *Type) *Type {
- if t.Hmap != nil {
- return t.Hmap
+ if t.MapType().Hmap != nil {
+ return t.MapType().Hmap
}
bucket := mapbucket(t)
@@ -176,14 +191,14 @@ func hmap(t *Type) *Type {
h.Local = t.Local
h.SetFields(field[:])
dowidth(h)
- t.Hmap = h
- h.Map = t
+ t.MapType().Hmap = h
+ h.StructType().Map = t
return h
}
func hiter(t *Type) *Type {
- if t.Hiter != nil {
- return t.Hiter
+ if t.MapType().Hiter != nil {
+ return t.MapType().Hiter
}
// build a struct:
@@ -224,8 +239,8 @@ func hiter(t *Type) *Type {
if i.Width != int64(12*Widthptr) {
Yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr)
}
- t.Hiter = i
- i.Map = t
+ t.MapType().Hiter = i
+ i.StructType().Map = t
return i
}
@@ -402,8 +417,6 @@ func imethods(t *Type) []*Sig {
return methods
}
-var dimportpath_gopkg *Pkg
-
func dimportpath(p *Pkg) {
if p.Pathsym != nil {
return
@@ -416,27 +429,18 @@ func dimportpath(p *Pkg) {
return
}
- if dimportpath_gopkg == nil {
- dimportpath_gopkg = mkpkg("go")
- dimportpath_gopkg.Name = "go"
- }
-
- nam := "importpath." + p.Prefix + "."
-
- n := Nod(ONAME, nil, nil)
- n.Sym = Pkglookup(nam, dimportpath_gopkg)
-
- n.Class = PEXTERN
- n.Xoffset = 0
- p.Pathsym = n.Sym
-
+ var str string
if p == localpkg {
// Note: myimportpath != "", or else dgopkgpath won't call dimportpath.
- gdatastring(n, myimportpath)
+ str = myimportpath
} else {
- gdatastring(n, p.Path)
+ str = p.Path
}
- ggloblsym(n.Sym, int32(Types[TSTRING].Width), obj.DUPOK|obj.RODATA)
+
+ s := obj.Linklookup(Ctxt, "type..importpath."+p.Prefix+".", 0)
+ ot := dnameData(s, 0, str, "", nil, false)
+ ggloblLSym(s, int32(ot), obj.DUPOK|obj.RODATA)
+ p.Pathsym = s
}
func dgopkgpath(s *Sym, ot int, pkg *Pkg) int {
@@ -451,15 +455,34 @@ func dgopkgpathLSym(s *obj.LSym, ot int, pkg *Pkg) int {
if pkg == localpkg && myimportpath == "" {
// If we don't know the full import path of the package being compiled
// (i.e. -p was not passed on the compiler command line), emit a reference to
- // go.importpath.""., which the linker will rewrite using the correct import path.
+ // type..importpath.""., which the linker will rewrite using the correct import path.
// Every package that imports this one directly defines the symbol.
// See also https://groups.google.com/forum/#!topic/golang-dev/myb9s53HxGQ.
- ns := obj.Linklookup(Ctxt, `go.importpath."".`, 0)
+ ns := obj.Linklookup(Ctxt, `type..importpath."".`, 0)
return dsymptrLSym(s, ot, ns, 0)
}
dimportpath(pkg)
- return dsymptrLSym(s, ot, Linksym(pkg.Pathsym), 0)
+ return dsymptrLSym(s, ot, pkg.Pathsym, 0)
+}
+
+// dgopkgpathOffLSym writes an offset relocation in s at offset ot to the pkg path symbol.
+func dgopkgpathOffLSym(s *obj.LSym, ot int, pkg *Pkg) int {
+ if pkg == nil {
+ return duintxxLSym(s, ot, 0, 4)
+ }
+ if pkg == localpkg && myimportpath == "" {
+ // If we don't know the full import path of the package being compiled
+ // (i.e. -p was not passed on the compiler command line), emit a reference to
+ // type..importpath.""., which the linker will rewrite using the correct import path.
+ // Every package that imports this one directly defines the symbol.
+ // See also https://groups.google.com/forum/#!topic/golang-dev/myb9s53HxGQ.
+ ns := obj.Linklookup(Ctxt, `type..importpath."".`, 0)
+ return dsymptrOffLSym(s, ot, ns, 0)
+ }
+
+ dimportpath(pkg)
+ return dsymptrOffLSym(s, ot, pkg.Pathsym, 0)
}
// isExportedField reports whether a struct field is exported.
@@ -478,20 +501,16 @@ func isExportedField(ft *Field) bool {
// dnameField dumps a reflect.name for a struct field.
func dnameField(s *Sym, ot int, ft *Field) int {
- var name, tag string
+ var name string
if ft.Sym != nil && ft.Embedded == 0 {
name = ft.Sym.Name
}
- if ft.Note != nil {
- tag = *ft.Note
- }
- return dname(s, ot, name, tag, nil, isExportedField(ft))
+ nsym := dname(name, ft.Note, nil, isExportedField(ft))
+ return dsymptrLSym(Linksym(s), ot, nsym, 0)
}
-var dnameCount int
-
-// dname dumps a reflect.name for a struct field or method.
-func dname(s *Sym, ot int, name, tag string, pkg *Pkg, exported bool) int {
+// dnameData writes the contents of a reflect.name into s at offset ot.
+func dnameData(s *obj.LSym, ot int, name, tag string, pkg *Pkg, exported bool) int {
if len(name) > 1<<16-1 {
Fatalf("name too long: %s", name)
}
@@ -524,31 +543,46 @@ func dname(s *Sym, ot int, name, tag string, pkg *Pkg, exported bool) int {
copy(tb[2:], tag)
}
- // Very few names require a pkgPath *string (only those
- // defined in a different package than their type). So if
- // there is no pkgPath, we treat the name contents as string
- // data that duplicates across packages.
- var bsym *obj.LSym
+ ot = int(s.WriteBytes(Ctxt, int64(ot), b))
+
+ if pkg != nil {
+ ot = dgopkgpathOffLSym(s, ot, pkg)
+ }
+
+ return ot
+}
+
+var dnameCount int
+
+// dname creates a reflect.name for a struct field or method.
+func dname(name, tag string, pkg *Pkg, exported bool) *obj.LSym {
+ // Write out data as "type.." to signal two things to the
+ // linker, first that when dynamically linking, the symbol
+ // should be moved to a relro section, and second that the
+ // contents should not be decoded as a type.
+ sname := "type..namedata."
if pkg == nil {
- _, bsym = stringsym(string(b))
+ // In the common case, share data with other packages.
+ if name == "" {
+ if exported {
+ sname += "-noname-exported." + tag
+ } else {
+ sname += "-noname-unexported." + tag
+ }
+ } else {
+ sname += name + "." + tag
+ }
} else {
- // Write out data as "type.." to signal two things to the
- // linker, first that when dynamically linking, the symbol
- // should be moved to a relro section, and second that the
- // contents should not be decoded as a type.
- bsymname := fmt.Sprintf(`type..methodname."".%d`, dnameCount)
+ sname = fmt.Sprintf(`%s"".%d`, sname, dnameCount)
dnameCount++
- bsym = obj.Linklookup(Ctxt, bsymname, 0)
- bsym.P = b
- boff := len(b)
- boff = int(Rnd(int64(boff), int64(Widthptr)))
- boff = dgopkgpathLSym(bsym, boff, pkg)
- ggloblLSym(bsym, int32(boff), obj.RODATA|obj.LOCAL)
}
-
- ot = dsymptrLSym(Linksym(s), ot, bsym, 0)
-
- return ot
+ s := obj.Linklookup(Ctxt, sname, 0)
+ if len(s.P) > 0 {
+ return s
+ }
+ ot := dnameData(s, 0, name, tag, pkg, exported)
+ ggloblLSym(s, int32(ot), obj.DUPOK|obj.RODATA)
+ return s
}
// dextratype dumps the fields of a runtime.uncommontype.
@@ -568,15 +602,19 @@ func dextratype(s *Sym, ot int, t *Type, dataAdd int) int {
dtypesym(a.type_)
}
- ot = dgopkgpath(s, ot, typePkg(t))
-
- // slice header
- ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+dataAdd)
+ ot = dgopkgpathOffLSym(Linksym(s), ot, typePkg(t))
- n := len(m)
- ot = duintxx(s, ot, uint64(n), Widthint)
- ot = duintxx(s, ot, uint64(n), Widthint)
+ dataAdd += 4 + 2 + 2
+ mcount := len(m)
+ if mcount != int(uint16(mcount)) {
+ Fatalf("too many methods on %s: %d", t, mcount)
+ }
+ if dataAdd != int(uint16(dataAdd)) {
+ Fatalf("methods are too far away on %s: %d", t, dataAdd)
+ }
+ ot = duint16(s, ot, uint16(mcount))
+ ot = duint16(s, ot, uint16(dataAdd))
return ot
}
@@ -584,7 +622,7 @@ func typePkg(t *Type) *Pkg {
tsym := t.Sym
if tsym == nil {
switch t.Etype {
- case TARRAY, TPTR32, TPTR64, TCHAN:
+ case TARRAY, TSLICE, TPTR32, TPTR64, TCHAN:
if t.Elem() != nil {
tsym = t.Elem().Sym
}
@@ -599,6 +637,7 @@ func typePkg(t *Type) *Pkg {
// dextratypeData dumps the backing array for the []method field of
// runtime.uncommontype.
func dextratypeData(s *Sym, ot int, t *Type) int {
+ lsym := Linksym(s)
for _, a := range methods(t) {
// ../../../../runtime/type.go:/method
exported := exportname(a.name)
@@ -606,22 +645,24 @@ func dextratypeData(s *Sym, ot int, t *Type) int {
if !exported && a.pkg != typePkg(t) {
pkg = a.pkg
}
- ot = dname(s, ot, a.name, "", pkg, exported)
- ot = dmethodptr(s, ot, dtypesym(a.mtype))
- ot = dmethodptr(s, ot, a.isym)
- ot = dmethodptr(s, ot, a.tsym)
+ nsym := dname(a.name, "", pkg, exported)
+
+ ot = dsymptrOffLSym(lsym, ot, nsym, 0)
+ ot = dmethodptrOffLSym(lsym, ot, Linksym(dtypesym(a.mtype)))
+ ot = dmethodptrOffLSym(lsym, ot, Linksym(a.isym))
+ ot = dmethodptrOffLSym(lsym, ot, Linksym(a.tsym))
}
return ot
}
-func dmethodptr(s *Sym, off int, x *Sym) int {
- duintptr(s, off, 0)
- r := obj.Addrel(Linksym(s))
- r.Off = int32(off)
- r.Siz = uint8(Widthptr)
- r.Sym = Linksym(x)
- r.Type = obj.R_METHOD
- return off + Widthptr
+func dmethodptrOffLSym(s *obj.LSym, ot int, x *obj.LSym) int {
+ duintxxLSym(s, ot, 0, 4)
+ r := obj.Addrel(s)
+ r.Off = int32(ot)
+ r.Siz = 4
+ r.Sym = x
+ r.Type = obj.R_METHODOFF
+ return ot + 4
}
var kinds = []int{
@@ -647,6 +688,7 @@ var kinds = []int{
TCHAN: obj.KindChan,
TMAP: obj.KindMap,
TARRAY: obj.KindArray,
+ TSLICE: obj.KindSlice,
TFUNC: obj.KindFunc,
TCOMPLEX64: obj.KindComplex64,
TCOMPLEX128: obj.KindComplex128,
@@ -654,67 +696,46 @@ var kinds = []int{
}
func haspointers(t *Type) bool {
- if t.Haspointers != 0 {
- return t.Haspointers-1 != 0
- }
-
- var ret bool
switch t.Etype {
- case TINT,
- TUINT,
- TINT8,
- TUINT8,
- TINT16,
- TUINT16,
- TINT32,
- TUINT32,
- TINT64,
- TUINT64,
- TUINTPTR,
- TFLOAT32,
- TFLOAT64,
- TCOMPLEX64,
- TCOMPLEX128,
- TBOOL:
- ret = false
+ case TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64,
+ TUINT64, TUINTPTR, TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, TBOOL:
+ return false
+
+ case TSLICE:
+ return true
case TARRAY:
- if t.IsSlice() {
- ret = true
- break
+ at := t.Extra.(*ArrayType)
+ if at.Haspointers != 0 {
+ return at.Haspointers-1 != 0
}
- if t.NumElem() == 0 { // empty array
- ret = false
- break
+ ret := false
+ if t.NumElem() != 0 { // non-empty array
+ ret = haspointers(t.Elem())
}
- ret = haspointers(t.Elem())
+ at.Haspointers = 1 + uint8(obj.Bool2int(ret))
+ return ret
case TSTRUCT:
- ret = false
+ st := t.StructType()
+ if st.Haspointers != 0 {
+ return st.Haspointers-1 != 0
+ }
+
+ ret := false
for _, t1 := range t.Fields().Slice() {
if haspointers(t1.Type) {
ret = true
break
}
}
-
- case TSTRING,
- TPTR32,
- TPTR64,
- TUNSAFEPTR,
- TINTER,
- TCHAN,
- TMAP,
- TFUNC:
- fallthrough
- default:
- ret = true
+ st.Haspointers = 1 + uint8(obj.Bool2int(ret))
+ return ret
}
- t.Haspointers = 1 + uint8(obj.Bool2int(ret))
- return ret
+ return true
}
// typeptrdata returns the length in bytes of the prefix of t
@@ -742,11 +763,11 @@ func typeptrdata(t *Type) int64 {
// struct { Type *type; void *data; }
return 2 * int64(Widthptr)
+ case TSLICE:
+ // struct { byte *array; uintgo len; uintgo cap; }
+ return int64(Widthptr)
+
case TARRAY:
- if t.IsSlice() {
- // struct { byte *array; uintgo len; uintgo cap; }
- return int64(Widthptr)
- }
// haspointers already eliminated t.NumElem() == 0.
return (t.NumElem()-1)*t.Elem().Width + typeptrdata(t.Elem())
@@ -766,14 +787,21 @@ func typeptrdata(t *Type) int64 {
}
}
-// tflag is documented in ../../../../reflect/type.go.
-const tflagUncommon = 1
-
-// commonType
-// ../../../../runtime/type.go:/commonType
+// tflag is documented in reflect/type.go.
+//
+// tflag values must be kept in sync with copies in:
+// cmd/compile/internal/gc/reflect.go
+// cmd/link/internal/ld/decodesym.go
+// reflect/type.go
+// runtime/type.go
+const (
+ tflagUncommon = 1 << 0
+ tflagExtraStar = 1 << 1
+)
var dcommontype_algarray *Sym
+// dcommontype dumps the contents of a reflect.rtype (runtime._type).
func dcommontype(s *Sym, ot int, t *Type) int {
if ot != 0 {
Fatalf("dcommontype %d", ot)
@@ -814,7 +842,8 @@ func dcommontype(s *Sym, ot int, t *Type) int {
// kind uint8
// alg *typeAlg
// gcdata *byte
- // string *string
+ // str nameOff
+ // _ int32
// }
ot = duintptr(s, ot, uint64(t.Width))
ot = duintptr(s, ot, uint64(ptrdata))
@@ -825,6 +854,26 @@ func dcommontype(s *Sym, ot int, t *Type) int {
if uncommonSize(t) != 0 {
tflag |= tflagUncommon
}
+
+ exported := false
+ p := Tconv(t, FmtLeft|FmtUnsigned)
+ // If we're writing out type T,
+ // we are very likely to write out type *T as well.
+ // Use the string "*T"[1:] for "T", so that the two
+ // share storage. This is a cheap way to reduce the
+ // amount of space taken up by reflect strings.
+ if !strings.HasPrefix(p, "*") {
+ p = "*" + p
+ tflag |= tflagExtraStar
+ if t.Sym != nil {
+ exported = exportname(t.Sym.Name)
+ }
+ } else {
+ if t.Elem() != nil && t.Elem().Sym != nil {
+ exported = exportname(t.Elem().Sym.Name)
+ }
+ }
+
ot = duint8(s, ot, tflag)
// runtime (and common sense) expects alignment to be a power of two.
@@ -840,9 +889,6 @@ func dcommontype(s *Sym, ot int, t *Type) int {
ot = duint8(s, ot, t.Align) // fieldAlign
i = kinds[t.Etype]
- if t.IsSlice() {
- i = obj.KindSlice
- }
if !haspointers(t) {
i |= obj.KindNoPointers
}
@@ -860,21 +906,9 @@ func dcommontype(s *Sym, ot int, t *Type) int {
}
ot = dsymptr(s, ot, gcsym, 0) // gcdata
- p := Tconv(t, FmtLeft|FmtUnsigned)
-
- // If we're writing out type T,
- // we are very likely to write out type *T as well.
- // Use the string "*T"[1:] for "T", so that the two
- // share storage. This is a cheap way to reduce the
- // amount of space taken up by reflect strings.
- prefix := 0
- if !strings.HasPrefix(p, "*") {
- p = "*" + p
- prefix = 1
- }
- _, symdata := stringsym(p) // string
- ot = dsymptrLSym(Linksym(s), ot, symdata, prefix)
- ot = duintxx(s, ot, uint64(len(p)-prefix), Widthint)
+ nsym := dname(p, "", nil, exported)
+ ot = dsymptrOffLSym(Linksym(s), ot, nsym, 0)
+ ot = duint32(s, ot, 0)
return ot
}
@@ -889,23 +923,9 @@ func tracksym(t *Type, f *Field) *Sym {
return Pkglookup(Tconv(t, FmtLeft)+"."+f.Sym.Name, trackpkg)
}
-func typelinksym(t *Type) *Sym {
- // %-uT is what the generated Type's string field says.
- // It uses (ambiguous) package names instead of import paths.
- // %-T is the complete, unambiguous type name.
- // We want the types to end up sorted by string field,
- // so use that first in the name, and then add :%-T to
- // disambiguate. We use a tab character as the separator to
- // ensure the types appear sorted by their string field. The
- // names are a little long but they are discarded by the linker
- // and do not end up in the symbol table of the final binary.
- p := Tconv(t, FmtLeft|FmtUnsigned) + "\t" + Tconv(t, FmtLeft)
-
- s := Pkglookup(p, typelinkpkg)
-
- //print("typelinksym: %s -> %+S\n", p, s);
-
- return s
+func typelinkLSym(t *Type) *obj.LSym {
+ name := "go.typelink." + Tconv(t, FmtLeft) // complete, unambiguous type name
+ return obj.Linklookup(Ctxt, name, 0)
}
func typesymprefix(prefix string, t *Type) *Sym {
@@ -999,9 +1019,6 @@ func isreflexive(t *Type) bool {
return false
case TARRAY:
- if t.IsSlice() {
- Fatalf("slice can't be a map key: %v", t)
- }
return isreflexive(t.Elem())
case TSTRUCT:
@@ -1049,9 +1066,6 @@ func needkeyupdate(t *Type) bool {
return true
case TARRAY:
- if t.IsSlice() {
- Fatalf("slice can't be a map key: %v", t)
- }
return needkeyupdate(t.Elem())
case TSTRUCT:
@@ -1119,28 +1133,26 @@ ok:
ot = dextratype(s, ot, t, 0)
case TARRAY:
- if t.IsArray() {
- // ../../../../runtime/type.go:/arrayType
- s1 := dtypesym(t.Elem())
- t2 := typSlice(t.Elem())
- s2 := dtypesym(t2)
- ot = dcommontype(s, ot, t)
- ot = dsymptr(s, ot, s1, 0)
- ot = dsymptr(s, ot, s2, 0)
- ot = duintptr(s, ot, uint64(t.NumElem()))
- } else {
- // ../../../../runtime/type.go:/sliceType
- s1 := dtypesym(t.Elem())
+ // ../../../../runtime/type.go:/arrayType
+ s1 := dtypesym(t.Elem())
+ t2 := typSlice(t.Elem())
+ s2 := dtypesym(t2)
+ ot = dcommontype(s, ot, t)
+ ot = dsymptr(s, ot, s1, 0)
+ ot = dsymptr(s, ot, s2, 0)
+ ot = duintptr(s, ot, uint64(t.NumElem()))
+ ot = dextratype(s, ot, t, 0)
- ot = dcommontype(s, ot, t)
- ot = dsymptr(s, ot, s1, 0)
- }
+ case TSLICE:
+ // ../../../../runtime/type.go:/sliceType
+ s1 := dtypesym(t.Elem())
+ ot = dcommontype(s, ot, t)
+ ot = dsymptr(s, ot, s1, 0)
ot = dextratype(s, ot, t, 0)
- // ../../../../runtime/type.go:/chanType
case TCHAN:
+ // ../../../../runtime/type.go:/chanType
s1 := dtypesym(t.Elem())
-
ot = dcommontype(s, ot, t)
ot = dsymptr(s, ot, s1, 0)
ot = duintptr(s, ot, uint64(t.ChanDir()))
@@ -1207,6 +1219,7 @@ ok:
dataAdd := imethodSize() * n
ot = dextratype(s, ot, t, dataAdd)
+ lsym := Linksym(s)
for _, a := range m {
// ../../../../runtime/type.go:/imethod
exported := exportname(a.name)
@@ -1214,8 +1227,10 @@ ok:
if !exported && a.pkg != tpkg {
pkg = a.pkg
}
- ot = dname(s, ot, a.name, "", pkg, exported)
- ot = dsymptr(s, ot, dtypesym(a.type_), 0)
+ nsym := dname(a.name, "", pkg, exported)
+
+ ot = dsymptrOffLSym(lsym, ot, nsym, 0)
+ ot = dsymptrOffLSym(lsym, ot, Linksym(dtypesym(a.type_)), 0)
}
// ../../../../runtime/type.go:/mapType
@@ -1301,18 +1316,29 @@ ok:
ggloblsym(s, int32(ot), int16(dupok|obj.RODATA))
// generate typelink.foo pointing at s = type.foo.
+ //
// The linker will leave a table of all the typelinks for
- // types in the binary, so reflect can find them.
- // We only need the link for unnamed composites that
- // we want be able to find.
- if t.Sym == nil {
+ // types in the binary, so the runtime can find them.
+ //
+ // When buildmode=shared, all types are in typelinks so the
+ // runtime can deduplicate type pointers.
+ keep := Ctxt.Flag_dynlink
+ if !keep && t.Sym == nil {
+ // For an unnamed type, we only need the link if the type can
+ // be created at run time by reflect.PtrTo and similar
+ // functions. If the type exists in the program, those
+ // functions must return the existing type structure rather
+ // than creating a new one.
switch t.Etype {
- case TPTR32, TPTR64, TARRAY, TCHAN, TFUNC, TMAP, TSTRUCT:
- slink := typelinksym(t)
- dsymptr(slink, 0, s, 0)
- ggloblsym(slink, int32(Widthptr), int16(dupok|obj.RODATA))
+ case TPTR32, TPTR64, TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRUCT:
+ keep = true
}
}
+ if keep {
+ slink := typelinkLSym(t)
+ dsymptrOffLSym(slink, 0, Linksym(s), 0)
+ ggloblLSym(slink, 4, int16(dupok|obj.RODATA))
+ }
return s
}
@@ -1365,6 +1391,11 @@ func dumptypestructs() {
}
// generate import strings for imported packages
+ if forceObjFileStability {
+ // Sorting the packages is not necessary but to compare binaries created
+ // using textual and binary format we sort by path to reduce differences.
+ sort.Sort(pkgByPath(pkgs))
+ }
for _, p := range pkgs {
if p.Direct {
dimportpath(p)
@@ -1393,16 +1424,22 @@ func dumptypestructs() {
// add paths for runtime and main, which 6l imports implicitly.
dimportpath(Runtimepkg)
- if flag_race != 0 {
+ if flag_race {
dimportpath(racepkg)
}
- if flag_msan != 0 {
+ if flag_msan {
dimportpath(msanpkg)
}
dimportpath(mkpkg("main"))
}
}
+type pkgByPath []*Pkg
+
+func (a pkgByPath) Len() int { return len(a) }
+func (a pkgByPath) Less(i, j int) bool { return a[i].Path < a[j].Path }
+func (a pkgByPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
func dalgsym(t *Type) *Sym {
var s *Sym
var hashfunc *Sym
@@ -1632,11 +1669,10 @@ func (p *GCProg) emit(t *Type, offset int64) {
p.w.Ptr(offset / int64(Widthptr))
p.w.Ptr(offset/int64(Widthptr) + 1)
+ case TSLICE:
+ p.w.Ptr(offset / int64(Widthptr))
+
case TARRAY:
- if t.IsSlice() {
- p.w.Ptr(offset / int64(Widthptr))
- return
- }
if t.NumElem() == 0 {
// should have been handled by haspointers check above
Fatalf("GCProg.emit: empty array")
@@ -1667,3 +1703,27 @@ func (p *GCProg) emit(t *Type, offset int64) {
}
}
}
+
+// zeroaddr returns the address of a symbol with at least
+// size bytes of zeros.
+func zeroaddr(size int64) *Node {
+ if size >= 1<<31 {
+ Fatalf("map value too big %d", size)
+ }
+ if zerosize < size {
+ zerosize = size
+ }
+ s := Pkglookup("zero", mappkg)
+ if s.Def == nil {
+ x := newname(s)
+ x.Type = Types[TUINT8]
+ x.Class = PEXTERN
+ x.Typecheck = 1
+ s.Def = x
+ }
+ z := Nod(OADDR, s.Def, nil)
+ z.Type = Ptrto(Types[TUINT8])
+ z.Addable = true
+ z.Typecheck = 1
+ return z
+}
diff --git a/src/cmd/compile/internal/gc/reg.go b/src/cmd/compile/internal/gc/reg.go
index 26746a5bcf..5763f79de1 100644
--- a/src/cmd/compile/internal/gc/reg.go
+++ b/src/cmd/compile/internal/gc/reg.go
@@ -33,6 +33,7 @@ package gc
import (
"bytes"
"cmd/internal/obj"
+ "cmd/internal/sys"
"fmt"
"sort"
"strings"
@@ -249,7 +250,7 @@ func addmove(r *Flow, bn int, rn int, f int) {
p1.As = Thearch.Optoas(OAS, Types[uint8(v.etype)])
// TODO(rsc): Remove special case here.
- if (Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && v.etype == TBOOL {
+ if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) && v.etype == TBOOL {
p1.As = Thearch.Optoas(OAS, Types[TUINT8])
}
p1.From.Type = obj.TYPE_REG
@@ -302,7 +303,7 @@ func mkvar(f *Flow, a *obj.Addr) Bits {
// TODO(rsc): Remove special case here.
case obj.TYPE_ADDR:
var bit Bits
- if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+ if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) {
goto memcase
}
a.Type = obj.TYPE_MEM
@@ -368,7 +369,7 @@ func mkvar(f *Flow, a *obj.Addr) Bits {
if v.etype == et {
if int64(v.width) == w {
// TODO(rsc): Remove special case for arm here.
- if flag == 0 || Thearch.Thechar != '5' {
+ if flag == 0 || Thearch.LinkArch.Family != sys.ARM {
return blsh(uint(i))
}
}
@@ -487,7 +488,7 @@ func mkvar(f *Flow, a *obj.Addr) Bits {
}
if Debug['R'] != 0 {
- fmt.Printf("bit=%2d et=%v w=%d+%d %v %v flag=%d\n", i, Econv(et), o, w, Nconv(node, FmtSharp), Ctxt.Dconv(a), v.addr)
+ fmt.Printf("bit=%2d et=%v w=%d+%d %v %v flag=%d\n", i, et, o, w, Nconv(node, FmtSharp), Ctxt.Dconv(a), v.addr)
}
Ostats.Nvar++
@@ -651,7 +652,7 @@ func allreg(b uint64, r *Rgn) uint64 {
r.regno = 0
switch v.etype {
default:
- Fatalf("unknown etype %d/%v", Bitno(b), Econv(v.etype))
+ Fatalf("unknown etype %d/%v", Bitno(b), v.etype)
case TINT8,
TUINT8,
@@ -1114,7 +1115,7 @@ func regopt(firstp *obj.Prog) {
// Currently we never generate three register forms.
// If we do, this will need to change.
- if p.From3Type() != obj.TYPE_NONE {
+ if p.From3Type() != obj.TYPE_NONE && p.From3Type() != obj.TYPE_CONST {
Fatalf("regopt not implemented for from3")
}
@@ -1146,7 +1147,7 @@ func regopt(firstp *obj.Prog) {
}
if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf("bit=%2d addr=%d et=%v w=%-2d s=%v + %d\n", i, v.addr, Econv(v.etype), v.width, v.node, v.offset)
+ fmt.Printf("bit=%2d addr=%d et=%v w=%-2d s=%v + %d\n", i, v.addr, v.etype, v.width, v.node, v.offset)
}
}
@@ -1357,7 +1358,7 @@ loop2:
if rgp.regno != 0 {
if Debug['R'] != 0 && Debug['v'] != 0 {
v := &vars[rgp.varno]
- fmt.Printf("registerize %v+%d (bit=%2d et=%v) in %v usedreg=%#x vreg=%#x\n", v.node, v.offset, rgp.varno, Econv(v.etype), obj.Rconv(int(rgp.regno)), usedreg, vreg)
+ fmt.Printf("registerize %v+%d (bit=%2d et=%v) in %v usedreg=%#x vreg=%#x\n", v.node, v.offset, rgp.varno, v.etype, obj.Rconv(int(rgp.regno)), usedreg, vreg)
}
paint3(rgp.enter, int(rgp.varno), vreg, int(rgp.regno))
diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go
index 22c716f9ce..120a9b8cf1 100644
--- a/src/cmd/compile/internal/gc/select.go
+++ b/src/cmd/compile/internal/gc/select.go
@@ -18,7 +18,7 @@ func typecheckselect(sel *Node) {
ncase = n1
setlineno(ncase)
if ncase.Op != OXCASE {
- Fatalf("typecheckselect %v", Oconv(ncase.Op, 0))
+ Fatalf("typecheckselect %v", ncase.Op)
}
if ncase.List.Len() == 0 {
@@ -120,7 +120,7 @@ func walkselect(sel *Node) {
var ch *Node
switch n.Op {
default:
- Fatalf("select %v", Oconv(n.Op, 0))
+ Fatalf("select %v", n.Op)
// ok already
case OSEND:
@@ -218,7 +218,7 @@ func walkselect(sel *Node) {
r.Ninit.Set(cas.Ninit.Slice())
switch n.Op {
default:
- Fatalf("select %v", Oconv(n.Op, 0))
+ Fatalf("select %v", n.Op)
// if selectnbsend(c, v) { body } else { default body }
case OSEND:
@@ -282,7 +282,7 @@ func walkselect(sel *Node) {
} else {
switch n.Op {
default:
- Fatalf("select %v", Oconv(n.Op, 0))
+ Fatalf("select %v", n.Op)
// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
case OSEND:
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
index 85ef78b973..c6f2acffbf 100644
--- a/src/cmd/compile/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -342,8 +342,6 @@ func staticcopy(l *Node, r *Node, out *[]*Node) bool {
return true
}
fallthrough
-
- // fall through
case OSTRUCTLIT:
p := initplans[r]
@@ -563,6 +561,35 @@ func getdyn(n *Node, top int) initGenType {
return mode
}
+// isStaticCompositeLiteral reports whether n is a compile-time constant.
+func isStaticCompositeLiteral(n *Node) bool {
+ switch n.Op {
+ case OARRAYLIT:
+ if n.Type.IsSlice() {
+ return false
+ }
+ case OSTRUCTLIT:
+ case OLITERAL:
+ return true
+ default:
+ return false
+ }
+ for _, r := range n.List.Slice() {
+ if r.Op != OKEY {
+ Fatalf("isStaticCompositeLiteral: rhs not OKEY: %v", r)
+ }
+ index := r.Left
+ if n.Op == OARRAYLIT && index.Op != OLITERAL {
+ return false
+ }
+ value := r.Right
+ if !isStaticCompositeLiteral(value) {
+ return false
+ }
+ }
+ return true
+}
+
func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
for _, r := range n.List.Slice() {
if r.Op != OKEY {
@@ -700,7 +727,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
arraylit(ctxt, 2, n, vstat, init)
// copy static to slice
- a := Nod(OSLICE, vstat, Nod(OKEY, nil, nil))
+ a := Nod(OSLICE, vstat, nil)
a = Nod(OAS, var_, a)
a = typecheck(a, Etop)
@@ -718,15 +745,15 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
// var vauto *[...]t = new([...]t)
// 4. copy the static array to the auto array
// *vauto = vstat
- // 5. assign slice of allocated heap to var
- // var = [0:]*auto
- // 6. for each dynamic part assign to the slice
- // var[i] = dynamic part
+ // 5. for each dynamic part assign to the array
+ // vauto[i] = dynamic part
+ // 6. assign slice of allocated heap to var
+ // var = vauto[:]
//
// an optimization is done if there is no constant part
// 3. var vauto *[...]t = new([...]t)
- // 5. var = [0:]*auto
- // 6. var[i] = dynamic part
+ // 5. vauto[i] = dynamic part
+ // 6. var = vauto[:]
// if the literal contains constants,
// make static initialized array (1),(2)
@@ -784,21 +811,14 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
init.Append(a)
}
- // make slice out of heap (5)
- a = Nod(OAS, var_, Nod(OSLICE, vauto, Nod(OKEY, nil, nil)))
-
- a = typecheck(a, Etop)
- a = orderstmtinplace(a)
- a = walkstmt(a)
- init.Append(a)
- // put dynamics into slice (6)
+ // put dynamics into array (5)
for _, r := range n.List.Slice() {
if r.Op != OKEY {
Fatalf("slicelit: rhs not OKEY: %v", r)
}
index := r.Left
value := r.Right
- a := Nod(OINDEX, var_, index)
+ a := Nod(OINDEX, vauto, index)
a.Bounded = true
// TODO need to check bounds?
@@ -820,7 +840,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
continue
}
- // build list of var[c] = expr
+ // build list of vauto[c] = expr
setlineno(value)
a = Nod(OAS, a, value)
@@ -829,6 +849,14 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
a = walkstmt(a)
init.Append(a)
}
+
+ // make slice out of heap (6)
+ a = Nod(OAS, var_, Nod(OSLICE, vauto, nil))
+
+ a = typecheck(a, Etop)
+ a = orderstmtinplace(a)
+ a = walkstmt(a)
+ init.Append(a)
}
func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
@@ -1005,7 +1033,7 @@ func anylit(ctxt int, n *Node, var_ *Node, init *Nodes) {
t := n.Type
switch n.Op {
default:
- Fatalf("anylit: not lit")
+ Fatalf("anylit: not lit, op=%v node=%v", n.Op, n)
case OPTRLIT:
if !t.IsPtr() {
@@ -1074,13 +1102,13 @@ func anylit(ctxt int, n *Node, var_ *Node, init *Nodes) {
structlit(ctxt, 3, n, var_, init)
case OARRAYLIT:
- if t.Etype != TARRAY {
- Fatalf("anylit: not array")
- }
if t.IsSlice() {
slicelit(ctxt, n, var_, init)
break
}
+ if !t.IsArray() {
+ Fatalf("anylit: not array")
+ }
if var_.isSimpleName() && n.List.Len() > 4 {
if ctxt == 0 {
@@ -1280,28 +1308,22 @@ func addvalue(p *InitPlan, xoffset int64, n *Node) {
func iszero(n *Node) bool {
switch n.Op {
case OLITERAL:
- switch n.Val().Ctype() {
+ switch u := n.Val().U.(type) {
default:
Dump("unexpected literal", n)
Fatalf("iszero")
-
- case CTNIL:
+ case *NilVal:
return true
-
- case CTSTR:
- return n.Val().U.(string) == ""
-
- case CTBOOL:
- return !n.Val().U.(bool)
-
- case CTINT, CTRUNE:
- return n.Val().U.(*Mpint).CmpInt64(0) == 0
-
- case CTFLT:
- return n.Val().U.(*Mpflt).CmpFloat64(0) == 0
-
- case CTCPLX:
- return n.Val().U.(*Mpcplx).Real.CmpFloat64(0) == 0 && n.Val().U.(*Mpcplx).Imag.CmpFloat64(0) == 0
+ case string:
+ return u == ""
+ case bool:
+ return !u
+ case *Mpint:
+ return u.CmpInt64(0) == 0
+ case *Mpflt:
+ return u.CmpFloat64(0) == 0
+ case *Mpcplx:
+ return u.Real.CmpFloat64(0) == 0 && u.Imag.CmpFloat64(0) == 0
}
case OARRAYLIT:
@@ -1309,8 +1331,6 @@ func iszero(n *Node) bool {
break
}
fallthrough
-
- // fall through
case OSTRUCTLIT:
for _, n1 := range n.List.Slice() {
if !iszero(n1.Right) {
@@ -1371,7 +1391,8 @@ func genAsInitNoCheck(n *Node, reportOnly bool) bool {
fallthrough
case OSLICEARR:
- if nr.Right.Op != OKEY || nr.Right.Left != nil || nr.Right.Right != nil {
+ low, high, _ := nr.SliceBounds()
+ if low != nil || high != nil {
return false
}
nr = nr.Left
@@ -1385,7 +1406,7 @@ func genAsInitNoCheck(n *Node, reportOnly bool) bool {
}
// nr is the array being converted to a slice
- if nr.Type == nil || nr.Type.Etype != TARRAY || nr.Type.IsSlice() {
+ if nr.Type == nil || !nr.Type.IsArray() {
return false
}
diff --git a/src/cmd/compile/internal/gc/sizeof_test.go b/src/cmd/compile/internal/gc/sizeof_test.go
index 11c0f419da..a01da13883 100644
--- a/src/cmd/compile/internal/gc/sizeof_test.go
+++ b/src/cmd/compile/internal/gc/sizeof_test.go
@@ -27,7 +27,20 @@ func TestSizeof(t *testing.T) {
{Name{}, 52, 80},
{Node{}, 92, 144},
{Sym{}, 60, 112},
- {Type{}, 116, 184},
+ {Type{}, 52, 80},
+ {MapType{}, 20, 40},
+ {ForwardType{}, 16, 32},
+ {FuncType{}, 28, 48},
+ {StructType{}, 12, 24},
+ {InterType{}, 4, 8},
+ {ChanType{}, 8, 16},
+ {ArrayType{}, 16, 24},
+ {InterMethType{}, 4, 8},
+ {DDDFieldType{}, 4, 8},
+ {FuncArgsType{}, 4, 8},
+ {ChanArgsType{}, 4, 8},
+ {PtrType{}, 4, 8},
+ {SliceType{}, 4, 8},
}
for _, tt := range tests {
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 359f4b22a2..b31cd878cd 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -13,6 +13,7 @@ import (
"cmd/compile/internal/ssa"
"cmd/internal/obj"
+ "cmd/internal/sys"
)
var ssaEnabled = true
@@ -24,13 +25,13 @@ func initssa() *ssa.Config {
ssaExp.unimplemented = false
ssaExp.mustImplement = true
if ssaConfig == nil {
- ssaConfig = ssa.NewConfig(Thearch.Thestring, &ssaExp, Ctxt, Debug['N'] == 0)
+ ssaConfig = ssa.NewConfig(Thearch.LinkArch.Name, &ssaExp, Ctxt, Debug['N'] == 0)
}
return ssaConfig
}
func shouldssa(fn *Node) bool {
- switch Thearch.Thestring {
+ switch Thearch.LinkArch.Name {
default:
// Only available for testing.
if os.Getenv("SSATEST") == "" {
@@ -336,12 +337,14 @@ var (
memVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "mem"}}
// dummy nodes for temporary variables
- ptrVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ptr"}}
- capVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}}
- typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
- idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
- okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
- deltaVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "delta"}}
+ ptrVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ptr"}}
+ lenVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "len"}}
+ newlenVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "newlen"}}
+ capVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}}
+ typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
+ idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
+ okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
+ deltaVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "delta"}}
)
// startBlock sets the current block we're generating code in to b.
@@ -552,7 +555,7 @@ func (s *state) stmt(n *Node) {
case OCALLFUNC, OCALLMETH, OCALLINTER:
s.call(n, callNormal)
if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class == PFUNC &&
- (compiling_runtime != 0 && n.Left.Sym.Name == "throw" ||
+ (compiling_runtime && n.Left.Sym.Name == "throw" ||
n.Left.Sym.Pkg == Runtimepkg && (n.Left.Sym.Name == "gopanic" || n.Left.Sym.Name == "selectgo" || n.Left.Sym.Name == "block")) {
m := s.mem()
b := s.endBlock()
@@ -577,7 +580,7 @@ func (s *state) stmt(n *Node) {
if n.Left.Class&PHEAP == 0 {
return
}
- if compiling_runtime != 0 {
+ if compiling_runtime {
Fatalf("%v escapes to heap, not allowed in runtime.", n)
}
@@ -661,6 +664,17 @@ func (s *state) stmt(n *Node) {
return
}
+ if n.Left == n.Right && n.Left.Op == ONAME {
+ // An x=x assignment. No point in doing anything
+ // here. In addition, skipping this assignment
+ // prevents generating:
+ // VARDEF x
+ // COPY x -> x
+ // which is bad because x is incorrectly considered
+ // dead before the vardef. See issue #14904.
+ return
+ }
+
var t *Type
if n.Right != nil {
t = n.Right.Type
@@ -670,14 +684,27 @@ func (s *state) stmt(n *Node) {
// Evaluate RHS.
rhs := n.Right
- if rhs != nil && (rhs.Op == OSTRUCTLIT || rhs.Op == OARRAYLIT) {
- // All literals with nonzero fields have already been
- // rewritten during walk. Any that remain are just T{}
- // or equivalents. Use the zero value.
- if !iszero(rhs) {
- Fatalf("literal with nonzero value in SSA: %v", rhs)
+ if rhs != nil {
+ switch rhs.Op {
+ case OSTRUCTLIT, OARRAYLIT:
+ // All literals with nonzero fields have already been
+ // rewritten during walk. Any that remain are just T{}
+ // or equivalents. Use the zero value.
+ if !iszero(rhs) {
+ Fatalf("literal with nonzero value in SSA: %v", rhs)
+ }
+ rhs = nil
+ case OAPPEND:
+ // If we're writing the result of an append back to the same slice,
+ // handle it specially to avoid write barriers on the fast (non-growth) path.
+ // If the slice can be SSA'd, it'll be on the stack,
+ // so there will be no write barriers,
+ // so there's no need to attempt to prevent them.
+ if samesafeexpr(n.Left, rhs.List.First()) && !s.canSSA(n.Left) {
+ s.append(rhs, true)
+ return
+ }
}
- rhs = nil
}
var r *ssa.Value
needwb := n.Op == OASWB && rhs != nil
@@ -696,11 +723,11 @@ func (s *state) stmt(n *Node) {
}
}
if rhs != nil && rhs.Op == OAPPEND {
- // Yuck! The frontend gets rid of the write barrier, but we need it!
- // At least, we need it in the case where growslice is called.
- // TODO: Do the write barrier on just the growslice branch.
+ // The frontend gets rid of the write barrier to enable the special OAPPEND
+ // handling above, but since this is not a special case, we need it.
// TODO: just add a ptr graying to the end of growslice?
- // TODO: check whether we need to do this for ODOTTYPE and ORECV also.
+ // TODO: check whether we need to provide special handling and a write barrier
+ // for ODOTTYPE and ORECV also.
// They get similar wb-removal treatment in walk.go:OAS.
needwb = true
}
@@ -709,14 +736,7 @@ func (s *state) stmt(n *Node) {
if rhs != nil && (rhs.Op == OSLICE || rhs.Op == OSLICE3 || rhs.Op == OSLICESTR) && samesafeexpr(rhs.Left, n.Left) {
// We're assigning a slicing operation back to its source.
// Don't write back fields we aren't changing. See issue #14855.
- i := rhs.Right.Left
- var j, k *Node
- if rhs.Op == OSLICE3 {
- j = rhs.Right.Right.Left
- k = rhs.Right.Right.Right
- } else {
- j = rhs.Right.Right
- }
+ i, j, k := rhs.SliceBounds()
if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64() == 0) {
// [0:...] is the same as [:...]
i = nil
@@ -942,7 +962,7 @@ func (s *state) stmt(n *Node) {
s.nilCheck(p)
default:
- s.Unimplementedf("unhandled stmt %s", opnames[n.Op])
+ s.Unimplementedf("unhandled stmt %s", n.Op)
}
}
@@ -1101,7 +1121,7 @@ var opToSSA = map[opAndType]ssa.Op{
opAndType{OXOR, TINT64}: ssa.OpXor64,
opAndType{OXOR, TUINT64}: ssa.OpXor64,
- opAndType{OEQ, TBOOL}: ssa.OpEq8,
+ opAndType{OEQ, TBOOL}: ssa.OpEqB,
opAndType{OEQ, TINT8}: ssa.OpEq8,
opAndType{OEQ, TUINT8}: ssa.OpEq8,
opAndType{OEQ, TINT16}: ssa.OpEq16,
@@ -1111,7 +1131,7 @@ var opToSSA = map[opAndType]ssa.Op{
opAndType{OEQ, TINT64}: ssa.OpEq64,
opAndType{OEQ, TUINT64}: ssa.OpEq64,
opAndType{OEQ, TINTER}: ssa.OpEqInter,
- opAndType{OEQ, TARRAY}: ssa.OpEqSlice,
+ opAndType{OEQ, TSLICE}: ssa.OpEqSlice,
opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
opAndType{OEQ, TMAP}: ssa.OpEqPtr,
opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
@@ -1121,7 +1141,7 @@ var opToSSA = map[opAndType]ssa.Op{
opAndType{OEQ, TFLOAT64}: ssa.OpEq64F,
opAndType{OEQ, TFLOAT32}: ssa.OpEq32F,
- opAndType{ONE, TBOOL}: ssa.OpNeq8,
+ opAndType{ONE, TBOOL}: ssa.OpNeqB,
opAndType{ONE, TINT8}: ssa.OpNeq8,
opAndType{ONE, TUINT8}: ssa.OpNeq8,
opAndType{ONE, TINT16}: ssa.OpNeq16,
@@ -1131,7 +1151,7 @@ var opToSSA = map[opAndType]ssa.Op{
opAndType{ONE, TINT64}: ssa.OpNeq64,
opAndType{ONE, TUINT64}: ssa.OpNeq64,
opAndType{ONE, TINTER}: ssa.OpNeqInter,
- opAndType{ONE, TARRAY}: ssa.OpNeqSlice,
+ opAndType{ONE, TSLICE}: ssa.OpNeqSlice,
opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
opAndType{ONE, TMAP}: ssa.OpNeqPtr,
opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
@@ -1220,7 +1240,7 @@ func (s *state) ssaOp(op Op, t *Type) ssa.Op {
etype := s.concreteEtype(t)
x, ok := opToSSA[opAndType{op, etype}]
if !ok {
- s.Unimplementedf("unhandled binary op %s %s", opnames[op], Econv(etype))
+ s.Unimplementedf("unhandled binary op %s %s", op, etype)
}
return x
}
@@ -1378,7 +1398,7 @@ func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
etype2 := s.concreteEtype(u)
x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
if !ok {
- s.Unimplementedf("unhandled shift op %s etype=%s/%s", opnames[op], Econv(etype1), Econv(etype2))
+ s.Unimplementedf("unhandled shift op %s etype=%s/%s", op, etype1, etype2)
}
return x
}
@@ -1387,15 +1407,19 @@ func (s *state) ssaRotateOp(op Op, t *Type) ssa.Op {
etype1 := s.concreteEtype(t)
x, ok := opToSSA[opAndType{op, etype1}]
if !ok {
- s.Unimplementedf("unhandled rotate op %s etype=%s", opnames[op], Econv(etype1))
+ s.Unimplementedf("unhandled rotate op %s etype=%s", op, etype1)
}
return x
}
// expr converts the expression n to ssa, adds it to s and returns the ssa result.
func (s *state) expr(n *Node) *ssa.Value {
- s.pushLine(n.Lineno)
- defer s.popLine()
+ if !(n.Op == ONAME || n.Op == OLITERAL && n.Sym != nil) {
+ // ONAMEs and named OLITERALs have the line number
+ // of the decl, not the use. See issue 14742.
+ s.pushLine(n.Lineno)
+ defer s.popLine()
+ }
s.stmtList(n.Ninit)
switch n.Op {
@@ -1421,9 +1445,9 @@ func (s *state) expr(n *Node) *ssa.Value {
addr := s.addr(n, false)
return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
case OLITERAL:
- switch n.Val().Ctype() {
- case CTINT:
- i := n.Int64()
+ switch u := n.Val().U.(type) {
+ case *Mpint:
+ i := u.Int64()
switch n.Type.Size() {
case 1:
return s.constInt8(n.Type, int8(i))
@@ -1437,21 +1461,14 @@ func (s *state) expr(n *Node) *ssa.Value {
s.Fatalf("bad integer size %d", n.Type.Size())
return nil
}
- case CTSTR:
- if n.Val().U == "" {
+ case string:
+ if u == "" {
return s.constEmptyString(n.Type)
}
- return s.entryNewValue0A(ssa.OpConstString, n.Type, n.Val().U)
- case CTBOOL:
- v := s.constBool(n.Val().U.(bool))
- // For some reason the frontend gets the line numbers of
- // CTBOOL literals totally wrong. Fix it here by grabbing
- // the line number of the enclosing AST node.
- if len(s.line) >= 2 {
- v.Line = s.line[len(s.line)-2]
- }
- return v
- case CTNIL:
+ return s.entryNewValue0A(ssa.OpConstString, n.Type, u)
+ case bool:
+ return s.constBool(u)
+ case *NilVal:
t := n.Type
switch {
case t.IsSlice():
@@ -1461,36 +1478,30 @@ func (s *state) expr(n *Node) *ssa.Value {
default:
return s.constNil(t)
}
- case CTFLT:
- f := n.Val().U.(*Mpflt)
+ case *Mpflt:
switch n.Type.Size() {
case 4:
- return s.constFloat32(n.Type, f.Float32())
+ return s.constFloat32(n.Type, u.Float32())
case 8:
- return s.constFloat64(n.Type, f.Float64())
+ return s.constFloat64(n.Type, u.Float64())
default:
s.Fatalf("bad float size %d", n.Type.Size())
return nil
}
- case CTCPLX:
- c := n.Val().U.(*Mpcplx)
- r := &c.Real
- i := &c.Imag
+ case *Mpcplx:
+ r := &u.Real
+ i := &u.Imag
switch n.Type.Size() {
case 8:
- {
- pt := Types[TFLOAT32]
- return s.newValue2(ssa.OpComplexMake, n.Type,
- s.constFloat32(pt, r.Float32()),
- s.constFloat32(pt, i.Float32()))
- }
+ pt := Types[TFLOAT32]
+ return s.newValue2(ssa.OpComplexMake, n.Type,
+ s.constFloat32(pt, r.Float32()),
+ s.constFloat32(pt, i.Float32()))
case 16:
- {
- pt := Types[TFLOAT64]
- return s.newValue2(ssa.OpComplexMake, n.Type,
- s.constFloat64(pt, r.Float64()),
- s.constFloat64(pt, i.Float64()))
- }
+ pt := Types[TFLOAT64]
+ return s.newValue2(ssa.OpComplexMake, n.Type,
+ s.constFloat64(pt, r.Float64()),
+ s.constFloat64(pt, i.Float64()))
default:
s.Fatalf("bad float size %d", n.Type.Size())
return nil
@@ -1540,7 +1551,7 @@ func (s *state) expr(n *Node) *ssa.Value {
return nil
}
if etypesign(from.Etype) != etypesign(to.Etype) {
- s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, Econv(from.Etype), to, Econv(to.Etype))
+ s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, from.Etype, to, to.Etype)
return nil
}
@@ -1685,7 +1696,7 @@ func (s *state) expr(n *Node) *ssa.Value {
s.newValue1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
}
- s.Unimplementedf("unhandled OCONV %s -> %s", Econv(n.Left.Type.Etype), Econv(n.Type.Etype))
+ s.Unimplementedf("unhandled OCONV %s -> %s", n.Left.Type.Etype, n.Type.Etype)
return nil
case ODOTTYPE:
@@ -1708,7 +1719,7 @@ func (s *state) expr(n *Node) *ssa.Value {
case ONE:
return s.newValue1(ssa.OpNot, Types[TBOOL], c)
default:
- s.Fatalf("ordered complex compare %s", opnames[n.Op])
+ s.Fatalf("ordered complex compare %s", n.Op)
}
}
return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
@@ -1911,8 +1922,7 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
case OIND:
- p := s.expr(n.Left)
- s.nilCheck(p)
+ p := s.exprPtr(n.Left, false, n.Lineno)
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
case ODOT:
@@ -1925,8 +1935,7 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
case ODOTPTR:
- p := s.expr(n.Left)
- s.nilCheck(p)
+ p := s.exprPtr(n.Left, false, n.Lineno)
p = s.newValue1I(ssa.OpOffPtr, p.Type, n.Xoffset, p)
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
@@ -2019,38 +2028,34 @@ func (s *state) expr(n *Node) *ssa.Value {
}
return s.newValue2(ssa.OpIMake, n.Type, tab, data)
- case OSLICE, OSLICEARR:
+ case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR:
v := s.expr(n.Left)
- var i, j *ssa.Value
- if n.Right.Left != nil {
- i = s.extendIndex(s.expr(n.Right.Left))
+ var i, j, k *ssa.Value
+ low, high, max := n.SliceBounds()
+ if low != nil {
+ i = s.extendIndex(s.expr(low))
+ }
+ if high != nil {
+ j = s.extendIndex(s.expr(high))
}
- if n.Right.Right != nil {
- j = s.extendIndex(s.expr(n.Right.Right))
+ if max != nil {
+ k = s.extendIndex(s.expr(max))
}
- p, l, c := s.slice(n.Left.Type, v, i, j, nil)
+ p, l, c := s.slice(n.Left.Type, v, i, j, k)
return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
+
case OSLICESTR:
v := s.expr(n.Left)
var i, j *ssa.Value
- if n.Right.Left != nil {
- i = s.extendIndex(s.expr(n.Right.Left))
+ low, high, _ := n.SliceBounds()
+ if low != nil {
+ i = s.extendIndex(s.expr(low))
}
- if n.Right.Right != nil {
- j = s.extendIndex(s.expr(n.Right.Right))
+ if high != nil {
+ j = s.extendIndex(s.expr(high))
}
p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
return s.newValue2(ssa.OpStringMake, n.Type, p, l)
- case OSLICE3, OSLICE3ARR:
- v := s.expr(n.Left)
- var i *ssa.Value
- if n.Right.Left != nil {
- i = s.extendIndex(s.expr(n.Right.Left))
- }
- j := s.extendIndex(s.expr(n.Right.Right.Left))
- k := s.extendIndex(s.expr(n.Right.Right.Right))
- p, l, c := s.slice(n.Left.Type, v, i, j, k)
- return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
case OCALLFUNC:
if isIntrinsicCall1(n) {
@@ -2066,32 +2071,67 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.newValue1(ssa.OpGetG, n.Type, s.mem())
case OAPPEND:
- return s.exprAppend(n)
+ return s.append(n, false)
default:
- s.Unimplementedf("unhandled expr %s", opnames[n.Op])
+ s.Unimplementedf("unhandled expr %s", n.Op)
return nil
}
}
-// exprAppend converts an OAPPEND node n to an ssa.Value, adds it to s, and returns the Value.
-func (s *state) exprAppend(n *Node) *ssa.Value {
- // append(s, e1, e2, e3). Compile like:
- // ptr,len,cap := s
+// append converts an OAPPEND node to SSA.
+// If inplace is false, it converts the OAPPEND expression n to an ssa.Value,
+// adds it to s, and returns the Value.
+// If inplace is true, it writes the result of the OAPPEND expression n
+// back to the slice being appended to, and returns nil.
+// inplace MUST be set to false if the slice can be SSA'd.
+func (s *state) append(n *Node, inplace bool) *ssa.Value {
+ // If inplace is false, process as expression "append(s, e1, e2, e3)":
+ //
+ // ptr, len, cap := s
// newlen := len + 3
- // if newlen > s.cap {
- // ptr,_,cap = growslice(s, newlen)
+ // if newlen > cap {
+ // ptr, len, cap = growslice(s, newlen)
+ // newlen = len + 3 // recalculate to avoid a spill
// }
+ // // with write barriers, if needed:
+ // *(ptr+len) = e1
+ // *(ptr+len+1) = e2
+ // *(ptr+len+2) = e3
+ // return makeslice(ptr, newlen, cap)
+ //
+ //
+ // If inplace is true, process as statement "s = append(s, e1, e2, e3)":
+ //
+ // a := &s
+ // ptr, len, cap := s
+ // newlen := len + 3
+ // if newlen > cap {
+ // newptr, len, newcap = growslice(ptr, len, cap, newlen)
+ // vardef(a) // if necessary, advise liveness we are writing a new a
+ // *a.cap = newcap // write before ptr to avoid a spill
+ // *a.ptr = newptr // with write barrier
+ // }
+ // newlen = len + 3 // recalculate to avoid a spill
+ // *a.len = newlen
+ // // with write barriers, if needed:
// *(ptr+len) = e1
// *(ptr+len+1) = e2
// *(ptr+len+2) = e3
- // makeslice(ptr,newlen,cap)
et := n.Type.Elem()
pt := Ptrto(et)
// Evaluate slice
- slice := s.expr(n.List.First())
+ sn := n.List.First() // the slice node is the first in the list
+
+ var slice, addr *ssa.Value
+ if inplace {
+ addr = s.addr(sn, false)
+ slice = s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
+ } else {
+ slice = s.expr(sn)
+ }
// Allocate new blocks
grow := s.f.NewBlock(ssa.BlockPlain)
@@ -2103,9 +2143,17 @@ func (s *state) exprAppend(n *Node) *ssa.Value {
l := s.newValue1(ssa.OpSliceLen, Types[TINT], slice)
c := s.newValue1(ssa.OpSliceCap, Types[TINT], slice)
nl := s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
+
cmp := s.newValue2(s.ssaOp(OGT, Types[TINT]), Types[TBOOL], nl, c)
s.vars[&ptrVar] = p
- s.vars[&capVar] = c
+
+ if !inplace {
+ s.vars[&newlenVar] = nl
+ s.vars[&capVar] = c
+ } else {
+ s.vars[&lenVar] = l
+ }
+
b := s.endBlock()
b.Kind = ssa.BlockIf
b.Likely = ssa.BranchUnlikely
@@ -2115,20 +2163,40 @@ func (s *state) exprAppend(n *Node) *ssa.Value {
// Call growslice
s.startBlock(grow)
- taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(n.Type)}, s.sb)
+ taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(n.Type.Elem())}, s.sb)
r := s.rtcall(growslice, true, []*Type{pt, Types[TINT], Types[TINT]}, taddr, p, l, c, nl)
- s.vars[&ptrVar] = r[0]
- // Note: we don't need to read r[1], the result's length. It will be nl.
- // (or maybe we should, we just have to spill/restore nl otherwise?)
- s.vars[&capVar] = r[2]
+ if inplace {
+ if sn.Op == ONAME {
+ // Tell liveness we're about to build a new slice
+ s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, sn, s.mem())
+ }
+ capaddr := s.newValue1I(ssa.OpOffPtr, pt, int64(Array_cap), addr)
+ s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capaddr, r[2], s.mem())
+ s.insertWBstore(pt, addr, r[0], n.Lineno, 0)
+ // load the value we just stored to avoid having to spill it
+ s.vars[&ptrVar] = s.newValue2(ssa.OpLoad, pt, addr, s.mem())
+ s.vars[&lenVar] = r[1] // avoid a spill in the fast path
+ } else {
+ s.vars[&ptrVar] = r[0]
+ s.vars[&newlenVar] = s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], r[1], s.constInt(Types[TINT], nargs))
+ s.vars[&capVar] = r[2]
+ }
+
b = s.endBlock()
b.AddEdgeTo(assign)
// assign new elements to slots
s.startBlock(assign)
+ if inplace {
+ l = s.variable(&lenVar, Types[TINT]) // generates phi for len
+ nl = s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
+ lenaddr := s.newValue1I(ssa.OpOffPtr, pt, int64(Array_nel), addr)
+ s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenaddr, nl, s.mem())
+ }
+
// Evaluate args
args := make([]*ssa.Value, 0, nargs)
store := make([]bool, 0, nargs)
@@ -2142,8 +2210,11 @@ func (s *state) exprAppend(n *Node) *ssa.Value {
}
}
- p = s.variable(&ptrVar, pt) // generates phi for ptr
- c = s.variable(&capVar, Types[TINT]) // generates phi for cap
+ p = s.variable(&ptrVar, pt) // generates phi for ptr
+ if !inplace {
+ nl = s.variable(&newlenVar, Types[TINT]) // generates phi for nl
+ c = s.variable(&capVar, Types[TINT]) // generates phi for cap
+ }
p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
// TODO: just one write barrier call for all of these writes?
// TODO: maybe just one writeBarrier.enabled check?
@@ -2164,9 +2235,14 @@ func (s *state) exprAppend(n *Node) *ssa.Value {
}
}
- // make result
delete(s.vars, &ptrVar)
+ if inplace {
+ delete(s.vars, &lenVar)
+ return nil
+ }
+ delete(s.vars, &newlenVar)
delete(s.vars, &capVar)
+ // make result
return s.newValue3(ssa.OpSliceMake, n.Type, p, nl, c)
}
@@ -2398,7 +2474,7 @@ func isSSAIntrinsic1(s *Sym) bool {
// so far has only been noticed for Bswap32 and the 16-bit count
// leading/trailing instructions, but heuristics might change
// in the future or on different architectures).
- if !ssaEnabled || ssa.IntrinsicsDisable || Thearch.Thechar != '6' {
+ if !ssaEnabled || ssa.IntrinsicsDisable || Thearch.LinkArch.Family != sys.AMD64 {
return false
}
if s != nil && s.Pkg != nil && s.Pkg.Path == "runtime/internal/sys" {
@@ -2484,7 +2560,7 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
// want to set it here.
case OCALLINTER:
if fn.Op != ODOTINTER {
- Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", Oconv(fn.Op, 0))
+ Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op)
}
i := s.expr(fn.Left)
itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i)
@@ -2542,7 +2618,7 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
case sym != nil:
call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, sym, s.mem())
default:
- Fatalf("bad call type %s %v", opnames[n.Op], n)
+ Fatalf("bad call type %s %v", n.Op, n)
}
call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
@@ -2570,7 +2646,7 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
return nil
}
fp := res.Field(0)
- return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Offset, s.sp)
+ return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Offset+Ctxt.FixedFrameSize(), s.sp)
}
// etypesign returns the signed-ness of e, for integer/pointer etypes.
@@ -2680,19 +2756,12 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value {
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Elem()), a, i)
}
case OIND:
- p := s.expr(n.Left)
- if !bounded {
- s.nilCheck(p)
- }
- return p
+ return s.exprPtr(n.Left, bounded, n.Lineno)
case ODOT:
p := s.addr(n.Left, bounded)
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
case ODOTPTR:
- p := s.expr(n.Left)
- if !bounded {
- s.nilCheck(p)
- }
+ p := s.exprPtr(n.Left, bounded, n.Lineno)
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
case OCLOSUREVAR:
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
@@ -2715,7 +2784,7 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value {
return s.call(n, callNormal)
default:
- s.Unimplementedf("unhandled addr %v", Oconv(n.Op, 0))
+ s.Unimplementedf("unhandled addr %v", n.Op)
return nil
}
}
@@ -2773,9 +2842,6 @@ func canSSAType(t *Type) bool {
}
switch t.Etype {
case TARRAY:
- if t.IsSlice() {
- return true
- }
// We can't do arrays because dynamic indexing is
// not supported on SSA variables.
// TODO: maybe allow if length is <=1? All indexes
@@ -2797,6 +2863,19 @@ func canSSAType(t *Type) bool {
}
}
+// exprPtr evaluates n to a pointer and nil-checks it.
+func (s *state) exprPtr(n *Node, bounded bool, lineno int32) *ssa.Value {
+ p := s.expr(n)
+ if bounded || n.NonNil {
+ if s.f.Config.Debug_checknil() && lineno > 1 {
+ s.f.Config.Warnl(lineno, "removed nil check")
+ }
+ return p
+ }
+ s.nilCheck(p)
+ return p
+}
+
// nilCheck generates nil pointer checking code.
// Starts a new block on return, unless nil checks are disabled.
// Used only for automatically inserted nil checks,
@@ -3687,6 +3766,10 @@ func (s *state) resolveFwdRef(v *ssa.Value) {
if b == s.f.Entry {
// Live variable at start of function.
if s.canSSA(name) {
+ if strings.HasPrefix(name.Sym.Name, "autotmp_") {
+ // It's likely that this is an uninitialized variable in the entry block.
+ s.Fatalf("Treating auto as if it were arg, func %s, node %v, value %v", b.Func.Name, name, v)
+ }
v.Op = ssa.OpArg
v.Aux = name
return
@@ -4207,7 +4290,7 @@ func (e *ssaExport) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.Local
func (e *ssaExport) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
n := name.N.(*Node)
- ptrType := Ptrto(n.Type.Type)
+ ptrType := Ptrto(name.Type.ElemType().(*Type))
lenType := Types[TINT]
if n.Class == PAUTO && !n.Addrtaken {
// Split this slice up into three separate variables.
@@ -4241,6 +4324,20 @@ func (e *ssaExport) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSl
return ssa.LocalSlot{n, t, name.Off}, ssa.LocalSlot{n, t, name.Off + s}
}
+func (e *ssaExport) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
+ n := name.N.(*Node)
+ st := name.Type
+ ft := st.FieldType(i)
+ if n.Class == PAUTO && !n.Addrtaken {
+ // Note: the _ field may appear several times. But
+ // have no fear, identically-named but distinct Autos are
+ // ok, albeit maybe confusing for a debugger.
+ x := e.namedAuto(n.Sym.Name+"."+st.FieldName(i), ft)
+ return ssa.LocalSlot{x, ft, 0}
+ }
+ return ssa.LocalSlot{n, ft, name.Off + st.FieldOff(i)}
+}
+
// namedAuto returns a new AUTO variable with the given name and type.
func (e *ssaExport) namedAuto(name string, typ ssa.Type) ssa.GCNode {
t := typ.(*Type)
diff --git a/src/cmd/compile/internal/gc/ssa_test.go b/src/cmd/compile/internal/gc/ssa_test.go
index 59a240237b..46e1b0a7d3 100644
--- a/src/cmd/compile/internal/gc/ssa_test.go
+++ b/src/cmd/compile/internal/gc/ssa_test.go
@@ -99,3 +99,7 @@ func TestUnsafe(t *testing.T) { runTest(t, "unsafe_ssa.go") }
func TestPhi(t *testing.T) { runTest(t, "phi_ssa.go") }
func TestSlice(t *testing.T) { runTest(t, "slice.go") }
+
+func TestNamedReturn(t *testing.T) { runTest(t, "namedReturn.go") }
+
+func TestDuplicateLoad(t *testing.T) { runTest(t, "dupLoad.go") }
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index a61b8bcd27..6f2ed6a839 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -372,30 +372,6 @@ func saveorignode(n *Node) {
n.Orig = norig
}
-// checkMapKeyType checks that Type key is valid for use as a map key.
-func checkMapKeyType(key *Type) {
- alg, bad := algtype1(key)
- if alg != ANOEQ {
- return
- }
- switch bad.Etype {
- default:
- Yyerror("invalid map key type %v", key)
- case TANY:
- // Will be resolved later.
- case TFORW:
- // map[key] used during definition of key.
- // postpone check until key is fully defined.
- // if there are multiple uses of map[key]
- // before key is fully defined, the error
- // will only be printed for the first one.
- // good enough.
- if key.Maplineno == 0 {
- key.Maplineno = lineno
- }
- }
-}
-
// methcmp sorts by symbol, then by package path for unexported symbols.
type methcmp []*Field
@@ -540,8 +516,15 @@ func treecopy(n *Node, lineno int32) *Node {
}
return n
+ case OPACK:
+ // OPACK nodes are never valid in const value declarations,
+ // but allow them like any other declared symbol to avoid
+ // crashing (golang.org/issue/11361).
+ fallthrough
+
case ONAME, OLITERAL, OTYPE:
return n
+
}
}
@@ -611,6 +594,7 @@ func methtype(t *Type, mustname int) *Type {
case TSTRUCT,
TARRAY,
+ TSLICE,
TMAP,
TCHAN,
TSTRING,
@@ -631,14 +615,10 @@ func cplxsubtype(et EType) EType {
return TFLOAT64
}
- Fatalf("cplxsubtype: %v\n", Econv(et))
+ Fatalf("cplxsubtype: %v\n", et)
return 0
}
-func eqnote(a, b *string) bool {
- return a == b || a != nil && b != nil && *a == *b
-}
-
// Eqtype reports whether t1 and t2 are identical, following the spec rules.
//
// Any cyclic type must go through a named type, and if one is
@@ -658,7 +638,7 @@ func eqtype1(t1, t2 *Type, assumedEqual map[typePair]struct{}) bool {
if t1 == t2 {
return true
}
- if t1 == nil || t2 == nil || t1.Etype != t2.Etype {
+ if t1 == nil || t2 == nil || t1.Etype != t2.Etype || t1.Broke || t2.Broke {
return false
}
if t1.Sym != nil || t2.Sym != nil {
@@ -686,7 +666,7 @@ func eqtype1(t1, t2 *Type, assumedEqual map[typePair]struct{}) bool {
t1, i1 := IterFields(t1)
t2, i2 := IterFields(t2)
for ; t1 != nil && t2 != nil; t1, t2 = i1.Next(), i2.Next() {
- if t1.Sym != t2.Sym || t1.Embedded != t2.Embedded || !eqtype1(t1.Type, t2.Type, assumedEqual) || !eqnote(t1.Note, t2.Note) {
+ if t1.Sym != t2.Sym || t1.Embedded != t2.Embedded || !eqtype1(t1.Type, t2.Type, assumedEqual) || t1.Note != t2.Note {
return false
}
}
@@ -767,7 +747,7 @@ func assignop(src *Type, dst *Type, why *string) Op {
// TODO(rsc,lvd): This behaves poorly in the presence of inlining.
// https://golang.org/issue/2795
- if safemode != 0 && importpkg == nil && src != nil && src.Etype == TUNSAFEPTR {
+ if safemode && importpkg == nil && src != nil && src.Etype == TUNSAFEPTR {
Yyerror("cannot use unsafe.Pointer")
errorexit()
}
@@ -853,18 +833,13 @@ func assignop(src *Type, dst *Type, why *string) Op {
// 5. src is the predeclared identifier nil and dst is a nillable type.
if src.Etype == TNIL {
switch dst.Etype {
- case TARRAY:
- if !dst.IsSlice() {
- break
- }
- fallthrough
-
case TPTR32,
TPTR64,
TFUNC,
TMAP,
TCHAN,
- TINTER:
+ TINTER,
+ TSLICE:
return OCONVNOP
}
}
@@ -1045,6 +1020,68 @@ func Is64(t *Type) bool {
return false
}
+// SliceBounds returns n's slice bounds: low, high, and max in expr[low:high:max].
+// n must be a slice expression. max is nil if n is a simple slice expression.
+func (n *Node) SliceBounds() (low, high, max *Node) {
+ switch n.Op {
+ case OSLICE, OSLICEARR, OSLICESTR:
+ if n.Right == nil {
+ return nil, nil, nil
+ }
+ if n.Right.Op != OKEY {
+ Fatalf("SliceBounds right %s", opnames[n.Right.Op])
+ }
+ return n.Right.Left, n.Right.Right, nil
+ case OSLICE3, OSLICE3ARR:
+ if n.Right.Op != OKEY || n.Right.Right.Op != OKEY {
+ Fatalf("SliceBounds right %s %s", opnames[n.Right.Op], opnames[n.Right.Right.Op])
+ }
+ return n.Right.Left, n.Right.Right.Left, n.Right.Right.Right
+ }
+ Fatalf("SliceBounds op %s: %v", n.Op, n)
+ return nil, nil, nil
+}
+
+// SetSliceBounds sets n's slice bounds, where n is a slice expression.
+// n must be a slice expression. If max is non-nil, n must be a full slice expression.
+func (n *Node) SetSliceBounds(low, high, max *Node) {
+ switch n.Op {
+ case OSLICE, OSLICEARR, OSLICESTR:
+ if max != nil {
+ Fatalf("SetSliceBounds %s given three bounds", n.Op)
+ }
+ if n.Right == nil {
+ n.Right = Nod(OKEY, low, high)
+ return
+ }
+ n.Right.Left = low
+ n.Right.Right = high
+ return
+ case OSLICE3, OSLICE3ARR:
+ if n.Right == nil {
+ n.Right = Nod(OKEY, low, Nod(OKEY, high, max))
+ }
+ n.Right.Left = low
+ n.Right.Right.Left = high
+ n.Right.Right.Right = max
+ return
+ }
+ Fatalf("SetSliceBounds op %s: %v", n.Op, n)
+}
+
+// IsSlice3 reports whether o is a slice3 op (OSLICE3, OSLICE3ARR).
+// o must be a slicing op.
+func (o Op) IsSlice3() bool {
+ switch o {
+ case OSLICE, OSLICEARR, OSLICESTR:
+ return false
+ case OSLICE3, OSLICE3ARR:
+ return true
+ }
+ Fatalf("IsSlice3 op %v", o)
+ return false
+}
+
// Is a conversion between t1 and t2 a no-op?
func Noconv(t1 *Type, t2 *Type) bool {
e1 := Simtype[t1.Etype]
@@ -1081,6 +1118,10 @@ func syslook(name string) *Node {
return s.Def
}
+func (s *Sym) IsRuntimeCall(name string) bool {
+ return s.Pkg == Runtimepkg && s.Name == name
+}
+
// typehash computes a hash value for type t to use in type switch
// statements.
func typehash(t *Type) uint32 {
@@ -1162,9 +1203,9 @@ func printframenode(n *Node) {
}
switch n.Op {
case ONAME:
- fmt.Printf("%v %v G%d %v width=%d\n", Oconv(n.Op, 0), n.Sym, n.Name.Vargen, n.Type, w)
+ fmt.Printf("%v %v G%d %v width=%d\n", n.Op, n.Sym, n.Name.Vargen, n.Type, w)
case OTYPE:
- fmt.Printf("%v %v width=%d\n", Oconv(n.Op, 0), n.Type, w)
+ fmt.Printf("%v %v width=%d\n", n.Op, n.Type, w)
}
}
@@ -1245,7 +1286,7 @@ func badtype(op Op, tl *Type, tr *Type) {
}
s := fmt_
- Yyerror("illegal types for operand: %v%s", Oconv(op, 0), s)
+ Yyerror("illegal types for operand: %v%s", op, s)
}
// Brcom returns !(op).
@@ -1265,7 +1306,7 @@ func Brcom(op Op) Op {
case OGE:
return OLT
}
- Fatalf("brcom: no com for %v\n", Oconv(op, 0))
+ Fatalf("brcom: no com for %v\n", op)
return op
}
@@ -1286,7 +1327,7 @@ func Brrev(op Op) Op {
case OGE:
return OLE
}
- Fatalf("brrev: no rev for %v\n", Oconv(op, 0))
+ Fatalf("brrev: no rev for %v\n", op)
return op
}
@@ -1341,6 +1382,11 @@ func safeexpr(n *Node, init *Nodes) *Node {
a.Right = r
a = walkexpr(a, init)
return a
+
+ case OSTRUCTLIT, OARRAYLIT:
+ if isStaticCompositeLiteral(n) {
+ return n
+ }
}
// make a copy; must not be used as an lvalue
diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
index 3b08b13508..aac92fd311 100644
--- a/src/cmd/compile/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -350,7 +350,7 @@ func casebody(sw *Node, typeswvar *Node) {
for i, n := range sw.List.Slice() {
setlineno(n)
if n.Op != OXCASE {
- Fatalf("casebody %v", Oconv(n.Op, 0))
+ Fatalf("casebody %v", n.Op)
}
n.Op = OCASE
needvar := n.List.Len() != 1 || n.List.First().Op == OLITERAL
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
index 2f3b98a8ef..8a675ac157 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -54,6 +54,7 @@ type Node struct {
Addable bool // addressable
Etype EType // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg, ChanDir for OTCHAN
Bounded bool // bounds check unnecessary
+ NonNil bool // guaranteed to be non-nil
Class Class // PPARAM, PAUTO, PEXTERN, etc
Embedded uint8 // ODCLFIELD embedded type
Colas bool // OAS resulting from :=
diff --git a/src/cmd/compile/internal/gc/testdata/dupLoad.go b/src/cmd/compile/internal/gc/testdata/dupLoad.go
new file mode 100644
index 0000000000..d18dc733e1
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/dupLoad.go
@@ -0,0 +1,83 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This test makes sure that we don't split a single
+// load up into two separate loads.
+
+package main
+
+import "fmt"
+
+//go:noinline
+func read1(b []byte) (uint16, uint16) {
+ // There is only a single read of b[0]. The two
+ // returned values must have the same low byte.
+ v := b[0]
+ return uint16(v), uint16(v) | uint16(b[1])<<8
+}
+
+const N = 100000
+
+func main1() {
+ done := make(chan struct{})
+ b := make([]byte, 2)
+ go func() {
+ for i := 0; i < N; i++ {
+ b[0] = byte(i)
+ b[1] = byte(i)
+ }
+ done <- struct{}{}
+ }()
+ go func() {
+ for i := 0; i < N; i++ {
+ x, y := read1(b)
+ if byte(x) != byte(y) {
+ fmt.Printf("x=%x y=%x\n", x, y)
+ panic("bad")
+ }
+ }
+ done <- struct{}{}
+ }()
+ <-done
+ <-done
+}
+
+//go:noinline
+func read2(b []byte) (uint16, uint16) {
+ // There is only a single read of b[1]. The two
+ // returned values must have the same high byte.
+ v := uint16(b[1]) << 8
+ return v, uint16(b[0]) | v
+}
+
+func main2() {
+ done := make(chan struct{})
+ b := make([]byte, 2)
+ go func() {
+ for i := 0; i < N; i++ {
+ b[0] = byte(i)
+ b[1] = byte(i)
+ }
+ done <- struct{}{}
+ }()
+ go func() {
+ for i := 0; i < N; i++ {
+ x, y := read2(b)
+ if x&0xff00 != y&0xff00 {
+ fmt.Printf("x=%x y=%x\n", x, y)
+ panic("bad")
+ }
+ }
+ done <- struct{}{}
+ }()
+ <-done
+ <-done
+}
+
+func main() {
+ main1()
+ main2()
+}
diff --git a/src/cmd/compile/internal/gc/testdata/namedReturn.go b/src/cmd/compile/internal/gc/testdata/namedReturn.go
new file mode 100644
index 0000000000..19ef8a7e43
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/namedReturn.go
@@ -0,0 +1,105 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This test makes sure that naming named
+// return variables in a return statement works.
+// See issue #14904.
+
+package main
+
+import (
+ "fmt"
+ "runtime"
+)
+
+// Our heap-allocated object that will be GC'd incorrectly.
+// Note that we always check the second word because that's
+// where 0xdeaddeaddeaddead is written.
+type B [4]int
+
+// small (SSAable) array
+type T1 [3]*B
+
+//go:noinline
+func f1() (t T1) {
+ t[0] = &B{91, 92, 93, 94}
+ runtime.GC()
+ return t
+}
+
+// large (non-SSAable) array
+type T2 [8]*B
+
+//go:noinline
+func f2() (t T2) {
+ t[0] = &B{91, 92, 93, 94}
+ runtime.GC()
+ return t
+}
+
+// small (SSAable) struct
+type T3 struct {
+ a, b, c *B
+}
+
+//go:noinline
+func f3() (t T3) {
+ t.a = &B{91, 92, 93, 94}
+ runtime.GC()
+ return t
+}
+
+// large (non-SSAable) struct
+type T4 struct {
+ a, b, c, d, e, f *B
+}
+
+//go:noinline
+func f4() (t T4) {
+ t.a = &B{91, 92, 93, 94}
+ runtime.GC()
+ return t
+}
+
+var sink *B
+
+func f5() int {
+ b := &B{91, 92, 93, 94}
+ t := T4{b, nil, nil, nil, nil, nil}
+ sink = b // make sure b is heap allocated ...
+ sink = nil // ... but not live
+ runtime.GC()
+ t = t
+ return t.a[1]
+}
+
+func main() {
+ failed := false
+
+ if v := f1()[0][1]; v != 92 {
+ fmt.Printf("f1()[0][1]=%d, want 92\n", v)
+ failed = true
+ }
+ if v := f2()[0][1]; v != 92 {
+ fmt.Printf("f2()[0][1]=%d, want 92\n", v)
+ failed = true
+ }
+ if v := f3().a[1]; v != 92 {
+ fmt.Printf("f3().a[1]=%d, want 92\n", v)
+ failed = true
+ }
+ if v := f4().a[1]; v != 92 {
+ fmt.Printf("f4().a[1]=%d, want 92\n", v)
+ failed = true
+ }
+ if v := f5(); v != 92 {
+ fmt.Printf("f5()=%d, want 92\n", v)
+ failed = true
+ }
+ if failed {
+ panic("bad")
+ }
+}
diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go
index b89c5dbf22..9f049babc2 100644
--- a/src/cmd/compile/internal/gc/type.go
+++ b/src/cmd/compile/internal/gc/type.go
@@ -44,6 +44,7 @@ const (
TPTR64
TFUNC
+ TSLICE
TARRAY
TSTRUCT
TCHAN
@@ -70,9 +71,18 @@ const (
NTYPE
)
+// ChanDir is whether a channel can send, receive, or both.
+type ChanDir uint8
+
+func (c ChanDir) CanRecv() bool { return c&Crecv != 0 }
+func (c ChanDir) CanSend() bool { return c&Csend != 0 }
+
const (
- sliceBound = -1 // slices have Bound=sliceBound
- dddBound = -100 // arrays declared as [...]T start life with Bound=dddBound
+ // types of channel
+ // must match ../../../../reflect/type.go:/ChanDir
+ Crecv ChanDir = 1 << 0
+ Csend ChanDir = 1 << 1
+ Cboth ChanDir = Crecv | Csend
)
// Types stores pointers to predeclared named types.
@@ -108,55 +118,168 @@ var (
// A Type represents a Go type.
type Type struct {
- Etype EType
- Noalg bool
- Chan ChanDir
- Trecur uint8 // to detect loops
- Printed bool
- Funarg bool // on TSTRUCT and TFIELD
- Local bool // created in this file
- Deferwidth bool
- Broke bool // broken type definition.
- Align uint8
- Haspointers uint8 // 0 unknown, 1 no, 2 yes
- Outnamed bool // on TFUNC
+ // Extra contains extra etype-specific fields.
+ // As an optimization, those etype-specific structs which contain exactly
+ // one pointer-shaped field are stored as values rather than pointers when possible.
+ //
+ // TMAP: *MapType
+ // TFORW: *ForwardType
+ // TFUNC: *FuncType
+ // TINTERMETHOD: InterMethType
+ // TSTRUCT: *StructType
+ // TINTER: *InterType
+ // TDDDFIELD: DDDFieldType
+ // TFUNCARGS: FuncArgsType
+ // TCHANARGS: ChanArgsType
+ // TCHAN: *ChanType
+ // TPTR32, TPTR64: PtrType
+ // TARRAY: *ArrayType
+ // TSLICE: SliceType
+ Extra interface{}
- Nod *Node // canonical OTYPE node
- Orig *Type // original type (type literal or predefined type)
+ // Width is the width of this Type in bytes.
+ Width int64
methods Fields
allMethods Fields
- Sym *Sym
+ Nod *Node // canonical OTYPE node
+ Orig *Type // original type (type literal or predefined type)
+
+ Sym *Sym // symbol containing name, for named types
Vargen int32 // unique name for OTYPE/ONAME
- Lineno int32
+ Lineno int32 // line at which this type was declared, implicitly or explicitly
+
+ Etype EType // kind of type
+ Noalg bool // suppress hash and eq algorithm generation
+ Trecur uint8 // to detect loops
+ Printed bool // prevent duplicate export printing
+ Local bool // created in this file
+ Deferwidth bool
+ Broke bool // broken type definition.
+ Align uint8 // the required alignment of this type, in bytes
+}
+
+// MapType contains Type fields specific to maps.
+type MapType struct {
+ Key *Type // Key type
+ Val *Type // Val (elem) type
+
+ Bucket *Type // internal struct type representing a hash bucket
+ Hmap *Type // internal struct type representing the Hmap (map header object)
+ Hiter *Type // internal struct type representing hash iterator state
+}
+
+// MapType returns t's extra map-specific fields.
+func (t *Type) MapType() *MapType {
+ t.wantEtype(TMAP)
+ return t.Extra.(*MapType)
+}
- nname *Node
+// ForwardType contains Type fields specific to forward types.
+type ForwardType struct {
+ Copyto []*Node // where to copy the eventual value to
+ Embedlineno int32 // first use of this type as an embedded type
+}
+
+// ForwardType returns t's extra forward-type-specific fields.
+func (t *Type) ForwardType() *ForwardType {
+ t.wantEtype(TFORW)
+ return t.Extra.(*ForwardType)
+}
+
+// FuncType contains Type fields specific to func types.
+type FuncType struct {
+ Receiver *Type // function receiver
+ Results *Type // function results
+ Params *Type // function params
+
+ Nname *Node
+
+ // Argwid is the total width of the function receiver, params, and results.
+ // It gets calculated via a temporary TFUNCARGS type.
+ // Note that TFUNC's Width is Widthptr.
Argwid int64
- // most nodes
- Type *Type // element type for TARRAY, TCHAN, TMAP, TPTRxx
- Width int64
+ Outnamed bool
+}
- // TSTRUCT
+// FuncType returns t's extra func-specific fields.
+func (t *Type) FuncType() *FuncType {
+ t.wantEtype(TFUNC)
+ return t.Extra.(*FuncType)
+}
+
+// InterMethType contains Type fields specific to interface method psuedo-types.
+type InterMethType struct {
+ Nname *Node
+}
+
+// StructType contains Type fields specific to struct types.
+type StructType struct {
fields Fields
- Down *Type // key type in TMAP; next struct in Funarg TSTRUCT
+ // Maps have three associated internal structs (see struct MapType).
+ // Map links such structs back to their map type.
+ Map *Type
- // TARRAY
- Bound int64 // negative is slice
+ Funarg bool // whether this struct represents function parameters
+ Haspointers uint8 // 0 unknown, 1 no, 2 yes
+}
- // TMAP
- Bucket *Type // internal type representing a hash bucket
- Hmap *Type // internal type representing a Hmap (map header object)
- Hiter *Type // internal type representing hash iterator state
- Map *Type // link from the above 3 internal types back to the map type.
+// StructType returns t's extra struct-specific fields.
+func (t *Type) StructType() *StructType {
+ t.wantEtype(TSTRUCT)
+ return t.Extra.(*StructType)
+}
- Maplineno int32 // first use of TFORW as map key
- Embedlineno int32 // first use of TFORW as embedded type
+// InterType contains Type fields specific to interface types.
+type InterType struct {
+ fields Fields
+}
+
+// PtrType contains Type fields specific to pointer types.
+type PtrType struct {
+ Elem *Type // element type
+}
+
+// DDDFieldType contains Type fields specific to TDDDFIELD types.
+type DDDFieldType struct {
+ T *Type // reference to a slice type for ... args
+}
+
+// ChanArgsType contains Type fields specific to TCHANARGS types.
+type ChanArgsType struct {
+ T *Type // reference to a chan type whose elements need a width check
+}
- // for TFORW, where to copy the eventual value to
- Copyto []*Node
+// // FuncArgsType contains Type fields specific to TFUNCARGS types.
+type FuncArgsType struct {
+ T *Type // reference to a func type whose elements need a width check
+}
+
+// ChanType contains Type fields specific to channel types.
+type ChanType struct {
+ Elem *Type // element type
+ Dir ChanDir // channel direction
+}
+
+// ChanType returns t's extra channel-specific fields.
+func (t *Type) ChanType() *ChanType {
+ t.wantEtype(TCHAN)
+ return t.Extra.(*ChanType)
+}
+
+// ArrayType contains Type fields specific to array types.
+type ArrayType struct {
+ Elem *Type // element type
+ Bound int64 // number of elements; <0 if unknown yet
+ Haspointers uint8 // 0 unknown, 1 no, 2 yes
+}
+
+// SliceType contains Type fields specific to slice types.
+type SliceType struct {
+ Elem *Type // element type
}
// A Field represents a field in a struct or a method in an interface or
@@ -177,7 +300,7 @@ type Field struct {
// or interface Type.
Offset int64
- Note *string // literal string annotation
+ Note string // literal string annotation
}
// End returns the offset of the first byte immediately after this field.
@@ -209,6 +332,12 @@ func (f *Fields) Slice() []*Field {
return *f.s
}
+// Index returns the i'th element of Fields.
+// It panics if f does not have at least i+1 elements.
+func (f *Fields) Index(i int) *Field {
+ return (*f.s)[i]
+}
+
// Set sets f to a slice.
// This takes ownership of the slice.
func (f *Fields) Set(s []*Field) {
@@ -238,71 +367,103 @@ func typ(et EType) *Type {
Lineno: lineno,
}
t.Orig = t
+ // TODO(josharian): lazily initialize some of these?
+ switch t.Etype {
+ case TMAP:
+ t.Extra = new(MapType)
+ case TFORW:
+ t.Extra = new(ForwardType)
+ case TFUNC:
+ t.Extra = new(FuncType)
+ case TINTERMETH:
+ t.Extra = InterMethType{}
+ case TSTRUCT:
+ t.Extra = new(StructType)
+ case TINTER:
+ t.Extra = new(InterType)
+ case TPTR32, TPTR64:
+ t.Extra = PtrType{}
+ case TCHANARGS:
+ t.Extra = ChanArgsType{}
+ case TFUNCARGS:
+ t.Extra = FuncArgsType{}
+ case TDDDFIELD:
+ t.Extra = DDDFieldType{}
+ case TCHAN:
+ t.Extra = new(ChanType)
+ }
return t
}
// typArray returns a new fixed-length array Type.
func typArray(elem *Type, bound int64) *Type {
+ if bound < 0 {
+ Fatalf("typArray: invalid bound %v", bound)
+ }
t := typ(TARRAY)
- t.Type = elem
- t.Bound = bound
+ t.Extra = &ArrayType{Elem: elem, Bound: bound}
return t
}
// typSlice returns a new slice Type.
func typSlice(elem *Type) *Type {
- t := typ(TARRAY)
- t.Type = elem
- t.Bound = sliceBound
+ t := typ(TSLICE)
+ t.Extra = SliceType{Elem: elem}
return t
}
// typDDDArray returns a new [...]T array Type.
func typDDDArray(elem *Type) *Type {
t := typ(TARRAY)
- t.Type = elem
- t.Bound = dddBound
+ t.Extra = &ArrayType{Elem: elem, Bound: -1}
return t
}
// typChan returns a new chan Type with direction dir.
func typChan(elem *Type, dir ChanDir) *Type {
t := typ(TCHAN)
- t.Type = elem
- t.Chan = dir
+ ct := t.ChanType()
+ ct.Elem = elem
+ ct.Dir = dir
return t
}
// typMap returns a new map Type with key type k and element (aka value) type v.
func typMap(k, v *Type) *Type {
- if k != nil {
- checkMapKeyType(k)
- }
-
t := typ(TMAP)
- t.Down = k
- t.Type = v
+ mt := t.MapType()
+ mt.Key = k
+ mt.Val = v
return t
}
// typPtr returns a new pointer type pointing to t.
func typPtr(elem *Type) *Type {
t := typ(Tptr)
- t.Type = elem
+ t.Extra = PtrType{Elem: elem}
t.Width = int64(Widthptr)
t.Align = uint8(Widthptr)
return t
}
-// typWrapper returns a new wrapper psuedo-type.
-func typWrapper(et EType, wrapped *Type) *Type {
- switch et {
- case TCHANARGS, TFUNCARGS, TDDDFIELD:
- default:
- Fatalf("typWrapper bad etype %s", et)
- }
- t := typ(et)
- t.Type = wrapped
+// typDDDField returns a new TDDDFIELD type for slice type s.
+func typDDDField(s *Type) *Type {
+ t := typ(TDDDFIELD)
+ t.Extra = DDDFieldType{T: s}
+ return t
+}
+
+// typChanArgs returns a new TCHANARGS type for channel type c.
+func typChanArgs(c *Type) *Type {
+ t := typ(TCHANARGS)
+ t.Extra = ChanArgsType{T: c}
+ return t
+}
+
+// typFuncArgs returns a new TFUNCARGS type for func type f.
+func typFuncArgs(f *Type) *Type {
+ t := typ(TFUNCARGS)
+ t.Extra = FuncArgsType{T: f}
return t
}
@@ -348,20 +509,41 @@ func substAny(t *Type, types *[]*Type) *Type {
t = (*types)[0]
*types = (*types)[1:]
- case TPTR32, TPTR64, TCHAN, TARRAY:
- elem := substAny(t.Type, types)
- if elem != t.Type {
+ case TPTR32, TPTR64:
+ elem := substAny(t.Elem(), types)
+ if elem != t.Elem() {
t = t.Copy()
- t.Type = elem
+ t.Extra = PtrType{Elem: elem}
+ }
+
+ case TARRAY:
+ elem := substAny(t.Elem(), types)
+ if elem != t.Elem() {
+ t = t.Copy()
+ t.Extra.(*ArrayType).Elem = elem
+ }
+
+ case TSLICE:
+ elem := substAny(t.Elem(), types)
+ if elem != t.Elem() {
+ t = t.Copy()
+ t.Extra = SliceType{Elem: elem}
+ }
+
+ case TCHAN:
+ elem := substAny(t.Elem(), types)
+ if elem != t.Elem() {
+ t = t.Copy()
+ t.Extra.(*ChanType).Elem = elem
}
case TMAP:
- key := substAny(t.Down, types)
- val := substAny(t.Type, types)
- if key != t.Down || val != t.Type {
+ key := substAny(t.Key(), types)
+ val := substAny(t.Val(), types)
+ if key != t.Key() || val != t.Val() {
t = t.Copy()
- t.Down = key
- t.Type = val
+ t.Extra.(*MapType).Key = key
+ t.Extra.(*MapType).Val = val
}
case TFUNC:
@@ -412,6 +594,30 @@ func (t *Type) Copy() *Type {
return nil
}
nt := *t
+ // copy any *T Extra fields, to avoid aliasing
+ switch t.Etype {
+ case TMAP:
+ x := *t.Extra.(*MapType)
+ nt.Extra = &x
+ case TFORW:
+ x := *t.Extra.(*ForwardType)
+ nt.Extra = &x
+ case TFUNC:
+ x := *t.Extra.(*FuncType)
+ nt.Extra = &x
+ case TSTRUCT:
+ x := *t.Extra.(*StructType)
+ nt.Extra = &x
+ case TINTER:
+ x := *t.Extra.(*InterType)
+ nt.Extra = &x
+ case TCHAN:
+ x := *t.Extra.(*ChanType)
+ nt.Extra = &x
+ case TARRAY:
+ x := *t.Extra.(*ArrayType)
+ nt.Extra = &x
+ }
// TODO(mdempsky): Find out why this is necessary and explain.
if t.Orig == t {
nt.Orig = &nt
@@ -469,17 +675,17 @@ func (t *Type) wantEtype2(et1, et2 EType) {
func (t *Type) RecvsP() **Type {
t.wantEtype(TFUNC)
- return &t.Type
+ return &t.Extra.(*FuncType).Receiver
}
func (t *Type) ParamsP() **Type {
t.wantEtype(TFUNC)
- return &t.Type.Down.Down
+ return &t.Extra.(*FuncType).Params
}
func (t *Type) ResultsP() **Type {
t.wantEtype(TFUNC)
- return &t.Type.Down
+ return &t.Extra.(*FuncType).Results
}
func (t *Type) Recvs() *Type { return *t.RecvsP() }
@@ -510,46 +716,77 @@ var paramsResults = [2]func(*Type) *Type{
// Key returns the key type of map type t.
func (t *Type) Key() *Type {
t.wantEtype(TMAP)
- return t.Down
+ return t.Extra.(*MapType).Key
}
// Val returns the value type of map type t.
func (t *Type) Val() *Type {
t.wantEtype(TMAP)
- return t.Type
+ return t.Extra.(*MapType).Val
}
// Elem returns the type of elements of t.
// Usable with pointers, channels, arrays, and slices.
func (t *Type) Elem() *Type {
switch t.Etype {
- case TPTR32, TPTR64, TCHAN, TARRAY:
- default:
- Fatalf("Type.Elem %s", t.Etype)
+ case TPTR32, TPTR64:
+ return t.Extra.(PtrType).Elem
+ case TARRAY:
+ return t.Extra.(*ArrayType).Elem
+ case TSLICE:
+ return t.Extra.(SliceType).Elem
+ case TCHAN:
+ return t.Extra.(*ChanType).Elem
}
- return t.Type
+ Fatalf("Type.Elem %s", t.Etype)
+ return nil
}
-// Wrapped returns the type that pseudo-type t wraps.
-func (t *Type) Wrapped() *Type {
- switch t.Etype {
- case TCHANARGS, TFUNCARGS, TDDDFIELD:
- default:
- Fatalf("Type.Wrapped %s", t.Etype)
- }
- return t.Type
+// DDDField returns the slice ... type for TDDDFIELD type t.
+func (t *Type) DDDField() *Type {
+ t.wantEtype(TDDDFIELD)
+ return t.Extra.(DDDFieldType).T
+}
+
+// ChanArgs returns the channel type for TCHANARGS type t.
+func (t *Type) ChanArgs() *Type {
+ t.wantEtype(TCHANARGS)
+ return t.Extra.(ChanArgsType).T
+}
+
+// FuncArgs returns the channel type for TFUNCARGS type t.
+func (t *Type) FuncArgs() *Type {
+ t.wantEtype(TFUNCARGS)
+ return t.Extra.(FuncArgsType).T
}
// Nname returns the associated function's nname.
func (t *Type) Nname() *Node {
- t.wantEtype2(TFUNC, TINTERMETH)
- return t.nname
+ switch t.Etype {
+ case TFUNC:
+ return t.Extra.(*FuncType).Nname
+ case TINTERMETH:
+ return t.Extra.(InterMethType).Nname
+ }
+ Fatalf("Type.Nname %v %v", t.Etype, t)
+ return nil
}
// Nname sets the associated function's nname.
func (t *Type) SetNname(n *Node) {
- t.wantEtype2(TFUNC, TINTERMETH)
- t.nname = n
+ switch t.Etype {
+ case TFUNC:
+ t.Extra.(*FuncType).Nname = n
+ case TINTERMETH:
+ t.Extra = InterMethType{Nname: n}
+ default:
+ Fatalf("Type.SetNname %v %v", t.Etype, t)
+ }
+}
+
+// IsFuncArgStruct reports whether t is a struct representing function parameters.
+func (t *Type) IsFuncArgStruct() bool {
+ return t.Etype == TSTRUCT && t.Extra.(*StructType).Funarg
}
func (t *Type) Methods() *Fields {
@@ -563,10 +800,14 @@ func (t *Type) AllMethods() *Fields {
}
func (t *Type) Fields() *Fields {
- if t.Etype != TSTRUCT && t.Etype != TINTER {
- Fatalf("Fields: type %v does not have fields", t)
+ switch t.Etype {
+ case TSTRUCT:
+ return &t.Extra.(*StructType).fields
+ case TINTER:
+ return &t.Extra.(*InterType).fields
}
- return &t.fields
+ Fatalf("Fields: type %v does not have fields", t)
+ return nil
}
// Field returns the i'th field/method of struct/interface type t.
@@ -589,15 +830,14 @@ func (t *Type) isDDDArray() bool {
if t.Etype != TARRAY {
return false
}
- t.checkBound()
- return t.Bound == dddBound
+ return t.Extra.(*ArrayType).Bound < 0
}
// ArgWidth returns the total aligned argument size for a function.
// It includes the receiver, parameters, and results.
func (t *Type) ArgWidth() int64 {
t.wantEtype(TFUNC)
- return t.Argwid
+ return t.Extra.(*FuncType).Argwid
}
func (t *Type) Size() int64 {
@@ -611,22 +851,15 @@ func (t *Type) Alignment() int64 {
}
func (t *Type) SimpleString() string {
- return Econv(t.Etype)
-}
-
-func (t *Type) Equal(u ssa.Type) bool {
- x, ok := u.(*Type)
- return ok && Eqtype(t, x)
+ return t.Etype.String()
}
// Compare compares types for purposes of the SSA back
// end, returning an ssa.Cmp (one of CMPlt, CMPeq, CMPgt).
// The answers are correct for an optimizer
-// or code generator, but not for Go source.
-// For example, "type gcDrainFlags int" results in
-// two Go-different types that Compare equal.
-// The order chosen is also arbitrary, only division into
-// equivalence classes (Types that compare CMPeq) matters.
+// or code generator, but not necessarily typechecking.
+// The order chosen is arbitrary, only consistency and division
+// into equivalence classes (Types that compare CMPeq) matters.
func (t *Type) Compare(u ssa.Type) ssa.Cmp {
x, ok := u.(*Type)
// ssa.CompilerType is smaller than gc.Type
@@ -740,25 +973,25 @@ func (t *Type) cmp(x *Type) ssa.Cmp {
}
return t.Val().cmp(x.Val())
- case TPTR32, TPTR64:
- // No special cases for these two, they are handled
+ case TPTR32, TPTR64, TSLICE:
+ // No special cases for these, they are handled
// by the general code after the switch.
case TSTRUCT:
- if t.Map == nil {
- if x.Map != nil {
+ if t.StructType().Map == nil {
+ if x.StructType().Map != nil {
return ssa.CMPlt // nil < non-nil
}
// to the fallthrough
- } else if x.Map == nil {
+ } else if x.StructType().Map == nil {
return ssa.CMPgt // nil > non-nil
- } else if t.Map.Bucket == t {
+ } else if t.StructType().Map.MapType().Bucket == t {
// Both have non-nil Map
// Special case for Maps which include a recursive type where the recursion is not broken with a named type
- if x.Map.Bucket != x {
+ if x.StructType().Map.MapType().Bucket != x {
return ssa.CMPlt // bucket maps are least
}
- return t.Map.cmp(x.Map)
+ return t.StructType().Map.cmp(x.StructType().Map)
} // If t != t.Map.Bucket, fall through to general case
fallthrough
@@ -770,15 +1003,7 @@ func (t *Type) cmp(x *Type) ssa.Cmp {
return cmpForNe(t1.Embedded < x1.Embedded)
}
if t1.Note != x1.Note {
- if t1.Note == nil {
- return ssa.CMPlt
- }
- if x1.Note == nil {
- return ssa.CMPgt
- }
- if *t1.Note != *x1.Note {
- return cmpForNe(*t1.Note < *x1.Note)
- }
+ return cmpForNe(t1.Note < x1.Note)
}
if c := t1.Sym.cmpsym(x1.Sym); c != ssa.CMPeq {
return c
@@ -826,7 +1051,7 @@ func (t *Type) cmp(x *Type) ssa.Cmp {
panic(e)
}
- // Common element type comparison for TARRAY, TCHAN, TPTR32, and TPTR64.
+ // Common element type comparison for TARRAY, TCHAN, TPTR32, TPTR64, and TSLICE.
return t.Elem().cmp(x.Elem())
}
@@ -869,6 +1094,11 @@ func (t *Type) IsPtr() bool {
return t.Etype == TPTR32 || t.Etype == TPTR64
}
+// IsUnsafePtr reports whether t is an unsafe pointer.
+func (t *Type) IsUnsafePtr() bool {
+ return t.Etype == TUNSAFEPTR
+}
+
// IsPtrShaped reports whether t is represented by a single machine pointer.
// In addition to regular Go pointer types, this includes map, channel, and
// function types and unsafe.Pointer. It does not include array or struct types
@@ -891,21 +1121,12 @@ func (t *Type) IsChan() bool {
return t.Etype == TCHAN
}
-// checkBound enforces that Bound has an acceptable value.
-func (t *Type) checkBound() {
- if t.Bound != sliceBound && t.Bound < 0 && t.Bound != dddBound {
- Fatalf("bad TARRAY bounds %d %s", t.Bound, t)
- }
-}
-
func (t *Type) IsSlice() bool {
- t.checkBound()
- return t.Etype == TARRAY && t.Bound == sliceBound
+ return t.Etype == TSLICE
}
func (t *Type) IsArray() bool {
- t.checkBound()
- return t.Etype == TARRAY && t.Bound >= 0
+ return t.Etype == TARRAY
}
func (t *Type) IsStruct() bool {
@@ -939,27 +1160,36 @@ func (t *Type) FieldType(i int) ssa.Type {
func (t *Type) FieldOff(i int) int64 {
return t.Field(i).Offset
}
+func (t *Type) FieldName(i int) string {
+ return t.Field(i).Sym.Name
+}
func (t *Type) NumElem() int64 {
t.wantEtype(TARRAY)
- t.checkBound()
- return t.Bound
+ at := t.Extra.(*ArrayType)
+ if at.Bound < 0 {
+ Fatalf("NumElem array %v does not have bound yet", t)
+ }
+ return at.Bound
}
// SetNumElem sets the number of elements in an array type.
-// It should not be used if at all possible.
-// Create a new array/slice/dddArray with typX instead.
-// TODO(josharian): figure out how to get rid of this.
+// The only allowed use is on array types created with typDDDArray.
+// For other uses, create a new array with typArray instead.
func (t *Type) SetNumElem(n int64) {
t.wantEtype(TARRAY)
- t.Bound = n
+ at := t.Extra.(*ArrayType)
+ if at.Bound >= 0 {
+ Fatalf("SetNumElem array %v already has bound %d", t, at.Bound)
+ }
+ at.Bound = n
}
// ChanDir returns the direction of a channel type t.
// The direction will be one of Crecv, Csend, or Cboth.
func (t *Type) ChanDir() ChanDir {
t.wantEtype(TCHAN)
- return t.Chan
+ return t.Extra.(*ChanType).Dir
}
func (t *Type) IsMemory() bool { return false }
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 688936e926..cf44ac8678 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -11,6 +11,16 @@ import (
"strings"
)
+const (
+ Etop = 1 << iota // evaluated at statement level
+ Erv // evaluated in value context
+ Etype // evaluated in type context
+ Ecall // call-only expressions are ok
+ Efnstruct // multivalue function returns are ok
+ Easgn // assigning to expression
+ Ecomplit // type in composite literal
+)
+
// type check the whole tree of an expression.
// calculates expression types.
// evaluates compile time constants.
@@ -66,6 +76,7 @@ var _typekind = []string{
TCHAN: "chan",
TMAP: "map",
TARRAY: "array",
+ TSLICE: "slice",
TFUNC: "func",
TNIL: "nil",
TIDEAL: "untyped number",
@@ -267,7 +278,7 @@ OpSwitch:
default:
Dump("typecheck", n)
- Fatalf("typecheck %v", Oconv(n.Op, 0))
+ Fatalf("typecheck %v", n.Op)
// names
case OLITERAL:
@@ -324,7 +335,6 @@ OpSwitch:
ok |= Etype
if n.Type == nil {
- n.Type = nil
return n
}
@@ -403,6 +413,18 @@ OpSwitch:
}
n.Op = OTYPE
n.Type = typMap(l.Type, r.Type)
+
+ // map key validation
+ alg, bad := algtype1(l.Type)
+ if alg == ANOEQ {
+ if bad.Etype == TFORW {
+ // queue check for map until all the types are done settling.
+ mapqueue = append(mapqueue, mapqueueval{l, n.Lineno})
+ } else if bad.Etype != TANY {
+ // no need to queue, key is already bad
+ Yyerror("invalid map key type %v", l.Type)
+ }
+ }
n.Left = nil
n.Right = nil
@@ -435,7 +457,6 @@ OpSwitch:
n.Op = OTYPE
n.Type = tointerface(n.List.Slice())
if n.Type == nil {
- n.Type = nil
return n
}
@@ -444,7 +465,6 @@ OpSwitch:
n.Op = OTYPE
n.Type = functype(n.Left, n.List.Slice(), n.Rlist.Slice())
if n.Type == nil {
- n.Type = nil
return n
}
n.Left = nil
@@ -453,13 +473,7 @@ OpSwitch:
// type or expr
case OIND:
- ntop := Erv | Etype
-
- if top&Eaddr == 0 { // The *x in &*x is not an indirect.
- ntop |= Eindir
- }
- ntop |= top & Ecomplit
- n.Left = typecheck(n.Left, ntop)
+ n.Left = typecheck(n.Left, Erv|Etype|top&Ecomplit)
l := n.Left
t := l.Type
if t == nil {
@@ -533,8 +547,8 @@ OpSwitch:
op = Op(n.Etype)
} else {
ok |= Erv
- n.Left = typecheck(n.Left, Erv|top&Eiota)
- n.Right = typecheck(n.Right, Erv|top&Eiota)
+ n.Left = typecheck(n.Left, Erv)
+ n.Right = typecheck(n.Right, Erv)
l = n.Left
r = n.Right
if l.Type == nil || r.Type == nil {
@@ -597,7 +611,7 @@ OpSwitch:
aop = assignop(l.Type, r.Type, nil)
if aop != 0 {
if r.Type.IsInterface() && !l.Type.IsInterface() && !l.Type.IsComparable() {
- Yyerror("invalid operation: %v (operator %v not defined on %s)", n, Oconv(op, 0), typekind(l.Type))
+ Yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type))
n.Type = nil
return n
}
@@ -619,7 +633,7 @@ OpSwitch:
aop = assignop(r.Type, l.Type, nil)
if aop != 0 {
if l.Type.IsInterface() && !r.Type.IsInterface() && !r.Type.IsComparable() {
- Yyerror("invalid operation: %v (operator %v not defined on %s)", n, Oconv(op, 0), typekind(r.Type))
+ Yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type))
n.Type = nil
return n
}
@@ -650,7 +664,7 @@ OpSwitch:
}
if !okfor[op][et] {
- Yyerror("invalid operation: %v (operator %v not defined on %s)", n, Oconv(op, 0), typekind(t))
+ Yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t))
n.Type = nil
return n
}
@@ -752,7 +766,7 @@ OpSwitch:
case OCOM, OMINUS, ONOT, OPLUS:
ok |= Erv
- n.Left = typecheck(n.Left, Erv|top&Eiota)
+ n.Left = typecheck(n.Left, Erv)
l := n.Left
t := l.Type
if t == nil {
@@ -760,7 +774,7 @@ OpSwitch:
return n
}
if !okfor[n.Op][t.Etype] {
- Yyerror("invalid operation: %v %v", Oconv(n.Op, 0), t)
+ Yyerror("invalid operation: %v %v", n.Op, t)
n.Type = nil
return n
}
@@ -772,7 +786,7 @@ OpSwitch:
case OADDR:
ok |= Erv
- n.Left = typecheck(n.Left, Erv|Eaddr)
+ n.Left = typecheck(n.Left, Erv)
if n.Left.Type == nil {
n.Type = nil
return n
@@ -808,7 +822,6 @@ OpSwitch:
ok |= Erv
n = typecheckcomplit(n)
if n.Type == nil {
- n.Type = nil
return n
}
break OpSwitch
@@ -850,7 +863,6 @@ OpSwitch:
if n.Type.Etype != TFUNC || n.Type.Recv() == nil {
Yyerror("type %v has no method %v", n.Left.Type, Sconv(n.Right.Sym, FmtShort))
n.Type = nil
- n.Type = nil
return n
}
@@ -986,7 +998,7 @@ OpSwitch:
n.Type = nil
return n
- case TSTRING, TARRAY:
+ case TSTRING, TARRAY, TSLICE:
n.Right = indexlit(n.Right)
if t.IsString() {
n.Type = bytetype
@@ -994,12 +1006,10 @@ OpSwitch:
n.Type = t.Elem()
}
why := "string"
- if t.Etype == TARRAY {
- if t.IsArray() {
- why = "array"
- } else {
- why = "slice"
- }
+ if t.IsArray() {
+ why = "array"
+ } else if t.IsSlice() {
+ why = "slice"
}
if n.Right.Type != nil && !n.Right.Type.IsInteger() {
@@ -1095,14 +1105,19 @@ OpSwitch:
n.Type = nil
break OpSwitch
- case OSLICE:
+ case OSLICE, OSLICE3:
ok |= Erv
n.Left = typecheck(n.Left, top)
- n.Right.Left = typecheck(n.Right.Left, Erv)
- n.Right.Right = typecheck(n.Right.Right, Erv)
+ low, high, max := n.SliceBounds()
+ hasmax := n.Op.IsSlice3()
+ low = typecheck(low, Erv)
+ high = typecheck(high, Erv)
+ max = typecheck(max, Erv)
n.Left = defaultlit(n.Left, nil)
- n.Right.Left = indexlit(n.Right.Left)
- n.Right.Right = indexlit(n.Right.Right)
+ low = indexlit(low)
+ high = indexlit(high)
+ max = indexlit(max)
+ n.SetSliceBounds(low, high, max)
l := n.Left
if l.Type.IsArray() {
if !islvalue(n.Left) {
@@ -1124,78 +1139,22 @@ OpSwitch:
}
var tp *Type
if t.IsString() {
+ if hasmax {
+ Yyerror("invalid operation %v (3-index slice of string)", n)
+ n.Type = nil
+ return n
+ }
n.Type = t
n.Op = OSLICESTR
} else if t.IsPtr() && t.Elem().IsArray() {
tp = t.Elem()
n.Type = typSlice(tp.Elem())
dowidth(n.Type)
- n.Op = OSLICEARR
- } else if t.IsSlice() {
- n.Type = t
- } else {
- Yyerror("cannot slice %v (type %v)", l, t)
- n.Type = nil
- return n
- }
-
- lo := n.Right.Left
- if lo != nil && !checksliceindex(l, lo, tp) {
- n.Type = nil
- return n
- }
- hi := n.Right.Right
- if hi != nil && !checksliceindex(l, hi, tp) {
- n.Type = nil
- return n
- }
- if !checksliceconst(lo, hi) {
- n.Type = nil
- return n
- }
- break OpSwitch
-
- case OSLICE3:
- ok |= Erv
- n.Left = typecheck(n.Left, top)
- n.Right.Left = typecheck(n.Right.Left, Erv)
- n.Right.Right.Left = typecheck(n.Right.Right.Left, Erv)
- n.Right.Right.Right = typecheck(n.Right.Right.Right, Erv)
- n.Left = defaultlit(n.Left, nil)
- n.Right.Left = indexlit(n.Right.Left)
- n.Right.Right.Left = indexlit(n.Right.Right.Left)
- n.Right.Right.Right = indexlit(n.Right.Right.Right)
- l := n.Left
- if l.Type.IsArray() {
- if !islvalue(n.Left) {
- Yyerror("invalid operation %v (slice of unaddressable value)", n)
- n.Type = nil
- return n
+ if hasmax {
+ n.Op = OSLICE3ARR
+ } else {
+ n.Op = OSLICEARR
}
-
- n.Left = Nod(OADDR, n.Left, nil)
- n.Left.Implicit = true
- n.Left = typecheck(n.Left, Erv)
- l = n.Left
- }
-
- t := l.Type
- if t == nil {
- n.Type = nil
- return n
- }
- if t.IsString() {
- Yyerror("invalid operation %v (3-index slice of string)", n)
- n.Type = nil
- return n
- }
-
- var tp *Type
- if t.IsPtr() && t.Elem().IsArray() {
- tp = t.Elem()
- n.Type = typSlice(tp.Elem())
- dowidth(n.Type)
- n.Op = OSLICE3ARR
} else if t.IsSlice() {
n.Type = t
} else {
@@ -1204,22 +1163,19 @@ OpSwitch:
return n
}
- lo := n.Right.Left
- if lo != nil && !checksliceindex(l, lo, tp) {
+ if low != nil && !checksliceindex(l, low, tp) {
n.Type = nil
return n
}
- mid := n.Right.Right.Left
- if mid != nil && !checksliceindex(l, mid, tp) {
+ if high != nil && !checksliceindex(l, high, tp) {
n.Type = nil
return n
}
- hi := n.Right.Right.Right
- if hi != nil && !checksliceindex(l, hi, tp) {
+ if max != nil && !checksliceindex(l, max, tp) {
n.Type = nil
return n
}
- if !checksliceconst(lo, hi) || !checksliceconst(lo, mid) || !checksliceconst(mid, hi) {
+ if !checksliceconst(low, high) || !checksliceconst(low, max) || !checksliceconst(high, max) {
n.Type = nil
return n
}
@@ -1241,7 +1197,7 @@ OpSwitch:
}
}
- n.Left = typecheck(n.Left, Erv|Etype|Ecall|top&Eproc)
+ n.Left = typecheck(n.Left, Erv|Etype|Ecall)
n.Diag |= n.Left.Diag
l = n.Left
if l.Op == ONAME && l.Etype != 0 {
@@ -1333,7 +1289,7 @@ OpSwitch:
if t.Results().NumFields() == 1 {
n.Type = l.Type.Results().Field(0).Type
- if n.Op == OCALLFUNC && n.Left.Op == ONAME && (compiling_runtime != 0 || n.Left.Sym.Pkg == Runtimepkg) && n.Left.Sym.Name == "getg" {
+ if n.Op == OCALLFUNC && n.Left.Op == ONAME && (compiling_runtime || n.Left.Sym.Pkg == Runtimepkg) && n.Left.Sym.Name == "getg" {
// Emit code for runtime.getg() directly instead of calling function.
// Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
// so that the ordering pass can make sure to preserve the semantics of the original code
@@ -1358,7 +1314,7 @@ OpSwitch:
case OCAP, OLEN, OREAL, OIMAG:
ok |= Erv
- if !onearg(n, "%v", Oconv(n.Op, 0)) {
+ if !onearg(n, "%v", n.Op) {
n.Type = nil
return n
}
@@ -1411,9 +1367,6 @@ OpSwitch:
}
case TARRAY:
- if t.IsSlice() {
- break
- }
if callrecv(l) { // has call or receive
break
}
@@ -1427,7 +1380,7 @@ OpSwitch:
break OpSwitch
badcall1:
- Yyerror("invalid argument %v for %v", Nconv(n.Left, FmtLong), Oconv(n.Op, 0))
+ Yyerror("invalid argument %v for %v", Nconv(n.Left, FmtLong), n.Op)
n.Type = nil
return n
@@ -1458,8 +1411,8 @@ OpSwitch:
n.Type = nil
return n
}
- n.Left = typecheck(n.Left, Erv|top&Eiota)
- n.Right = typecheck(n.Right, Erv|top&Eiota)
+ n.Left = typecheck(n.Left, Erv)
+ n.Right = typecheck(n.Right, Erv)
l = n.Left
r = n.Right
if l.Type == nil || r.Type == nil {
@@ -1510,7 +1463,7 @@ OpSwitch:
break OpSwitch
case OCLOSE:
- if !onearg(n, "%v", Oconv(n.Op, 0)) {
+ if !onearg(n, "%v", n.Op) {
n.Type = nil
return n
}
@@ -1593,7 +1546,7 @@ OpSwitch:
// Unpack multiple-return result before type-checking.
var funarg *Type
- if t.IsStruct() && t.Funarg {
+ if t.IsFuncArgStruct() {
funarg = t
t = t.Field(0).Type
}
@@ -1717,7 +1670,7 @@ OpSwitch:
case OCONV:
ok |= Erv
saveorignode(n)
- n.Left = typecheck(n.Left, Erv|top&(Eindir|Eiota))
+ n.Left = typecheck(n.Left, Erv)
n.Left = convlit1(n.Left, n.Type, true, noReuse)
t := n.Left.Type
if t == nil || n.Type == nil {
@@ -1784,13 +1737,7 @@ OpSwitch:
n.Type = nil
return n
- case TARRAY:
- if !t.IsSlice() {
- Yyerror("cannot make type %v", t)
- n.Type = nil
- return n
- }
-
+ case TSLICE:
if i >= len(args) {
Yyerror("missing len argument to make(%v)", t)
n.Type = nil
@@ -1905,7 +1852,7 @@ OpSwitch:
case OPRINT, OPRINTN:
ok |= Etop
- typecheckslice(n.List.Slice(), Erv|Eindir) // Eindir: address does not escape
+ typecheckslice(n.List.Slice(), Erv)
ls := n.List.Slice()
for i1, n1 := range ls {
// Special case for print: int constant is int64, not int.
@@ -1947,7 +1894,6 @@ OpSwitch:
ok |= Erv
typecheckclosure(n, top)
if n.Type == nil {
- n.Type = nil
return n
}
break OpSwitch
@@ -2042,7 +1988,7 @@ OpSwitch:
case OPROC:
ok |= Etop
- n.Left = typecheck(n.Left, Etop|Eproc|Erv)
+ n.Left = typecheck(n.Left, Etop|Erv)
checkdefergo(n)
break OpSwitch
@@ -2089,7 +2035,7 @@ OpSwitch:
return n
}
- if Curfn.Type.Outnamed && n.List.Len() == 0 {
+ if Curfn.Type.FuncType().Outnamed && n.List.Len() == 0 {
break OpSwitch
}
typecheckaste(ORETURN, nil, false, Curfn.Type.Results(), n.List, func() string { return "return argument" })
@@ -2145,14 +2091,10 @@ OpSwitch:
}
t := n.Type
- if t != nil && !t.Funarg && n.Op != OTYPE {
+ if t != nil && !t.IsFuncArgStruct() && n.Op != OTYPE {
switch t.Etype {
- case TFUNC, // might have TANY; wait until its called
- TANY,
- TFORW,
- TIDEAL,
- TNIL,
- TBLANK:
+ case TFUNC, // might have TANY; wait until it's called
+ TANY, TFORW, TIDEAL, TNIL, TBLANK:
break
default:
@@ -2160,7 +2102,7 @@ OpSwitch:
}
}
- if safemode != 0 && incannedimport == 0 && importpkg == nil && compiling_wrappers == 0 && t != nil && t.Etype == TUNSAFEPTR {
+ if safemode && incannedimport == 0 && importpkg == nil && compiling_wrappers == 0 && t != nil && t.Etype == TUNSAFEPTR {
Yyerror("cannot use unsafe.Pointer")
}
@@ -2342,19 +2284,19 @@ func twoarg(n *Node) bool {
return true
}
if n.List.Len() == 0 {
- Yyerror("missing argument to %v - %v", Oconv(n.Op, 0), n)
+ Yyerror("missing argument to %v - %v", n.Op, n)
return false
}
n.Left = n.List.First()
if n.List.Len() == 1 {
- Yyerror("missing argument to %v - %v", Oconv(n.Op, 0), n)
+ Yyerror("missing argument to %v - %v", n.Op, n)
n.List.Set(nil)
return false
}
if n.List.Len() > 2 {
- Yyerror("too many arguments to %v - %v", Oconv(n.Op, 0), n)
+ Yyerror("too many arguments to %v - %v", n.Op, n)
n.List.Set(nil)
return false
}
@@ -2597,7 +2539,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc
if nl.Len() == 1 {
n = nl.First()
if n.Type != nil {
- if n.Type.IsStruct() && n.Type.Funarg {
+ if n.Type.IsFuncArgStruct() {
if !hasddd(tstruct) {
n1 := tstruct.NumFields()
n2 := n.Type.NumFields()
@@ -2720,7 +2662,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc
if call != nil {
Yyerror("invalid use of ... in call to %v", call)
} else {
- Yyerror("invalid use of ... in %v", Oconv(op, 0))
+ Yyerror("invalid use of ... in %v", op)
}
}
@@ -2740,7 +2682,7 @@ notenough:
Yyerror("not enough arguments in call to %v", call)
}
} else {
- Yyerror("not enough arguments to %v", Oconv(op, 0))
+ Yyerror("not enough arguments to %v", op)
}
if n != nil {
n.Diag = 1
@@ -2753,7 +2695,7 @@ toomany:
if call != nil {
Yyerror("too many arguments in call to %v", call)
} else {
- Yyerror("too many arguments to %v", Oconv(op, 0))
+ Yyerror("too many arguments to %v", op)
}
goto out
}
@@ -2842,19 +2784,19 @@ func indexdup(n *Node, hash map[int64]*Node) {
hash[v] = n
}
+// iscomptype reports whether type t is a composite literal type
+// or a pointer to one.
func iscomptype(t *Type) bool {
+ if t.IsPtr() {
+ t = t.Elem()
+ }
+
switch t.Etype {
- case TARRAY, TSTRUCT, TMAP:
+ case TARRAY, TSLICE, TSTRUCT, TMAP:
return true
-
- case TPTR32, TPTR64:
- switch t.Elem().Etype {
- case TARRAY, TSTRUCT, TMAP:
- return true
- }
+ default:
+ return false
}
-
- return false
}
func pushtype(n *Node, t *Type) {
@@ -2937,7 +2879,7 @@ func typecheckcomplit(n *Node) *Node {
Yyerror("invalid type for composite literal: %v", t)
n.Type = nil
- case TARRAY:
+ case TARRAY, TSLICE:
// Only allocate hash if there are some key/value pairs.
var hash map[int64]*Node
for _, n1 := range n.List.Slice() {
@@ -2948,6 +2890,7 @@ func typecheckcomplit(n *Node) *Node {
}
length := int64(0)
i := 0
+ checkBounds := t.IsArray() && !t.isDDDArray()
for i2, n2 := range n.List.Slice() {
l := n2
setlineno(l)
@@ -2973,11 +2916,10 @@ func typecheckcomplit(n *Node) *Node {
i++
if int64(i) > length {
length = int64(i)
- if t.IsArray() && length > t.NumElem() {
+ if checkBounds && length > t.NumElem() {
setlineno(l)
Yyerror("array index %d out of bounds [0:%d]", length-1, t.NumElem())
- // suppress any further errors out of bounds errors for the same type by pretending it is a slice
- t.SetNumElem(sliceBound)
+ checkBounds = false
}
}
@@ -3083,7 +3025,12 @@ func typecheckcomplit(n *Node) *Node {
}
s := l.Left.Sym
- if s == nil {
+
+ // An OXDOT uses the Sym field to hold
+ // the field to the right of the dot,
+ // so s will be non-nil, but an OXDOT
+ // is never a valid struct literal key.
+ if s == nil || l.Left.Op == OXDOT {
Yyerror("invalid field name %v in struct initializer", l.Left)
l.Right = typecheck(l.Right, Erv)
continue
@@ -3152,8 +3099,6 @@ func islvalue(n *Node) bool {
return false
}
fallthrough
-
- // fall through
case OIND, ODOTPTR, OCLOSUREVAR, OPARAM:
return true
@@ -3345,7 +3290,7 @@ func typecheckas2(n *Node) {
}
switch r.Op {
case OCALLMETH, OCALLINTER, OCALLFUNC:
- if !r.Type.IsStruct() || !r.Type.Funarg {
+ if !r.Type.IsFuncArgStruct() {
break
}
cr = r.Type.NumFields()
@@ -3503,18 +3448,23 @@ func domethod(n *Node) {
checkwidth(n.Type)
}
-var mapqueue []*Node
+type mapqueueval struct {
+ n *Node
+ lno int32
+}
+
+// tracks the line numbers at which forward types are first used as map keys
+var mapqueue []mapqueueval
func copytype(n *Node, t *Type) {
if t.Etype == TFORW {
// This type isn't computed yet; when it is, update n.
- t.Copyto = append(t.Copyto, n)
+ t.ForwardType().Copyto = append(t.ForwardType().Copyto, n)
return
}
- maplineno := n.Type.Maplineno
- embedlineno := n.Type.Embedlineno
- l := n.Type.Copyto
+ embedlineno := n.Type.ForwardType().Embedlineno
+ l := n.Type.ForwardType().Copyto
// TODO(mdempsky): Fix Type rekinding.
*n.Type = *t
@@ -3530,7 +3480,6 @@ func copytype(n *Node, t *Type) {
t.Nod = nil
t.Printed = false
t.Deferwidth = false
- t.Copyto = nil
// Update nodes waiting on this type.
for _, n := range l {
@@ -3542,18 +3491,12 @@ func copytype(n *Node, t *Type) {
if embedlineno != 0 {
lineno = embedlineno
- if t.IsPtr() {
+ if t.IsPtr() || t.IsUnsafePtr() {
Yyerror("embedded type cannot be a pointer")
}
}
lineno = lno
-
- // Queue check for map until all the types are done settling.
- if maplineno != 0 {
- t.Maplineno = maplineno
- mapqueue = append(mapqueue, n)
- }
}
func typecheckdeftype(n *Node) {
@@ -3598,12 +3541,13 @@ ret:
domethod(n)
}
}
-
- for _, n := range mapqueue {
- lineno = n.Type.Maplineno
- checkMapKeyType(n.Type)
+ for _, e := range mapqueue {
+ lineno = e.lno
+ if !e.n.Type.IsComparable() {
+ Yyerror("invalid map key type %v", e.n.Type)
+ }
}
-
+ mapqueue = nil
lineno = lno
}
@@ -3662,7 +3606,7 @@ func typecheckdef(n *Node) *Node {
switch n.Op {
default:
- Fatalf("typecheckdef %v", Oconv(n.Op, 0))
+ Fatalf("typecheckdef %v", n.Op)
// not really syms
case OGOTO, OLABEL:
@@ -3687,7 +3631,7 @@ func typecheckdef(n *Node) *Node {
Yyerror("xxx")
}
- e = typecheck(e, Erv|Eiota)
+ e = typecheck(e, Erv)
if Isconst(e, CTNIL) {
Yyerror("const initializer cannot be nil")
goto ret
@@ -3858,11 +3802,8 @@ func markbreak(n *Node, implicit *Node) {
ORANGE:
implicit = n
fallthrough
-
- // fall through
default:
markbreak(n.Left, implicit)
-
markbreak(n.Right, implicit)
markbreaklist(n.Ninit, implicit)
markbreaklist(n.Nbody, implicit)
@@ -3958,7 +3899,7 @@ func (n *Node) isterminating() bool {
}
func checkreturn(fn *Node) {
- if fn.Type.Results().NumFields() != 0 && len(fn.Nbody.Slice()) != 0 {
+ if fn.Type.Results().NumFields() != 0 && fn.Nbody.Len() != 0 {
markbreaklist(fn.Nbody, nil)
if !fn.Nbody.isterminating() {
yyerrorl(fn.Func.Endlineno, "missing return at end of function")
diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go
index c2ba9c9a93..84df22502f 100644
--- a/src/cmd/compile/internal/gc/universe.go
+++ b/src/cmd/compile/internal/gc/universe.go
@@ -228,6 +228,7 @@ func typeinit() {
okforcap[TARRAY] = true
okforcap[TCHAN] = true
+ okforcap[TSLICE] = true
okforconst[TBOOL] = true
okforconst[TSTRING] = true
@@ -235,6 +236,7 @@ func typeinit() {
okforlen[TARRAY] = true
okforlen[TCHAN] = true
okforlen[TMAP] = true
+ okforlen[TSLICE] = true
okforlen[TSTRING] = true
okforeq[TPTR32] = true
@@ -246,8 +248,9 @@ func typeinit() {
okforeq[TBOOL] = true
okforeq[TMAP] = true // nil only; refined in typecheck
okforeq[TFUNC] = true // nil only; refined in typecheck
- okforeq[TARRAY] = true // nil slice only; refined in typecheck
- okforeq[TSTRUCT] = true // it's complicated; refined in typecheck
+ okforeq[TSLICE] = true // nil only; refined in typecheck
+ okforeq[TARRAY] = true // only if element type is comparable; refined in typecheck
+ okforeq[TSTRUCT] = true // only if all struct fields are comparable; refined in typecheck
okforcmp[TSTRING] = true
@@ -359,16 +362,16 @@ func lexinit1() {
// t = interface { Error() string }
rcvr := typ(TSTRUCT)
- rcvr.Funarg = true
+ rcvr.StructType().Funarg = true
field := newField()
field.Type = Ptrto(typ(TSTRUCT))
rcvr.SetFields([]*Field{field})
in := typ(TSTRUCT)
- in.Funarg = true
+ in.StructType().Funarg = true
out := typ(TSTRUCT)
- out.Funarg = true
+ out.StructType().Funarg = true
field = newField()
field.Type = Types[TSTRING]
out.SetFields([]*Field{field})
diff --git a/src/cmd/compile/internal/gc/unsafe.go b/src/cmd/compile/internal/gc/unsafe.go
index 338f3c0eae..5935cd98ff 100644
--- a/src/cmd/compile/internal/gc/unsafe.go
+++ b/src/cmd/compile/internal/gc/unsafe.go
@@ -9,7 +9,7 @@ func unsafenmagic(nn *Node) *Node {
fn := nn.Left
args := nn.List
- if safemode != 0 || fn == nil || fn.Op != ONAME {
+ if safemode || fn == nil || fn.Op != ONAME {
return nil
}
s := fn.Sym
@@ -82,7 +82,7 @@ func unsafenmagic(nn *Node) *Node {
v += r1.Xoffset
default:
Dump("unsafenmagic", r)
- Fatalf("impossible %v node after dot insertion", Oconv(r1.Op, FmtSharp))
+ Fatalf("impossible %v node after dot insertion", oconv(r1.Op, FmtSharp))
goto bad
}
}
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index b7edae5af4..6ec06453ef 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -6,6 +6,7 @@ package gc
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"fmt"
"strings"
)
@@ -69,7 +70,7 @@ func walk(fn *Node) {
}
heapmoves()
- if Debug['W'] != 0 && len(Curfn.Func.Enter.Slice()) > 0 {
+ if Debug['W'] != 0 && Curfn.Func.Enter.Len() > 0 {
s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
dumplist(s, Curfn.Func.Enter)
}
@@ -158,7 +159,7 @@ func walkstmt(n *Node) *Node {
if n.Op == ONAME {
Yyerror("%v is not a top level statement", n.Sym)
} else {
- Yyerror("%v is not a top level statement", Oconv(n.Op, 0))
+ Yyerror("%v is not a top level statement", n.Op)
}
Dump("nottop", n)
@@ -287,7 +288,7 @@ func walkstmt(n *Node) *Node {
if n.List.Len() == 0 {
break
}
- if (Curfn.Type.Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) {
+ if (Curfn.Type.FuncType().Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) {
// assign to the function out parameters,
// so that reorder3 can fix up conflicts
var rl []*Node
@@ -593,8 +594,7 @@ opswitch:
// for a struct containing a reflect.Value, which itself has
// an unexported field of type unsafe.Pointer.
old_safemode := safemode
-
- safemode = 0
+ safemode = false
n = walkcompare(n, init)
safemode = old_safemode
@@ -672,8 +672,7 @@ opswitch:
walkexprlist(n.List.Slice(), init)
if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
- switch Thearch.Thechar {
- case '5', '6', '7', '9':
+ if Thearch.LinkArch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
n.Op = OSQRT
n.Left = n.List.First()
n.List.Set(nil)
@@ -865,8 +864,14 @@ opswitch:
// a = *var
a := n.List.First()
- fn := mapfn(p, t)
- r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key)
+ if w := t.Val().Width; w <= 1024 { // 1024 must match ../../../../runtime/hashmap.go:maxZero
+ fn := mapfn(p, t)
+ r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key)
+ } else {
+ fn := mapfn("mapaccess2_fat", t)
+ z := zeroaddr(w)
+ r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key, z)
+ }
// mapaccess2* returns a typed bool, but due to spec changes,
// the boolean result of i.(T) is now untyped so we make it the
@@ -881,6 +886,7 @@ opswitch:
if !isblank(a) {
var_ := temp(Ptrto(t.Val()))
var_.Typecheck = 1
+ var_.NonNil = true // mapaccess always returns a non-nil pointer
n.List.SetIndex(0, var_)
n = walkexpr(n, init)
init.Append(n)
@@ -890,8 +896,6 @@ opswitch:
n = typecheck(n, Etop)
n = walkexpr(n, init)
- // TODO: ptr is always non-nil, so disable nil check for this OIND op.
-
case ODELETE:
init.AppendNodes(&n.Ninit)
map_ := n.List.First()
@@ -1056,7 +1060,7 @@ opswitch:
n = walkexpr(n, init)
case OCONV, OCONVNOP:
- if Thearch.Thechar == '5' {
+ if Thearch.LinkArch.Family == sys.ARM {
if n.Left.Type.IsFloat() {
if n.Type.Etype == TINT64 {
n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
@@ -1219,11 +1223,17 @@ opswitch:
// standard version takes key by reference.
// orderexpr made sure key is addressable.
key = Nod(OADDR, n.Right, nil)
-
p = "mapaccess1"
}
- n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key)
+ if w := t.Val().Width; w <= 1024 { // 1024 must match ../../../../runtime/hashmap.go:maxZero
+ n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key)
+ } else {
+ p = "mapaccess1_fat"
+ z := zeroaddr(w)
+ n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key, z)
+ }
+ n.NonNil = true // mapaccess always returns a non-nil pointer
n = Nod(OIND, n, nil)
n.Type = t.Val()
n.Typecheck = 1
@@ -1231,35 +1241,28 @@ opswitch:
case ORECV:
Fatalf("walkexpr ORECV") // should see inside OAS only
- case OSLICE, OSLICEARR, OSLICESTR:
- n.Left = walkexpr(n.Left, init)
- n.Right.Left = walkexpr(n.Right.Left, init)
- if n.Right.Left != nil && iszero(n.Right.Left) {
- // Reduce x[0:j] to x[:j].
- n.Right.Left = nil
- }
- n.Right.Right = walkexpr(n.Right.Right, init)
- n = reduceSlice(n)
-
- case OSLICE3, OSLICE3ARR:
+ case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
n.Left = walkexpr(n.Left, init)
- n.Right.Left = walkexpr(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
+ low, high, max := n.SliceBounds()
+ low = walkexpr(low, init)
+ if low != nil && iszero(low) {
+ // Reduce x[0:j] to x[:j] and x[0:j:k] to x[:j:k].
+ low = nil
}
- n.Right.Right.Left = walkexpr(n.Right.Right.Left, init)
- n.Right.Right.Right = walkexpr(n.Right.Right.Right, init)
-
- 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
+ high = walkexpr(high, init)
+ max = walkexpr(max, init)
+ n.SetSliceBounds(low, high, max)
+ if n.Op.IsSlice3() {
+ if max != nil && max.Op == OCAP && samesafeexpr(n.Left, max.Left) {
+ // Reduce x[i:j:cap(x)] to x[i:j].
+ if n.Op == OSLICE3 {
+ n.Op = OSLICE
+ } else {
+ n.Op = OSLICEARR
+ }
+ n = reduceSlice(n)
}
+ } else {
n = reduceSlice(n)
}
@@ -1415,17 +1418,18 @@ opswitch:
a := Nod(OAS, var_, nil) // zero temp
a = typecheck(a, Etop)
init.Append(a)
- r := Nod(OSLICE, var_, Nod(OKEY, nil, l)) // arr[:l]
- r = conv(r, n.Type) // in case n.Type is named.
+ r := Nod(OSLICE, var_, nil) // arr[:l]
+ r.SetSliceBounds(nil, l, nil)
+ r = conv(r, n.Type) // in case n.Type is named.
r = typecheck(r, Erv)
r = walkexpr(r, init)
n = r
} else {
- // makeslice(t *Type, nel int64, max int64) (ary []any)
+ // makeslice(et *Type, nel int64, max int64) (ary []any)
fn := syslook("makeslice")
fn = substArgTypes(fn, t.Elem()) // any-1
- n = mkcall1(fn, n.Type, init, typename(n.Type), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
+ n = mkcall1(fn, n.Type, init, typename(t.Elem()), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
}
case ORUNESTR:
@@ -1501,7 +1505,7 @@ opswitch:
// ifaceeq(i1 any-1, i2 any-2) (ret bool);
case OCMPIFACE:
if !Eqtype(n.Left.Type, n.Right.Type) {
- Fatalf("ifaceeq %v %v %v", Oconv(n.Op, 0), n.Left.Type, n.Right.Type)
+ Fatalf("ifaceeq %v %v %v", n.Op, n.Left.Type, n.Right.Type)
}
var fn *Node
if n.Left.Type.IsEmptyInterface() {
@@ -1532,6 +1536,19 @@ opswitch:
n = r
case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
+ if isStaticCompositeLiteral(n) {
+ // n can be directly represented in the read-only data section.
+ // Make direct reference to the static data. See issue 12841.
+ vstat := staticname(n.Type, 0)
+ if n.Op == OSTRUCTLIT {
+ structlit(0, 1, n, vstat, init)
+ } else {
+ arraylit(0, 1, n, vstat, init)
+ }
+ n = vstat
+ n = typecheck(n, Erv)
+ break
+ }
var_ := temp(n.Type)
anylit(0, n, var_, init)
n = var_
@@ -1573,13 +1590,15 @@ opswitch:
return n
}
+// TODO(josharian): combine this with its caller and simplify
func reduceSlice(n *Node) *Node {
- r := n.Right.Right
- if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) {
+ low, high, max := n.SliceBounds()
+ if high != nil && high.Op == OLEN && samesafeexpr(n.Left, high.Left) {
// Reduce x[i:len(x)] to x[i:].
- n.Right.Right = nil
+ high = nil
}
- if (n.Op == OSLICE || n.Op == OSLICESTR) && n.Right.Left == nil && n.Right.Right == nil {
+ n.SetSliceBounds(low, high, max)
+ if (n.Op == OSLICE || n.Op == OSLICESTR) && low == nil && high == nil {
// Reduce x[:] to x.
if Debug_slice > 0 {
Warn("slice: omit slice operation")
@@ -1632,7 +1651,7 @@ func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node {
var nln, nrn Nodes
nln.Set(nl)
nrn.Set(nr)
- Yyerror("error in shape across %v %v %v / %d %d [%s]", Hconv(nln, FmtSign), Oconv(op, 0), Hconv(nrn, FmtSign), len(nl), len(nr), Curfn.Func.Nname.Sym.Name)
+ Yyerror("error in shape across %v %v %v / %d %d [%s]", Hconv(nln, FmtSign), op, Hconv(nrn, FmtSign), len(nl), len(nr), Curfn.Func.Nname.Sym.Name)
}
return nn
}
@@ -1716,6 +1735,7 @@ func mkdotargslice(lr0, nn []*Node, l *Field, fp int, init *Nodes, ddd *Node) []
}
tslice := typSlice(l.Type.Elem())
+ tslice.Noalg = true
var n *Node
if len(lr0) == 0 {
@@ -1783,7 +1803,7 @@ func ascompatte(op Op, call *Node, isddd bool, nl *Type, lr []*Node, fp int, ini
var nn []*Node
// f(g()) where g has multiple return values
- if r != nil && len(lr) <= 1 && r.Type.IsStruct() && r.Type.Funarg {
+ if r != nil && len(lr) <= 1 && r.Type.IsFuncArgStruct() {
// optimization - can do block copy
if eqtypenoname(r.Type, nl) {
arg := nodarg(nl, fp)
@@ -1846,9 +1866,9 @@ func ascompatte(op Op, call *Node, isddd bool, nl *Type, lr []*Node, fp int, ini
l1 := dumptypes(nl, "expected")
l2 := dumpnodetypes(lr0, "given")
if l != nil {
- Yyerror("not enough arguments to %v\n\t%s\n\t%s", Oconv(op, 0), l1, l2)
+ Yyerror("not enough arguments to %v\n\t%s\n\t%s", op, l1, l2)
} else {
- Yyerror("too many arguments to %v\n\t%s\n\t%s", Oconv(op, 0), l1, l2)
+ Yyerror("too many arguments to %v\n\t%s\n\t%s", op, l1, l2)
}
}
@@ -1938,7 +1958,7 @@ func walkprint(nn *Node, init *Nodes) *Node {
on = substArgTypes(on, n.Type) // any-1
} else if Isint[et] {
if et == TUINT64 {
- if (t.Sym.Pkg == Runtimepkg || compiling_runtime != 0) && t.Sym.Name == "hex" {
+ if (t.Sym.Pkg == Runtimepkg || compiling_runtime) && t.Sym.Name == "hex" {
on = syslook("printhex")
} else {
on = syslook("printuint")
@@ -1991,7 +2011,9 @@ func callnew(t *Type) *Node {
dowidth(t)
fn := syslook("newobject")
fn = substArgTypes(fn, t)
- return mkcall1(fn, Ptrto(t), nil, typename(t))
+ v := mkcall1(fn, Ptrto(t), nil, typename(t))
+ v.NonNil = true
+ return v
}
func iscallret(n *Node) bool {
@@ -2041,7 +2063,7 @@ func isglobal(n *Node) bool {
// Do we need a write barrier for the assignment l = r?
func needwritebarrier(l *Node, r *Node) bool {
- if use_writebarrier == 0 {
+ if !use_writebarrier {
return false
}
@@ -2120,7 +2142,7 @@ func applywritebarrier(n *Node) *Node {
func convas(n *Node, init *Nodes) *Node {
if n.Op != OAS {
- Fatalf("convas: not OAS %v", Oconv(n.Op, 0))
+ Fatalf("convas: not OAS %v", n.Op)
}
n.Typecheck = 1
@@ -2263,7 +2285,7 @@ func reorder3(all []*Node) []*Node {
switch l.Op {
default:
- Fatalf("reorder3 unexpected lvalue %v", Oconv(l.Op, FmtSharp))
+ Fatalf("reorder3 unexpected lvalue %v", oconv(l.Op, FmtSharp))
case ONAME:
break
@@ -2550,7 +2572,7 @@ func paramstoheap(params *Type, out bool) []*Node {
}
// generate allocation & copying code
- if compiling_runtime != 0 {
+ if compiling_runtime {
Yyerror("%v escapes to heap, not allowed in runtime.", v)
}
if prealloc[v] == nil {
@@ -2723,8 +2745,7 @@ func addstr(n *Node, init *Nodes) *Node {
prealloc[slice] = prealloc[n]
}
slice.List.Set(args[1:]) // skip buf arg
- args = []*Node{buf}
- args = append(args, slice)
+ args = []*Node{buf, slice}
slice.Esc = EscNone
}
@@ -2787,18 +2808,19 @@ func appendslice(n *Node, init *Nodes) *Node {
fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
// s = growslice(T, s, n)
- nif.Nbody.Set1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, nn)))
+ nif.Nbody.Set1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type.Elem()), s, nn)))
l = append(l, nif)
// s = s[:n]
- nt := Nod(OSLICE, s, Nod(OKEY, nil, nn))
+ nt := Nod(OSLICE, s, nil)
+ nt.SetSliceBounds(nil, nn, nil)
nt.Etype = 1
l = append(l, Nod(OAS, s, nt))
if haspointers(l1.Type.Elem()) {
// copy(s[len(l1):], l2)
- nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), nil))
-
+ nptr1 := Nod(OSLICE, s, nil)
+ nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil)
nptr1.Etype = 1
nptr2 := l2
fn := syslook("typedslicecopy")
@@ -2810,8 +2832,8 @@ func appendslice(n *Node, init *Nodes) *Node {
} else if instrumenting {
// rely on runtime to instrument copy.
// copy(s[len(l1):], l2)
- nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), nil))
-
+ nptr1 := Nod(OSLICE, s, nil)
+ nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil)
nptr1.Etype = 1
nptr2 := l2
var fn *Node
@@ -2917,7 +2939,7 @@ func walkappend(n *Node, init *Nodes, dst *Node) *Node {
fn = substArgTypes(fn, ns.Type.Elem(), ns.Type.Elem())
nx.Nbody.Set1(Nod(OAS, ns,
- mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type), ns,
+ mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type.Elem()), ns,
Nod(OADD, Nod(OLEN, ns, nil), na))))
l = append(l, nx)
@@ -2925,7 +2947,8 @@ func walkappend(n *Node, init *Nodes, dst *Node) *Node {
nn := temp(Types[TINT])
l = append(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
- nx = Nod(OSLICE, ns, Nod(OKEY, nil, Nod(OADD, nn, na))) // ...s[:n+argc]
+ nx = Nod(OSLICE, ns, nil) // ...s[:n+argc]
+ nx.SetSliceBounds(nil, Nod(OADD, nn, na), nil)
nx.Etype = 1
l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
@@ -3101,12 +3124,7 @@ func walkcompare(n *Node, init *Nodes) *Node {
default:
return n
- case TARRAY:
- if t.IsSlice() {
- return n
- }
-
- case TSTRUCT:
+ case TARRAY, TSTRUCT:
break
}
@@ -3274,7 +3292,7 @@ func samecheap(a *Node, b *Node) bool {
// The result of walkrotate MUST be assigned back to n, e.g.
// n.Left = walkrotate(n.Left)
func walkrotate(n *Node) *Node {
- if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+ if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) {
return n
}
@@ -3294,6 +3312,11 @@ func walkrotate(n *Node) *Node {
// Constants adding to width?
w := int(l.Type.Width * 8)
+ if Thearch.LinkArch.Family == sys.S390X && w != 32 && w != 64 {
+ // only supports 32-bit and 64-bit rotates
+ return n
+ }
+
if Smallintconst(l.Right) && Smallintconst(r.Right) {
sl := int(l.Right.Int64())
if sl >= 0 {
@@ -3401,7 +3424,7 @@ func walkdiv(n *Node, init *Nodes) *Node {
// if >= 0, nr is 1<<pow // 1 if nr is negative.
// TODO(minux)
- if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+ if Thearch.LinkArch.InFamily(sys.MIPS64, sys.PPC64) {
return n
}
@@ -3462,6 +3485,16 @@ func walkdiv(n *Node, init *Nodes) *Node {
goto ret
}
+ // TODO(zhongwei) Test shows that TUINT8, TINT8, TUINT16 and TINT16's "quick division" method
+ // on current arm64 backend is slower than hardware div instruction on ARM64 due to unnecessary
+ // data movement between registers. It could be enabled when generated code is good enough.
+ if Thearch.LinkArch.Family == sys.ARM64 {
+ switch Simtype[nl.Type.Etype] {
+ case TUINT8, TINT8, TUINT16, TINT16:
+ return n
+ }
+ }
+
switch Simtype[nl.Type.Etype] {
default:
return n
@@ -3765,7 +3798,7 @@ func usefield(n *Node) {
switch n.Op {
default:
- Fatalf("usefield %v", Oconv(n.Op, 0))
+ Fatalf("usefield %v", n.Op)
case ODOT, ODOTPTR:
break
@@ -3784,7 +3817,7 @@ func usefield(n *Node) {
if field == nil {
Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym)
}
- if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
+ if !strings.Contains(field.Note, "go:\"track\"") {
return
}
diff --git a/src/cmd/compile/internal/mips64/galign.go b/src/cmd/compile/internal/mips64/galign.go
index 9d582f4b51..22890c891b 100644
--- a/src/cmd/compile/internal/mips64/galign.go
+++ b/src/cmd/compile/internal/mips64/galign.go
@@ -11,18 +11,12 @@ import (
)
func betypeinit() {
- gc.Widthptr = 8
- gc.Widthint = 8
- gc.Widthreg = 8
}
func Main() {
- gc.Thearch.Thechar = '0'
- gc.Thearch.Thestring = "mips64"
- gc.Thearch.Thelinkarch = &mips.Linkmips64
+ gc.Thearch.LinkArch = &mips.Linkmips64
if obj.Getgoarch() == "mips64le" {
- gc.Thearch.Thestring = "mips64le"
- gc.Thearch.Thelinkarch = &mips.Linkmips64le
+ gc.Thearch.LinkArch = &mips.Linkmips64le
}
gc.Thearch.REGSP = mips.REGSP
gc.Thearch.REGCTXT = mips.REGCTXT
diff --git a/src/cmd/compile/internal/mips64/gsubr.go b/src/cmd/compile/internal/mips64/gsubr.go
index 60805270af..a2bff29ecc 100644
--- a/src/cmd/compile/internal/mips64/gsubr.go
+++ b/src/cmd/compile/internal/mips64/gsubr.go
@@ -148,7 +148,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
case gc.TFLOAT32:
switch op {
default:
- gc.Fatalf("ginscmp: no entry for op=%v type=%v", gc.Oconv(op, 0), t)
+ gc.Fatalf("ginscmp: no entry for op=%s type=%v", op, t)
case gc.OEQ,
gc.ONE:
@@ -165,7 +165,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
case gc.TFLOAT64:
switch op {
default:
- gc.Fatalf("ginscmp: no entry for op=%v type=%v", gc.Oconv(op, 0), t)
+ gc.Fatalf("ginscmp: no entry for op=%s type=%v", op, t)
case gc.OEQ,
gc.ONE:
@@ -715,7 +715,7 @@ func optoas(op gc.Op, t *gc.Type) obj.As {
a := obj.AXXX
switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
default:
- gc.Fatalf("optoas: no entry for op=%v type=%v", gc.Oconv(op, 0), t)
+ gc.Fatalf("optoas: no entry for op=%s type=%v", op, t)
case OEQ_ | gc.TBOOL,
OEQ_ | gc.TINT8,
diff --git a/src/cmd/compile/internal/ppc64/galign.go b/src/cmd/compile/internal/ppc64/galign.go
index 91bece6080..a83dff9a8b 100644
--- a/src/cmd/compile/internal/ppc64/galign.go
+++ b/src/cmd/compile/internal/ppc64/galign.go
@@ -11,23 +11,16 @@ import (
)
func betypeinit() {
- gc.Widthptr = 8
- gc.Widthint = 8
- gc.Widthreg = 8
-
- if gc.Ctxt.Flag_shared != 0 {
+ if gc.Ctxt.Flag_shared {
gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, ppc64.REG_R2)
gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, ppc64.REG_R12)
}
}
func Main() {
- gc.Thearch.Thechar = '9'
- gc.Thearch.Thestring = "ppc64"
- gc.Thearch.Thelinkarch = &ppc64.Linkppc64
+ gc.Thearch.LinkArch = &ppc64.Linkppc64
if obj.Getgoarch() == "ppc64le" {
- gc.Thearch.Thestring = "ppc64le"
- gc.Thearch.Thelinkarch = &ppc64.Linkppc64le
+ gc.Thearch.LinkArch = &ppc64.Linkppc64le
}
gc.Thearch.REGSP = ppc64.REGSP
gc.Thearch.REGCTXT = ppc64.REGCTXT
diff --git a/src/cmd/compile/internal/ppc64/gsubr.go b/src/cmd/compile/internal/ppc64/gsubr.go
index de6e2fbe05..1137c50678 100644
--- a/src/cmd/compile/internal/ppc64/gsubr.go
+++ b/src/cmd/compile/internal/ppc64/gsubr.go
@@ -580,7 +580,7 @@ func rawgins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
case obj.ACALL:
if p.To.Type == obj.TYPE_REG && p.To.Reg != ppc64.REG_CTR {
// Allow front end to emit CALL REG, and rewrite into MOV REG, CTR; CALL CTR.
- if gc.Ctxt.Flag_shared != 0 {
+ if gc.Ctxt.Flag_shared {
// Make sure function pointer is in R12 as well when
// compiling Go into PIC.
// TODO(mwhudson): it would obviously be better to
@@ -602,7 +602,7 @@ func rawgins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
p.To.Type = obj.TYPE_REG
p.To.Reg = ppc64.REG_CTR
- if gc.Ctxt.Flag_shared != 0 {
+ if gc.Ctxt.Flag_shared {
// When compiling Go into PIC, the function we just
// called via pointer might have been implemented in
// a separate module and so overwritten the TOC
@@ -712,7 +712,7 @@ func optoas(op gc.Op, t *gc.Type) obj.As {
a := obj.AXXX
switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
default:
- gc.Fatalf("optoas: no entry for op=%v type=%v", gc.Oconv(op, 0), t)
+ gc.Fatalf("optoas: no entry for op=%v type=%v", op, t)
case OEQ_ | gc.TBOOL,
OEQ_ | gc.TINT8,
diff --git a/src/cmd/compile/internal/ppc64/reg.go b/src/cmd/compile/internal/ppc64/reg.go
index 447679e207..558ba4a4f4 100644
--- a/src/cmd/compile/internal/ppc64/reg.go
+++ b/src/cmd/compile/internal/ppc64/reg.go
@@ -113,7 +113,7 @@ func excludedregs() uint64 {
// Exclude registers with fixed functions
regbits := 1<<0 | RtoB(ppc64.REGSP) | RtoB(ppc64.REGG) | RtoB(ppc64.REGTLS) | RtoB(ppc64.REGTMP)
- if gc.Ctxt.Flag_shared != 0 {
+ if gc.Ctxt.Flag_shared {
// When compiling Go into PIC, R2 is reserved to be the TOC pointer
// and R12 so that calls via function pointer can stomp on it.
regbits |= RtoB(ppc64.REG_R2)
diff --git a/src/cmd/compile/internal/s390x/cgen.go b/src/cmd/compile/internal/s390x/cgen.go
new file mode 100644
index 0000000000..28bb34e0ef
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/cgen.go
@@ -0,0 +1,178 @@
+// Copyright 2016 The Go 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 s390x
+
+import (
+ "cmd/compile/internal/gc"
+ "cmd/internal/obj"
+ "cmd/internal/obj/s390x"
+)
+
+type direction int
+
+const (
+ _FORWARDS direction = iota
+ _BACKWARDS
+)
+
+// blockcopy copies w bytes from &n to &res
+func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
+ var dst gc.Node
+ var src gc.Node
+ if n.Ullman >= res.Ullman {
+ gc.Agenr(n, &dst, res) // temporarily use dst
+ gc.Regalloc(&src, gc.Types[gc.Tptr], nil)
+ gins(s390x.AMOVD, &dst, &src)
+ if res.Op == gc.ONAME {
+ gc.Gvardef(res)
+ }
+ gc.Agen(res, &dst)
+ } else {
+ if res.Op == gc.ONAME {
+ gc.Gvardef(res)
+ }
+ gc.Agenr(res, &dst, res)
+ gc.Agenr(n, &src, nil)
+ }
+ defer gc.Regfree(&src)
+ defer gc.Regfree(&dst)
+
+ var tmp gc.Node
+ gc.Regalloc(&tmp, gc.Types[gc.Tptr], nil)
+ defer gc.Regfree(&tmp)
+
+ offset := int64(0)
+ dir := _FORWARDS
+ if osrc < odst && odst < osrc+w {
+ // Reverse. Can't use MVC, fall back onto basic moves.
+ dir = _BACKWARDS
+ const copiesPerIter = 2
+ if w >= 8*copiesPerIter {
+ cnt := w - (w % (8 * copiesPerIter))
+ ginscon(s390x.AADD, w, &src)
+ ginscon(s390x.AADD, w, &dst)
+
+ var end gc.Node
+ gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
+ p := gins(s390x.ASUB, nil, &end)
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = cnt
+ p.Reg = src.Reg
+
+ var label *obj.Prog
+ for i := 0; i < copiesPerIter; i++ {
+ offset := int64(-8 * (i + 1))
+ p := gins(s390x.AMOVD, &src, &tmp)
+ p.From.Type = obj.TYPE_MEM
+ p.From.Offset = offset
+ if i == 0 {
+ label = p
+ }
+ p = gins(s390x.AMOVD, &tmp, &dst)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Offset = offset
+ }
+
+ ginscon(s390x.ASUB, 8*copiesPerIter, &src)
+ ginscon(s390x.ASUB, 8*copiesPerIter, &dst)
+ gins(s390x.ACMP, &src, &end)
+ gc.Patch(gc.Gbranch(s390x.ABNE, nil, 0), label)
+ gc.Regfree(&end)
+
+ w -= cnt
+ } else {
+ offset = w
+ }
+ }
+
+ if dir == _FORWARDS && w > 1024 {
+ // Loop over MVCs
+ cnt := w - (w % 256)
+
+ var end gc.Node
+ gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
+ add := gins(s390x.AADD, nil, &end)
+ add.From.Type = obj.TYPE_CONST
+ add.From.Offset = cnt
+ add.Reg = src.Reg
+
+ mvc := gins(s390x.AMVC, &src, &dst)
+ mvc.From.Type = obj.TYPE_MEM
+ mvc.From.Offset = 0
+ mvc.To.Type = obj.TYPE_MEM
+ mvc.To.Offset = 0
+ mvc.From3 = new(obj.Addr)
+ mvc.From3.Type = obj.TYPE_CONST
+ mvc.From3.Offset = 256
+
+ ginscon(s390x.AADD, 256, &src)
+ ginscon(s390x.AADD, 256, &dst)
+ gins(s390x.ACMP, &src, &end)
+ gc.Patch(gc.Gbranch(s390x.ABNE, nil, 0), mvc)
+ gc.Regfree(&end)
+
+ w -= cnt
+ }
+
+ for w > 0 {
+ cnt := w
+ // If in reverse we can only do 8, 4, 2 or 1 bytes at a time.
+ if dir == _BACKWARDS {
+ switch {
+ case cnt >= 8:
+ cnt = 8
+ case cnt >= 4:
+ cnt = 4
+ case cnt >= 2:
+ cnt = 2
+ }
+ } else if cnt > 256 {
+ cnt = 256
+ }
+
+ switch cnt {
+ case 8, 4, 2, 1:
+ op := s390x.AMOVB
+ switch cnt {
+ case 8:
+ op = s390x.AMOVD
+ case 4:
+ op = s390x.AMOVW
+ case 2:
+ op = s390x.AMOVH
+ }
+ load := gins(op, &src, &tmp)
+ load.From.Type = obj.TYPE_MEM
+ load.From.Offset = offset
+
+ store := gins(op, &tmp, &dst)
+ store.To.Type = obj.TYPE_MEM
+ store.To.Offset = offset
+
+ if dir == _BACKWARDS {
+ load.From.Offset -= cnt
+ store.To.Offset -= cnt
+ }
+
+ default:
+ p := gins(s390x.AMVC, &src, &dst)
+ p.From.Type = obj.TYPE_MEM
+ p.From.Offset = offset
+ p.To.Type = obj.TYPE_MEM
+ p.To.Offset = offset
+ p.From3 = new(obj.Addr)
+ p.From3.Type = obj.TYPE_CONST
+ p.From3.Offset = cnt
+ }
+
+ switch dir {
+ case _FORWARDS:
+ offset += cnt
+ case _BACKWARDS:
+ offset -= cnt
+ }
+ w -= cnt
+ }
+}
diff --git a/src/cmd/compile/internal/s390x/galign.go b/src/cmd/compile/internal/s390x/galign.go
new file mode 100644
index 0000000000..d0d621e557
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/galign.go
@@ -0,0 +1,66 @@
+// Copyright 2016 The Go 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 s390x
+
+import (
+ "cmd/compile/internal/gc"
+ "cmd/internal/obj/s390x"
+)
+
+func betypeinit() {
+ gc.Widthptr = 8
+ gc.Widthint = 8
+ gc.Widthreg = 8
+}
+
+func Main() {
+ gc.Thearch.LinkArch = &s390x.Links390x
+ gc.Thearch.REGSP = s390x.REGSP
+ gc.Thearch.REGCTXT = s390x.REGCTXT
+ gc.Thearch.REGCALLX = s390x.REG_R3
+ gc.Thearch.REGCALLX2 = s390x.REG_R4
+ gc.Thearch.REGRETURN = s390x.REG_R3
+ gc.Thearch.REGMIN = s390x.REG_R0
+ gc.Thearch.REGMAX = s390x.REG_R15
+ gc.Thearch.FREGMIN = s390x.REG_F0
+ gc.Thearch.FREGMAX = s390x.REG_F15
+ gc.Thearch.MAXWIDTH = 1 << 50
+ gc.Thearch.ReservedRegs = resvd
+
+ gc.Thearch.Betypeinit = betypeinit
+ gc.Thearch.Cgen_hmul = cgen_hmul
+ gc.Thearch.Cgen_shift = cgen_shift
+ gc.Thearch.Clearfat = clearfat
+ gc.Thearch.Defframe = defframe
+ gc.Thearch.Dodiv = dodiv
+ gc.Thearch.Excise = excise
+ 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
+ gc.Thearch.Peep = peep
+ gc.Thearch.Proginfo = proginfo
+ gc.Thearch.Regtyp = isReg
+ gc.Thearch.Sameaddr = sameaddr
+ gc.Thearch.Smallindir = smallindir
+ gc.Thearch.Stackaddr = stackaddr
+ gc.Thearch.Blockcopy = blockcopy
+ gc.Thearch.Sudoaddable = sudoaddable
+ gc.Thearch.Sudoclean = sudoclean
+ gc.Thearch.Excludedregs = excludedregs
+ gc.Thearch.RtoB = RtoB
+ gc.Thearch.FtoB = RtoB
+ gc.Thearch.BtoR = BtoR
+ gc.Thearch.BtoF = BtoF
+ gc.Thearch.Optoas = optoas
+ gc.Thearch.Doregbits = doregbits
+ gc.Thearch.Regnames = regnames
+
+ gc.Main()
+ gc.Exit(0)
+}
diff --git a/src/cmd/compile/internal/s390x/ggen.go b/src/cmd/compile/internal/s390x/ggen.go
new file mode 100644
index 0000000000..39885baace
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/ggen.go
@@ -0,0 +1,577 @@
+// Copyright 2016 The Go 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 s390x
+
+import (
+ "cmd/compile/internal/gc"
+ "cmd/internal/obj"
+ "cmd/internal/obj/s390x"
+ "fmt"
+)
+
+// clearLoopCutOff is the (somewhat arbitrary) value above which it is better
+// to have a loop of clear instructions (e.g. XCs) rather than just generating
+// multiple instructions (i.e. loop unrolling).
+// Must be between 256 and 4096.
+const clearLoopCutoff = 1024
+
+func defframe(ptxt *obj.Prog) {
+ // fill in argument size, stack size
+ ptxt.To.Type = obj.TYPE_TEXTSIZE
+
+ ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.ArgWidth(), int64(gc.Widthptr)))
+ frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
+ ptxt.To.Offset = int64(frame)
+
+ // insert code to zero ambiguously live variables
+ // so that the garbage collector only sees initialized values
+ // when it looks for pointers.
+ p := ptxt
+
+ hi := int64(0)
+ lo := hi
+
+ // iterate through declarations - they are sorted in decreasing xoffset order.
+ for _, n := range gc.Curfn.Func.Dcl {
+ if !n.Name.Needzero {
+ continue
+ }
+ if n.Class != gc.PAUTO {
+ gc.Fatalf("needzero class %d", n.Class)
+ }
+ if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
+ gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.FmtLong), int(n.Type.Width), int(n.Xoffset))
+ }
+
+ if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) {
+ // merge with range we already have
+ lo = n.Xoffset
+
+ continue
+ }
+
+ // zero old range
+ p = zerorange(p, int64(frame), lo, hi)
+
+ // set new range
+ hi = n.Xoffset + n.Type.Width
+
+ lo = n.Xoffset
+ }
+
+ // zero final range
+ zerorange(p, int64(frame), lo, hi)
+}
+
+// zerorange clears the stack in the given range.
+func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
+ cnt := hi - lo
+ if cnt == 0 {
+ return p
+ }
+
+ // Adjust the frame to account for LR.
+ frame += gc.Ctxt.FixedFrameSize()
+ offset := frame + lo
+ reg := int16(s390x.REGSP)
+
+ // If the offset cannot fit in a 12-bit unsigned displacement then we
+ // need to create a copy of the stack pointer that we can adjust.
+ // We also need to do this if we are going to loop.
+ if offset < 0 || offset > 4096-clearLoopCutoff || cnt > clearLoopCutoff {
+ p = appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset, obj.TYPE_REG, s390x.REGRT1, 0)
+ p.Reg = int16(s390x.REGSP)
+ reg = s390x.REGRT1
+ offset = 0
+ }
+
+ // Generate a loop of large clears.
+ if cnt > clearLoopCutoff {
+ n := cnt - (cnt % 256)
+ end := int16(s390x.REGRT2)
+ p = appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset+n, obj.TYPE_REG, end, 0)
+ p.Reg = reg
+ p = appendpp(p, s390x.AXC, obj.TYPE_MEM, reg, offset, obj.TYPE_MEM, reg, offset)
+ p.From3 = new(obj.Addr)
+ p.From3.Type = obj.TYPE_CONST
+ p.From3.Offset = 256
+ pl := p
+ p = appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, 256, obj.TYPE_REG, reg, 0)
+ p = appendpp(p, s390x.ACMP, obj.TYPE_REG, reg, 0, obj.TYPE_REG, end, 0)
+ p = appendpp(p, s390x.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
+ gc.Patch(p, pl)
+
+ cnt -= n
+ }
+
+ // Generate remaining clear instructions without a loop.
+ for cnt > 0 {
+ n := cnt
+
+ // Can clear at most 256 bytes per instruction.
+ if n > 256 {
+ n = 256
+ }
+
+ switch n {
+ // Handle very small clears with move instructions.
+ case 8, 4, 2, 1:
+ ins := s390x.AMOVB
+ switch n {
+ case 8:
+ ins = s390x.AMOVD
+ case 4:
+ ins = s390x.AMOVW
+ case 2:
+ ins = s390x.AMOVH
+ }
+ p = appendpp(p, ins, obj.TYPE_CONST, 0, 0, obj.TYPE_MEM, reg, offset)
+
+ // Handle clears that would require multiple move instructions with XC.
+ default:
+ p = appendpp(p, s390x.AXC, obj.TYPE_MEM, reg, offset, obj.TYPE_MEM, reg, offset)
+ p.From3 = new(obj.Addr)
+ p.From3.Type = obj.TYPE_CONST
+ p.From3.Offset = n
+ }
+
+ cnt -= n
+ offset += n
+ }
+
+ return p
+}
+
+func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset int64, ttype obj.AddrType, treg int16, toffset int64) *obj.Prog {
+ q := gc.Ctxt.NewProg()
+ gc.Clearp(q)
+ q.As = as
+ q.Lineno = p.Lineno
+ q.From.Type = ftype
+ q.From.Reg = freg
+ q.From.Offset = foffset
+ q.To.Type = ttype
+ q.To.Reg = treg
+ q.To.Offset = toffset
+ q.Link = p.Link
+ p.Link = q
+ return q
+}
+
+func ginsnop() {
+ var reg gc.Node
+ gc.Nodreg(&reg, gc.Types[gc.TINT], s390x.REG_R0)
+ gins(s390x.AOR, &reg, &reg)
+}
+
+var panicdiv *gc.Node
+
+/*
+ * generate division.
+ * generates one of:
+ * res = nl / nr
+ * res = nl % nr
+ * according to op.
+ */
+func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
+ // Have to be careful about handling
+ // most negative int divided by -1 correctly.
+ // The hardware will generate undefined result.
+ // Also need to explicitly trap on division on zero,
+ // the hardware will silently generate undefined result.
+ // DIVW will leave unpredicable result in higher 32-bit,
+ // so always use DIVD/DIVDU.
+ t := nl.Type
+
+ t0 := t
+ check := 0
+ if t.IsSigned() {
+ check = 1
+ if gc.Isconst(nl, gc.CTINT) && nl.Int64() != -(1<<uint64(t.Width*8-1)) {
+ check = 0
+ } else if gc.Isconst(nr, gc.CTINT) && nr.Int64() != -1 {
+ check = 0
+ }
+ }
+
+ if t.Width < 8 {
+ if t.IsSigned() {
+ t = gc.Types[gc.TINT64]
+ } else {
+ t = gc.Types[gc.TUINT64]
+ }
+ check = 0
+ }
+
+ a := optoas(gc.ODIV, t)
+
+ var tl gc.Node
+ gc.Regalloc(&tl, t0, nil)
+ var tr gc.Node
+ gc.Regalloc(&tr, t0, nil)
+ if nl.Ullman >= nr.Ullman {
+ gc.Cgen(nl, &tl)
+ gc.Cgen(nr, &tr)
+ } else {
+ gc.Cgen(nr, &tr)
+ gc.Cgen(nl, &tl)
+ }
+
+ if t != t0 {
+ // Convert
+ tl2 := tl
+
+ tr2 := tr
+ tl.Type = t
+ tr.Type = t
+ gmove(&tl2, &tl)
+ gmove(&tr2, &tr)
+ }
+
+ // Handle divide-by-zero panic.
+ p1 := gins(optoas(gc.OCMP, t), &tr, nil)
+
+ p1.To.Type = obj.TYPE_REG
+ p1.To.Reg = s390x.REGZERO
+ p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1)
+ if panicdiv == nil {
+ panicdiv = gc.Sysfunc("panicdivide")
+ }
+ gc.Ginscall(panicdiv, -1)
+ gc.Patch(p1, gc.Pc)
+
+ var p2 *obj.Prog
+ if check != 0 {
+ var nm1 gc.Node
+ gc.Nodconst(&nm1, t, -1)
+ gins(optoas(gc.OCMP, t), &tr, &nm1)
+ p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
+ if op == gc.ODIV {
+ // a / (-1) is -a.
+ gins(optoas(gc.OMINUS, t), nil, &tl)
+
+ gmove(&tl, res)
+ } else {
+ // a % (-1) is 0.
+ var nz gc.Node
+ gc.Nodconst(&nz, t, 0)
+
+ gmove(&nz, res)
+ }
+
+ p2 = gc.Gbranch(obj.AJMP, nil, 0)
+ gc.Patch(p1, gc.Pc)
+ }
+
+ p1 = gins(a, &tr, &tl)
+ if op == gc.ODIV {
+ gc.Regfree(&tr)
+ gmove(&tl, res)
+ } else {
+ // A%B = A-(A/B*B)
+ var tm gc.Node
+ gc.Regalloc(&tm, t, nil)
+
+ // patch div to use the 3 register form
+ // TODO(minux): add gins3?
+ p1.Reg = p1.To.Reg
+
+ p1.To.Reg = tm.Reg
+ gins(optoas(gc.OMUL, t), &tr, &tm)
+ gc.Regfree(&tr)
+ gins(optoas(gc.OSUB, t), &tm, &tl)
+ gc.Regfree(&tm)
+ gmove(&tl, res)
+ }
+
+ gc.Regfree(&tl)
+ if check != 0 {
+ gc.Patch(p2, gc.Pc)
+ }
+}
+
+/*
+ * generate high multiply:
+ * res = (nl*nr) >> width
+ */
+func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
+ // largest ullman on left.
+ if nl.Ullman < nr.Ullman {
+ nl, nr = nr, nl
+ }
+
+ t := nl.Type
+ w := int(t.Width) * 8
+ var n1 gc.Node
+ gc.Cgenr(nl, &n1, res)
+ var n2 gc.Node
+ gc.Cgenr(nr, &n2, nil)
+ switch gc.Simtype[t.Etype] {
+ case gc.TINT8,
+ gc.TINT16,
+ gc.TINT32:
+ gins(optoas(gc.OMUL, t), &n2, &n1)
+ p := gins(s390x.ASRAD, nil, &n1)
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = int64(w)
+
+ case gc.TUINT8,
+ gc.TUINT16,
+ gc.TUINT32:
+ gins(optoas(gc.OMUL, t), &n2, &n1)
+ p := gins(s390x.ASRD, nil, &n1)
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = int64(w)
+
+ case gc.TINT64:
+ gins(s390x.AMULHD, &n2, &n1)
+
+ case gc.TUINT64:
+ gins(s390x.AMULHDU, &n2, &n1)
+
+ default:
+ gc.Fatalf("cgen_hmul %v", t)
+ }
+
+ gc.Cgen(&n1, res)
+ gc.Regfree(&n1)
+ gc.Regfree(&n2)
+}
+
+/*
+ * generate shift according to op, one of:
+ * res = nl << nr
+ * res = nl >> nr
+ */
+func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
+ a := optoas(op, nl.Type)
+
+ if nr.Op == gc.OLITERAL {
+ var n1 gc.Node
+ gc.Regalloc(&n1, nl.Type, res)
+ gc.Cgen(nl, &n1)
+ sc := uint64(nr.Int64())
+ if sc >= uint64(nl.Type.Width*8) {
+ // large shift gets 2 shifts by width-1
+ var n3 gc.Node
+ gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
+
+ gins(a, &n3, &n1)
+ gins(a, &n3, &n1)
+ } else {
+ gins(a, nr, &n1)
+ }
+ gmove(&n1, res)
+ gc.Regfree(&n1)
+ return
+ }
+
+ if nl.Ullman >= gc.UINF {
+ var n4 gc.Node
+ gc.Tempname(&n4, nl.Type)
+ gc.Cgen(nl, &n4)
+ nl = &n4
+ }
+
+ if nr.Ullman >= gc.UINF {
+ var n5 gc.Node
+ gc.Tempname(&n5, nr.Type)
+ gc.Cgen(nr, &n5)
+ nr = &n5
+ }
+
+ // Allow either uint32 or uint64 as shift type,
+ // to avoid unnecessary conversion from uint32 to uint64
+ // just to do the comparison.
+ tcount := gc.Types[gc.Simtype[nr.Type.Etype]]
+
+ if tcount.Etype < gc.TUINT32 {
+ tcount = gc.Types[gc.TUINT32]
+ }
+
+ var n1 gc.Node
+ gc.Regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
+ var n3 gc.Node
+ gc.Regalloc(&n3, tcount, &n1) // to clear high bits of CX
+
+ var n2 gc.Node
+ gc.Regalloc(&n2, nl.Type, res)
+
+ if nl.Ullman >= nr.Ullman {
+ gc.Cgen(nl, &n2)
+ gc.Cgen(nr, &n1)
+ gmove(&n1, &n3)
+ } else {
+ gc.Cgen(nr, &n1)
+ gmove(&n1, &n3)
+ gc.Cgen(nl, &n2)
+ }
+
+ gc.Regfree(&n3)
+
+ // test and fix up large shifts
+ if !bounded {
+ gc.Nodconst(&n3, tcount, nl.Type.Width*8)
+ gins(optoas(gc.OCMP, tcount), &n1, &n3)
+ p1 := gc.Gbranch(optoas(gc.OLT, tcount), nil, 1)
+ if op == gc.ORSH && nl.Type.IsSigned() {
+ gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
+ gins(a, &n3, &n2)
+ } else {
+ gc.Nodconst(&n3, nl.Type, 0)
+ gmove(&n3, &n2)
+ }
+
+ gc.Patch(p1, gc.Pc)
+ }
+
+ gins(a, &n1, &n2)
+
+ gmove(&n2, res)
+
+ gc.Regfree(&n1)
+ gc.Regfree(&n2)
+}
+
+// clearfat clears (i.e. replaces with zeros) the value pointed to by nl.
+func clearfat(nl *gc.Node) {
+ if gc.Debug['g'] != 0 {
+ fmt.Printf("clearfat %v (%v, size: %d)\n", nl, nl.Type, nl.Type.Width)
+ }
+
+ // Avoid taking the address for simple enough types.
+ if gc.Componentgen(nil, nl) {
+ return
+ }
+
+ var dst gc.Node
+ gc.Regalloc(&dst, gc.Types[gc.Tptr], nil)
+ gc.Agen(nl, &dst)
+
+ var boff int64
+ w := nl.Type.Width
+ if w > clearLoopCutoff {
+ // Generate a loop clearing 256 bytes per iteration using XCs.
+ var end gc.Node
+ gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
+ p := gins(s390x.AMOVD, &dst, &end)
+ p.From.Type = obj.TYPE_ADDR
+ p.From.Offset = w - (w % 256)
+
+ p = gins(s390x.AXC, &dst, &dst)
+ p.From.Type = obj.TYPE_MEM
+ p.From.Offset = 0
+ p.To.Type = obj.TYPE_MEM
+ p.To.Offset = 0
+ p.From3 = new(obj.Addr)
+ p.From3.Offset = 256
+ p.From3.Type = obj.TYPE_CONST
+ pl := p
+
+ ginscon(s390x.AADD, 256, &dst)
+ gins(s390x.ACMP, &dst, &end)
+ gc.Patch(gc.Gbranch(s390x.ABNE, nil, 0), pl)
+ gc.Regfree(&end)
+ w = w % 256
+ }
+
+ // Generate instructions to clear the remaining memory.
+ for w > 0 {
+ n := w
+
+ // Can clear at most 256 bytes per instruction.
+ if n > 256 {
+ n = 256
+ }
+
+ switch n {
+ // Handle very small clears using moves.
+ case 8, 4, 2, 1:
+ ins := s390x.AMOVB
+ switch n {
+ case 8:
+ ins = s390x.AMOVD
+ case 4:
+ ins = s390x.AMOVW
+ case 2:
+ ins = s390x.AMOVH
+ }
+ p := gins(ins, nil, &dst)
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = 0
+ p.To.Type = obj.TYPE_MEM
+ p.To.Offset = boff
+
+ // Handle clears that would require multiple moves with a XC.
+ default:
+ p := gins(s390x.AXC, &dst, &dst)
+ p.From.Type = obj.TYPE_MEM
+ p.From.Offset = boff
+ p.To.Type = obj.TYPE_MEM
+ p.To.Offset = boff
+ p.From3 = new(obj.Addr)
+ p.From3.Offset = n
+ p.From3.Type = obj.TYPE_CONST
+ }
+
+ boff += n
+ w -= n
+ }
+
+ gc.Regfree(&dst)
+}
+
+// Called after regopt and peep have run.
+// Expand CHECKNIL pseudo-op into actual nil pointer check.
+func expandchecks(firstp *obj.Prog) {
+ for p := firstp; p != nil; p = p.Link {
+ if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 {
+ fmt.Printf("expandchecks: %v\n", p)
+ }
+ if p.As != obj.ACHECKNIL {
+ continue
+ }
+ if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
+ gc.Warnl(p.Lineno, "generated nil check")
+ }
+ if p.From.Type != obj.TYPE_REG {
+ gc.Fatalf("invalid nil check %v\n", p)
+ }
+
+ // check is
+ // CMPBNE arg, $0, 2(PC) [likely]
+ // MOVD R0, 0(R0)
+ p1 := gc.Ctxt.NewProg()
+
+ gc.Clearp(p1)
+ p1.Link = p.Link
+ p.Link = p1
+ p1.Lineno = p.Lineno
+ p1.Pc = 9999
+ p.As = s390x.ACMPBNE
+ p.From3 = new(obj.Addr)
+ p.From3.Type = obj.TYPE_CONST
+ p.From3.Offset = 0
+
+ p.To.Type = obj.TYPE_BRANCH
+ p.To.Val = p1.Link
+
+ // crash by write to memory address 0.
+ p1.As = s390x.AMOVD
+
+ p1.From.Type = obj.TYPE_REG
+ p1.From.Reg = s390x.REGZERO
+ p1.To.Type = obj.TYPE_MEM
+ p1.To.Reg = s390x.REGZERO
+ p1.To.Offset = 0
+ }
+}
+
+// res = runtime.getg()
+func getg(res *gc.Node) {
+ var n1 gc.Node
+ gc.Nodreg(&n1, res.Type, s390x.REGG)
+ gmove(&n1, res)
+}
diff --git a/src/cmd/compile/internal/s390x/gsubr.go b/src/cmd/compile/internal/s390x/gsubr.go
new file mode 100644
index 0000000000..3e8782f5e6
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/gsubr.go
@@ -0,0 +1,1115 @@
+// Derived from Inferno utils/6c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package s390x
+
+import (
+ "cmd/compile/internal/gc"
+ "cmd/internal/obj"
+ "cmd/internal/obj/s390x"
+ "fmt"
+)
+
+var resvd = []int{
+ s390x.REGZERO, // R0
+ s390x.REGTMP, // R10
+ s390x.REGTMP2, // R11
+ s390x.REGCTXT, // R12
+ s390x.REGG, // R13
+ s390x.REG_LR, // R14
+ s390x.REGSP, // R15
+}
+
+// generate
+// as $c, n
+func ginscon(as obj.As, c int64, n2 *gc.Node) {
+ var n1 gc.Node
+
+ gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
+
+ if as != s390x.AMOVD && (c < -s390x.BIG || c > s390x.BIG) || n2.Op != gc.OREGISTER || as == s390x.AMULLD {
+ // cannot have more than 16-bit of immediate in ADD, etc.
+ // instead, MOV into register first.
+ var ntmp gc.Node
+ gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
+
+ rawgins(s390x.AMOVD, &n1, &ntmp)
+ rawgins(as, &ntmp, n2)
+ gc.Regfree(&ntmp)
+ return
+ }
+
+ rawgins(as, &n1, n2)
+}
+
+// generate
+// as n, $c (CMP/CMPU)
+func ginscon2(as obj.As, n2 *gc.Node, c int64) {
+ var n1 gc.Node
+
+ gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
+
+ switch as {
+ default:
+ gc.Fatalf("ginscon2")
+
+ case s390x.ACMP:
+ if -s390x.BIG <= c && c <= s390x.BIG {
+ rawgins(as, n2, &n1)
+ return
+ }
+
+ case s390x.ACMPU:
+ if 0 <= c && c <= 2*s390x.BIG {
+ rawgins(as, n2, &n1)
+ return
+ }
+ }
+
+ // MOV n1 into register first
+ var ntmp gc.Node
+ gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
+
+ rawgins(s390x.AMOVD, &n1, &ntmp)
+ rawgins(as, n2, &ntmp)
+ gc.Regfree(&ntmp)
+}
+
+func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
+ if t.IsInteger() && 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 t.IsInteger() && gc.Isconst(n2, gc.CTINT) {
+ ginscon2(optoas(gc.OCMP, t), &r1, n2.Int64())
+ } 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)
+}
+
+// gmvc tries to move f to t using a mvc instruction.
+// If successful it returns true, otherwise it returns false.
+func gmvc(f, t *gc.Node) bool {
+ ft := int(gc.Simsimtype(f.Type))
+ tt := int(gc.Simsimtype(t.Type))
+
+ if ft != tt {
+ return false
+ }
+
+ if f.Op != gc.OINDREG || t.Op != gc.OINDREG {
+ return false
+ }
+
+ if f.Xoffset < 0 || f.Xoffset >= 4096-8 {
+ return false
+ }
+
+ if t.Xoffset < 0 || t.Xoffset >= 4096-8 {
+ return false
+ }
+
+ var len int64
+ switch ft {
+ case gc.TUINT8, gc.TINT8, gc.TBOOL:
+ len = 1
+ case gc.TUINT16, gc.TINT16:
+ len = 2
+ case gc.TUINT32, gc.TINT32, gc.TFLOAT32:
+ len = 4
+ case gc.TUINT64, gc.TINT64, gc.TFLOAT64, gc.TPTR64:
+ len = 8
+ case gc.TUNSAFEPTR:
+ len = int64(gc.Widthptr)
+ default:
+ return false
+ }
+
+ p := gc.Prog(s390x.AMVC)
+ gc.Naddr(&p.From, f)
+ gc.Naddr(&p.To, t)
+ p.From3 = new(obj.Addr)
+ p.From3.Offset = len
+ p.From3.Type = obj.TYPE_CONST
+ return true
+}
+
+// generate move:
+// t = f
+// hard part is conversions.
+func gmove(f *gc.Node, t *gc.Node) {
+ if gc.Debug['M'] != 0 {
+ fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
+ }
+
+ ft := int(gc.Simsimtype(f.Type))
+ tt := int(gc.Simsimtype(t.Type))
+ cvt := t.Type
+
+ if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
+ gc.Complexmove(f, t)
+ return
+ }
+
+ var a obj.As
+
+ // cannot have two memory operands
+ if gc.Ismem(f) && gc.Ismem(t) {
+ if gmvc(f, t) {
+ return
+ }
+ goto hard
+ }
+
+ // convert constant to desired type
+ if f.Op == gc.OLITERAL {
+ var con gc.Node
+ f.Convconst(&con, t.Type)
+ f = &con
+ ft = tt // so big switch will choose a simple mov
+
+ // some constants can't move directly to memory.
+ if gc.Ismem(t) {
+ // float constants come from memory.
+ if t.Type.IsFloat() {
+ goto hard
+ }
+
+ // all immediates are 16-bit sign-extended
+ // unless moving into a register.
+ if t.Type.IsInteger() {
+ if i := con.Int64(); int64(int16(i)) != i {
+ goto hard
+ }
+ }
+
+ // immediate moves to memory have a 12-bit unsigned displacement
+ if t.Xoffset < 0 || t.Xoffset >= 4096-8 {
+ goto hard
+ }
+ }
+ }
+
+ // a float-to-int or int-to-float conversion requires the source operand in a register
+ if gc.Ismem(f) && ((f.Type.IsFloat() && t.Type.IsInteger()) || (f.Type.IsInteger() && t.Type.IsFloat())) {
+ cvt = f.Type
+ goto hard
+ }
+
+ // a float32-to-float64 or float64-to-float32 conversion requires the source operand in a register
+ if gc.Ismem(f) && f.Type.IsFloat() && t.Type.IsFloat() && (ft != tt) {
+ cvt = f.Type
+ goto hard
+ }
+
+ // value -> value copy, only one memory operand.
+ // figure out the instruction to use.
+ // break out of switch for one-instruction gins.
+ // goto rdst for "destination must be register".
+ // goto hard for "convert to cvt type first".
+ // otherwise handle and return.
+ switch uint32(ft)<<16 | uint32(tt) {
+ default:
+ gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
+
+ // integer copy and truncate
+ case gc.TINT8<<16 | gc.TINT8,
+ gc.TUINT8<<16 | gc.TINT8,
+ gc.TINT16<<16 | gc.TINT8,
+ gc.TUINT16<<16 | gc.TINT8,
+ gc.TINT32<<16 | gc.TINT8,
+ gc.TUINT32<<16 | gc.TINT8,
+ gc.TINT64<<16 | gc.TINT8,
+ gc.TUINT64<<16 | gc.TINT8:
+ a = s390x.AMOVB
+
+ case gc.TINT8<<16 | gc.TUINT8,
+ gc.TUINT8<<16 | gc.TUINT8,
+ gc.TINT16<<16 | gc.TUINT8,
+ gc.TUINT16<<16 | gc.TUINT8,
+ gc.TINT32<<16 | gc.TUINT8,
+ gc.TUINT32<<16 | gc.TUINT8,
+ gc.TINT64<<16 | gc.TUINT8,
+ gc.TUINT64<<16 | gc.TUINT8:
+ a = s390x.AMOVBZ
+
+ case gc.TINT16<<16 | gc.TINT16,
+ gc.TUINT16<<16 | gc.TINT16,
+ gc.TINT32<<16 | gc.TINT16,
+ gc.TUINT32<<16 | gc.TINT16,
+ gc.TINT64<<16 | gc.TINT16,
+ gc.TUINT64<<16 | gc.TINT16:
+ a = s390x.AMOVH
+
+ case gc.TINT16<<16 | gc.TUINT16,
+ gc.TUINT16<<16 | gc.TUINT16,
+ gc.TINT32<<16 | gc.TUINT16,
+ gc.TUINT32<<16 | gc.TUINT16,
+ gc.TINT64<<16 | gc.TUINT16,
+ gc.TUINT64<<16 | gc.TUINT16:
+ a = s390x.AMOVHZ
+
+ case gc.TINT32<<16 | gc.TINT32,
+ gc.TUINT32<<16 | gc.TINT32,
+ gc.TINT64<<16 | gc.TINT32,
+ gc.TUINT64<<16 | gc.TINT32:
+ a = s390x.AMOVW
+
+ case gc.TINT32<<16 | gc.TUINT32,
+ gc.TUINT32<<16 | gc.TUINT32,
+ gc.TINT64<<16 | gc.TUINT32,
+ gc.TUINT64<<16 | gc.TUINT32:
+ a = s390x.AMOVWZ
+
+ case gc.TINT64<<16 | gc.TINT64,
+ gc.TINT64<<16 | gc.TUINT64,
+ gc.TUINT64<<16 | gc.TINT64,
+ gc.TUINT64<<16 | gc.TUINT64:
+ a = s390x.AMOVD
+
+ // sign extend int8
+ case gc.TINT8<<16 | gc.TINT16,
+ gc.TINT8<<16 | gc.TUINT16,
+ gc.TINT8<<16 | gc.TINT32,
+ gc.TINT8<<16 | gc.TUINT32,
+ gc.TINT8<<16 | gc.TINT64,
+ gc.TINT8<<16 | gc.TUINT64:
+ a = s390x.AMOVB
+ goto rdst
+
+ // sign extend uint8
+ case gc.TUINT8<<16 | gc.TINT16,
+ gc.TUINT8<<16 | gc.TUINT16,
+ gc.TUINT8<<16 | gc.TINT32,
+ gc.TUINT8<<16 | gc.TUINT32,
+ gc.TUINT8<<16 | gc.TINT64,
+ gc.TUINT8<<16 | gc.TUINT64:
+ a = s390x.AMOVBZ
+ goto rdst
+
+ // sign extend int16
+ case gc.TINT16<<16 | gc.TINT32,
+ gc.TINT16<<16 | gc.TUINT32,
+ gc.TINT16<<16 | gc.TINT64,
+ gc.TINT16<<16 | gc.TUINT64:
+ a = s390x.AMOVH
+ goto rdst
+
+ // zero extend uint16
+ case gc.TUINT16<<16 | gc.TINT32,
+ gc.TUINT16<<16 | gc.TUINT32,
+ gc.TUINT16<<16 | gc.TINT64,
+ gc.TUINT16<<16 | gc.TUINT64:
+ a = s390x.AMOVHZ
+ goto rdst
+
+ // sign extend int32
+ case gc.TINT32<<16 | gc.TINT64,
+ gc.TINT32<<16 | gc.TUINT64:
+ a = s390x.AMOVW
+ goto rdst
+
+ // zero extend uint32
+ case gc.TUINT32<<16 | gc.TINT64,
+ gc.TUINT32<<16 | gc.TUINT64:
+ a = s390x.AMOVWZ
+ goto rdst
+
+ // float to integer
+ case gc.TFLOAT32<<16 | gc.TUINT8,
+ gc.TFLOAT32<<16 | gc.TUINT16:
+ cvt = gc.Types[gc.TUINT32]
+ goto hard
+
+ case gc.TFLOAT32<<16 | gc.TUINT32:
+ a = s390x.ACLFEBR
+ goto rdst
+
+ case gc.TFLOAT32<<16 | gc.TUINT64:
+ a = s390x.ACLGEBR
+ goto rdst
+
+ case gc.TFLOAT64<<16 | gc.TUINT8,
+ gc.TFLOAT64<<16 | gc.TUINT16:
+ cvt = gc.Types[gc.TUINT32]
+ goto hard
+
+ case gc.TFLOAT64<<16 | gc.TUINT32:
+ a = s390x.ACLFDBR
+ goto rdst
+
+ case gc.TFLOAT64<<16 | gc.TUINT64:
+ a = s390x.ACLGDBR
+ goto rdst
+
+ case gc.TFLOAT32<<16 | gc.TINT8,
+ gc.TFLOAT32<<16 | gc.TINT16:
+ cvt = gc.Types[gc.TINT32]
+ goto hard
+
+ case gc.TFLOAT32<<16 | gc.TINT32:
+ a = s390x.ACFEBRA
+ goto rdst
+
+ case gc.TFLOAT32<<16 | gc.TINT64:
+ a = s390x.ACGEBRA
+ goto rdst
+
+ case gc.TFLOAT64<<16 | gc.TINT8,
+ gc.TFLOAT64<<16 | gc.TINT16:
+ cvt = gc.Types[gc.TINT32]
+ goto hard
+
+ case gc.TFLOAT64<<16 | gc.TINT32:
+ a = s390x.ACFDBRA
+ goto rdst
+
+ case gc.TFLOAT64<<16 | gc.TINT64:
+ a = s390x.ACGDBRA
+ goto rdst
+
+ // integer to float
+ case gc.TUINT8<<16 | gc.TFLOAT32,
+ gc.TUINT16<<16 | gc.TFLOAT32:
+ cvt = gc.Types[gc.TUINT32]
+ goto hard
+
+ case gc.TUINT32<<16 | gc.TFLOAT32:
+ a = s390x.ACELFBR
+ goto rdst
+
+ case gc.TUINT64<<16 | gc.TFLOAT32:
+ a = s390x.ACELGBR
+ goto rdst
+
+ case gc.TUINT8<<16 | gc.TFLOAT64,
+ gc.TUINT16<<16 | gc.TFLOAT64:
+ cvt = gc.Types[gc.TUINT32]
+ goto hard
+
+ case gc.TUINT32<<16 | gc.TFLOAT64:
+ a = s390x.ACDLFBR
+ goto rdst
+
+ case gc.TUINT64<<16 | gc.TFLOAT64:
+ a = s390x.ACDLGBR
+ goto rdst
+
+ case gc.TINT8<<16 | gc.TFLOAT32,
+ gc.TINT16<<16 | gc.TFLOAT32:
+ cvt = gc.Types[gc.TINT32]
+ goto hard
+
+ case gc.TINT32<<16 | gc.TFLOAT32:
+ a = s390x.ACEFBRA
+ goto rdst
+
+ case gc.TINT64<<16 | gc.TFLOAT32:
+ a = s390x.ACEGBRA
+ goto rdst
+
+ case gc.TINT8<<16 | gc.TFLOAT64,
+ gc.TINT16<<16 | gc.TFLOAT64:
+ cvt = gc.Types[gc.TINT32]
+ goto hard
+
+ case gc.TINT32<<16 | gc.TFLOAT64:
+ a = s390x.ACDFBRA
+ goto rdst
+
+ case gc.TINT64<<16 | gc.TFLOAT64:
+ a = s390x.ACDGBRA
+ goto rdst
+
+ // float to float
+ case gc.TFLOAT32<<16 | gc.TFLOAT32:
+ a = s390x.AFMOVS
+
+ case gc.TFLOAT64<<16 | gc.TFLOAT64:
+ a = s390x.AFMOVD
+
+ case gc.TFLOAT32<<16 | gc.TFLOAT64:
+ a = s390x.ALDEBR
+ goto rdst
+
+ case gc.TFLOAT64<<16 | gc.TFLOAT32:
+ a = s390x.ALEDBR
+ goto rdst
+ }
+
+ gins(a, f, t)
+ return
+
+ // requires register destination
+rdst:
+ if t != nil && t.Op == gc.OREGISTER {
+ gins(a, f, t)
+ return
+ } else {
+ var r1 gc.Node
+ gc.Regalloc(&r1, t.Type, t)
+
+ gins(a, f, &r1)
+ gmove(&r1, t)
+ gc.Regfree(&r1)
+ return
+ }
+
+ // requires register intermediate
+hard:
+ var r1 gc.Node
+ gc.Regalloc(&r1, cvt, t)
+
+ gmove(f, &r1)
+ gmove(&r1, t)
+ gc.Regfree(&r1)
+ return
+}
+
+func intLiteral(n *gc.Node) (x int64, ok bool) {
+ switch {
+ case n == nil:
+ return
+ case gc.Isconst(n, gc.CTINT):
+ return n.Int64(), true
+ case gc.Isconst(n, gc.CTBOOL):
+ return int64(obj.Bool2int(n.Bool())), true
+ }
+ return
+}
+
+// gins is called by the front end.
+// It synthesizes some multiple-instruction sequences
+// so the front end can stay simpler.
+func gins(as obj.As, f, t *gc.Node) *obj.Prog {
+ if t != nil {
+ if as >= obj.A_ARCHSPECIFIC {
+ if x, ok := intLiteral(f); ok {
+ ginscon(as, x, t)
+ return nil // caller must not use
+ }
+ }
+ if as == s390x.ACMP || as == s390x.ACMPU {
+ if x, ok := intLiteral(t); ok {
+ ginscon2(as, f, x)
+ return nil // caller must not use
+ }
+ }
+ }
+ return rawgins(as, f, t)
+}
+
+// generate one instruction:
+// as f, t
+func rawgins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
+ // self move check
+ // TODO(mundaym): use sized math and extend to MOVB, MOVWZ etc.
+ switch as {
+ case s390x.AMOVD, s390x.AFMOVS, s390x.AFMOVD:
+ if f != nil && t != nil &&
+ f.Op == gc.OREGISTER && t.Op == gc.OREGISTER &&
+ f.Reg == t.Reg {
+ return nil
+ }
+ }
+
+ p := gc.Prog(as)
+ gc.Naddr(&p.From, f)
+ gc.Naddr(&p.To, t)
+
+ switch as {
+ // Bad things the front end has done to us. Crash to find call stack.
+ case s390x.AMULLD:
+ if p.From.Type == obj.TYPE_CONST {
+ gc.Debug['h'] = 1
+ gc.Fatalf("bad inst: %v", p)
+ }
+ case s390x.ACMP, s390x.ACMPU:
+ if p.From.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_MEM {
+ gc.Debug['h'] = 1
+ gc.Fatalf("bad inst: %v", p)
+ }
+ }
+
+ if gc.Debug['g'] != 0 {
+ fmt.Printf("%v\n", p)
+ }
+
+ w := int32(0)
+ switch as {
+ case s390x.AMOVB, s390x.AMOVBZ:
+ w = 1
+
+ case s390x.AMOVH, s390x.AMOVHZ:
+ w = 2
+
+ case s390x.AMOVW, s390x.AMOVWZ:
+ w = 4
+
+ case s390x.AMOVD:
+ if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_ADDR {
+ break
+ }
+ w = 8
+ }
+
+ if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Type != obj.TYPE_REG && p.To.Width > int64(w))) {
+ gc.Dump("f", f)
+ gc.Dump("t", t)
+ gc.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
+ }
+
+ return p
+}
+
+// optoas returns the Axxx equivalent of Oxxx for type t
+func optoas(op gc.Op, t *gc.Type) obj.As {
+ if t == nil {
+ gc.Fatalf("optoas: t is nil")
+ }
+
+ // avoid constant conversions in switches below
+ const (
+ OMINUS_ = uint32(gc.OMINUS) << 16
+ OLSH_ = uint32(gc.OLSH) << 16
+ ORSH_ = uint32(gc.ORSH) << 16
+ OADD_ = uint32(gc.OADD) << 16
+ OSUB_ = uint32(gc.OSUB) << 16
+ OMUL_ = uint32(gc.OMUL) << 16
+ ODIV_ = uint32(gc.ODIV) << 16
+ OOR_ = uint32(gc.OOR) << 16
+ OAND_ = uint32(gc.OAND) << 16
+ OXOR_ = uint32(gc.OXOR) << 16
+ OEQ_ = uint32(gc.OEQ) << 16
+ ONE_ = uint32(gc.ONE) << 16
+ OLT_ = uint32(gc.OLT) << 16
+ OLE_ = uint32(gc.OLE) << 16
+ OGE_ = uint32(gc.OGE) << 16
+ OGT_ = uint32(gc.OGT) << 16
+ OCMP_ = uint32(gc.OCMP) << 16
+ OAS_ = uint32(gc.OAS) << 16
+ OHMUL_ = uint32(gc.OHMUL) << 16
+ OSQRT_ = uint32(gc.OSQRT) << 16
+ OLROT_ = uint32(gc.OLROT) << 16
+ )
+
+ a := obj.AXXX
+ switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
+ default:
+ gc.Fatalf("optoas: no entry for op=%v type=%v", op, t)
+
+ case OEQ_ | gc.TBOOL,
+ OEQ_ | gc.TINT8,
+ OEQ_ | gc.TUINT8,
+ OEQ_ | gc.TINT16,
+ OEQ_ | gc.TUINT16,
+ OEQ_ | gc.TINT32,
+ OEQ_ | gc.TUINT32,
+ OEQ_ | gc.TINT64,
+ OEQ_ | gc.TUINT64,
+ OEQ_ | gc.TPTR32,
+ OEQ_ | gc.TPTR64,
+ OEQ_ | gc.TFLOAT32,
+ OEQ_ | gc.TFLOAT64:
+ a = s390x.ABEQ
+
+ case ONE_ | gc.TBOOL,
+ ONE_ | gc.TINT8,
+ ONE_ | gc.TUINT8,
+ ONE_ | gc.TINT16,
+ ONE_ | gc.TUINT16,
+ ONE_ | gc.TINT32,
+ ONE_ | gc.TUINT32,
+ ONE_ | gc.TINT64,
+ ONE_ | gc.TUINT64,
+ ONE_ | gc.TPTR32,
+ ONE_ | gc.TPTR64,
+ ONE_ | gc.TFLOAT32,
+ ONE_ | gc.TFLOAT64:
+ a = s390x.ABNE
+
+ case OLT_ | gc.TINT8, // ACMP
+ OLT_ | gc.TINT16,
+ OLT_ | gc.TINT32,
+ OLT_ | gc.TINT64,
+ OLT_ | gc.TUINT8,
+ // ACMPU
+ OLT_ | gc.TUINT16,
+ OLT_ | gc.TUINT32,
+ OLT_ | gc.TUINT64,
+ OLT_ | gc.TFLOAT32,
+ // AFCMPU
+ OLT_ | gc.TFLOAT64:
+ a = s390x.ABLT
+
+ case OLE_ | gc.TINT8, // ACMP
+ OLE_ | gc.TINT16,
+ OLE_ | gc.TINT32,
+ OLE_ | gc.TINT64,
+ OLE_ | gc.TUINT8,
+ // ACMPU
+ OLE_ | gc.TUINT16,
+ OLE_ | gc.TUINT32,
+ OLE_ | gc.TUINT64,
+ OLE_ | gc.TFLOAT32,
+ OLE_ | gc.TFLOAT64:
+ a = s390x.ABLE
+
+ case OGT_ | gc.TINT8,
+ OGT_ | gc.TINT16,
+ OGT_ | gc.TINT32,
+ OGT_ | gc.TINT64,
+ OGT_ | gc.TUINT8,
+ OGT_ | gc.TUINT16,
+ OGT_ | gc.TUINT32,
+ OGT_ | gc.TUINT64,
+ OGT_ | gc.TFLOAT32,
+ OGT_ | gc.TFLOAT64:
+ a = s390x.ABGT
+
+ case OGE_ | gc.TINT8,
+ OGE_ | gc.TINT16,
+ OGE_ | gc.TINT32,
+ OGE_ | gc.TINT64,
+ OGE_ | gc.TUINT8,
+ OGE_ | gc.TUINT16,
+ OGE_ | gc.TUINT32,
+ OGE_ | gc.TUINT64,
+ OGE_ | gc.TFLOAT32,
+ OGE_ | gc.TFLOAT64:
+ a = s390x.ABGE
+
+ case OCMP_ | gc.TBOOL,
+ OCMP_ | gc.TINT8,
+ OCMP_ | gc.TINT16,
+ OCMP_ | gc.TINT32,
+ OCMP_ | gc.TPTR32,
+ OCMP_ | gc.TINT64:
+ a = s390x.ACMP
+
+ case OCMP_ | gc.TUINT8,
+ OCMP_ | gc.TUINT16,
+ OCMP_ | gc.TUINT32,
+ OCMP_ | gc.TUINT64,
+ OCMP_ | gc.TPTR64:
+ a = s390x.ACMPU
+
+ case OCMP_ | gc.TFLOAT32:
+ a = s390x.ACEBR
+
+ case OCMP_ | gc.TFLOAT64:
+ a = s390x.AFCMPU
+
+ case OAS_ | gc.TBOOL,
+ OAS_ | gc.TINT8:
+ a = s390x.AMOVB
+
+ case OAS_ | gc.TUINT8:
+ a = s390x.AMOVBZ
+
+ case OAS_ | gc.TINT16:
+ a = s390x.AMOVH
+
+ case OAS_ | gc.TUINT16:
+ a = s390x.AMOVHZ
+
+ case OAS_ | gc.TINT32:
+ a = s390x.AMOVW
+
+ case OAS_ | gc.TUINT32,
+ OAS_ | gc.TPTR32:
+ a = s390x.AMOVWZ
+
+ case OAS_ | gc.TINT64,
+ OAS_ | gc.TUINT64,
+ OAS_ | gc.TPTR64:
+ a = s390x.AMOVD
+
+ case OAS_ | gc.TFLOAT32:
+ a = s390x.AFMOVS
+
+ case OAS_ | gc.TFLOAT64:
+ a = s390x.AFMOVD
+
+ case OADD_ | gc.TINT8,
+ OADD_ | gc.TUINT8,
+ OADD_ | gc.TINT16,
+ OADD_ | gc.TUINT16,
+ OADD_ | gc.TINT32,
+ OADD_ | gc.TUINT32,
+ OADD_ | gc.TPTR32,
+ OADD_ | gc.TINT64,
+ OADD_ | gc.TUINT64,
+ OADD_ | gc.TPTR64:
+ a = s390x.AADD
+
+ case OADD_ | gc.TFLOAT32:
+ a = s390x.AFADDS
+
+ case OADD_ | gc.TFLOAT64:
+ a = s390x.AFADD
+
+ case OSUB_ | gc.TINT8,
+ OSUB_ | gc.TUINT8,
+ OSUB_ | gc.TINT16,
+ OSUB_ | gc.TUINT16,
+ OSUB_ | gc.TINT32,
+ OSUB_ | gc.TUINT32,
+ OSUB_ | gc.TPTR32,
+ OSUB_ | gc.TINT64,
+ OSUB_ | gc.TUINT64,
+ OSUB_ | gc.TPTR64:
+ a = s390x.ASUB
+
+ case OSUB_ | gc.TFLOAT32:
+ a = s390x.AFSUBS
+
+ case OSUB_ | gc.TFLOAT64:
+ a = s390x.AFSUB
+
+ case OMINUS_ | gc.TINT8,
+ OMINUS_ | gc.TUINT8,
+ OMINUS_ | gc.TINT16,
+ OMINUS_ | gc.TUINT16,
+ OMINUS_ | gc.TINT32,
+ OMINUS_ | gc.TUINT32,
+ OMINUS_ | gc.TPTR32,
+ OMINUS_ | gc.TINT64,
+ OMINUS_ | gc.TUINT64,
+ OMINUS_ | gc.TPTR64:
+ a = s390x.ANEG
+
+ case OAND_ | gc.TINT8,
+ OAND_ | gc.TUINT8,
+ OAND_ | gc.TINT16,
+ OAND_ | gc.TUINT16,
+ OAND_ | gc.TINT32,
+ OAND_ | gc.TUINT32,
+ OAND_ | gc.TPTR32,
+ OAND_ | gc.TINT64,
+ OAND_ | gc.TUINT64,
+ OAND_ | gc.TPTR64:
+ a = s390x.AAND
+
+ case OOR_ | gc.TINT8,
+ OOR_ | gc.TUINT8,
+ OOR_ | gc.TINT16,
+ OOR_ | gc.TUINT16,
+ OOR_ | gc.TINT32,
+ OOR_ | gc.TUINT32,
+ OOR_ | gc.TPTR32,
+ OOR_ | gc.TINT64,
+ OOR_ | gc.TUINT64,
+ OOR_ | gc.TPTR64:
+ a = s390x.AOR
+
+ case OXOR_ | gc.TINT8,
+ OXOR_ | gc.TUINT8,
+ OXOR_ | gc.TINT16,
+ OXOR_ | gc.TUINT16,
+ OXOR_ | gc.TINT32,
+ OXOR_ | gc.TUINT32,
+ OXOR_ | gc.TPTR32,
+ OXOR_ | gc.TINT64,
+ OXOR_ | gc.TUINT64,
+ OXOR_ | gc.TPTR64:
+ a = s390x.AXOR
+
+ case OLSH_ | gc.TINT8,
+ OLSH_ | gc.TUINT8,
+ OLSH_ | gc.TINT16,
+ OLSH_ | gc.TUINT16,
+ OLSH_ | gc.TINT32,
+ OLSH_ | gc.TUINT32,
+ OLSH_ | gc.TPTR32,
+ OLSH_ | gc.TINT64,
+ OLSH_ | gc.TUINT64,
+ OLSH_ | gc.TPTR64:
+ a = s390x.ASLD
+
+ case ORSH_ | gc.TUINT8,
+ ORSH_ | gc.TUINT16,
+ ORSH_ | gc.TUINT32,
+ ORSH_ | gc.TPTR32,
+ ORSH_ | gc.TUINT64,
+ ORSH_ | gc.TPTR64:
+ a = s390x.ASRD
+
+ case ORSH_ | gc.TINT8,
+ ORSH_ | gc.TINT16,
+ ORSH_ | gc.TINT32,
+ ORSH_ | gc.TINT64:
+ a = s390x.ASRAD
+
+ case OHMUL_ | gc.TINT64:
+ a = s390x.AMULHD
+
+ case OHMUL_ | gc.TUINT64,
+ OHMUL_ | gc.TPTR64:
+ a = s390x.AMULHDU
+
+ case OMUL_ | gc.TINT8,
+ OMUL_ | gc.TINT16,
+ OMUL_ | gc.TINT32,
+ OMUL_ | gc.TINT64:
+ a = s390x.AMULLD
+
+ case OMUL_ | gc.TUINT8,
+ OMUL_ | gc.TUINT16,
+ OMUL_ | gc.TUINT32,
+ OMUL_ | gc.TPTR32,
+ // don't use word multiply, the high 32-bit are undefined.
+ OMUL_ | gc.TUINT64,
+ OMUL_ | gc.TPTR64:
+ // for 64-bit multiplies, signedness doesn't matter.
+ a = s390x.AMULLD
+
+ case OMUL_ | gc.TFLOAT32:
+ a = s390x.AFMULS
+
+ case OMUL_ | gc.TFLOAT64:
+ a = s390x.AFMUL
+
+ case ODIV_ | gc.TINT8,
+ ODIV_ | gc.TINT16,
+ ODIV_ | gc.TINT32,
+ ODIV_ | gc.TINT64:
+ a = s390x.ADIVD
+
+ case ODIV_ | gc.TUINT8,
+ ODIV_ | gc.TUINT16,
+ ODIV_ | gc.TUINT32,
+ ODIV_ | gc.TPTR32,
+ ODIV_ | gc.TUINT64,
+ ODIV_ | gc.TPTR64:
+ a = s390x.ADIVDU
+
+ case ODIV_ | gc.TFLOAT32:
+ a = s390x.AFDIVS
+
+ case ODIV_ | gc.TFLOAT64:
+ a = s390x.AFDIV
+
+ case OSQRT_ | gc.TFLOAT64:
+ a = s390x.AFSQRT
+
+ case OLROT_ | gc.TUINT32,
+ OLROT_ | gc.TPTR32,
+ OLROT_ | gc.TINT32:
+ a = s390x.ARLL
+
+ case OLROT_ | gc.TUINT64,
+ OLROT_ | gc.TPTR64,
+ OLROT_ | gc.TINT64:
+ a = s390x.ARLLG
+ }
+
+ return a
+}
+
+const (
+ ODynam = 1 << 0
+ OAddable = 1 << 1
+)
+
+var clean [20]gc.Node
+
+var cleani int = 0
+
+func sudoclean() {
+ if clean[cleani-1].Op != gc.OEMPTY {
+ gc.Regfree(&clean[cleani-1])
+ }
+ if clean[cleani-2].Op != gc.OEMPTY {
+ gc.Regfree(&clean[cleani-2])
+ }
+ cleani -= 2
+}
+
+/*
+ * generate code to compute address of n,
+ * a reference to a (perhaps nested) field inside
+ * an array or struct.
+ * return 0 on failure, 1 on success.
+ * on success, leaves usable address in a.
+ *
+ * caller is responsible for calling sudoclean
+ * after successful sudoaddable,
+ * to release the register used for a.
+ */
+func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
+ if n.Type == nil {
+ return false
+ }
+
+ *a = obj.Addr{}
+
+ switch n.Op {
+ case gc.OLITERAL:
+ if !gc.Isconst(n, gc.CTINT) {
+ return false
+ }
+ v := n.Int64()
+ switch as {
+ default:
+ return false
+
+ // operations that can cope with a 32-bit immediate
+ // TODO(mundaym): logical operations can work on high bits
+ case s390x.AADD,
+ s390x.AADDC,
+ s390x.ASUB,
+ s390x.AMULLW,
+ s390x.AAND,
+ s390x.AOR,
+ s390x.AXOR,
+ s390x.ASLD,
+ s390x.ASLW,
+ s390x.ASRAW,
+ s390x.ASRAD,
+ s390x.ASRW,
+ s390x.ASRD,
+ s390x.AMOVB,
+ s390x.AMOVBZ,
+ s390x.AMOVH,
+ s390x.AMOVHZ,
+ s390x.AMOVW,
+ s390x.AMOVWZ,
+ s390x.AMOVD:
+ if int64(int32(v)) != v {
+ return false
+ }
+
+ // for comparisons avoid immediates unless they can
+ // fit into a int8/uint8
+ // this favours combined compare and branch instructions
+ case s390x.ACMP:
+ if int64(int8(v)) != v {
+ return false
+ }
+ case s390x.ACMPU:
+ if int64(uint8(v)) != v {
+ return false
+ }
+ }
+
+ cleani += 2
+ reg := &clean[cleani-1]
+ reg1 := &clean[cleani-2]
+ reg.Op = gc.OEMPTY
+ reg1.Op = gc.OEMPTY
+ gc.Naddr(a, n)
+ return true
+
+ case gc.ODOT,
+ gc.ODOTPTR:
+ cleani += 2
+ reg := &clean[cleani-1]
+ reg1 := &clean[cleani-2]
+ reg.Op = gc.OEMPTY
+ reg1.Op = gc.OEMPTY
+ var nn *gc.Node
+ var oary [10]int64
+ o := gc.Dotoffset(n, oary[:], &nn)
+ if nn == nil {
+ sudoclean()
+ return false
+ }
+
+ if nn.Addable && o == 1 && oary[0] >= 0 {
+ // directly addressable set of DOTs
+ n1 := *nn
+
+ n1.Type = n.Type
+ n1.Xoffset += oary[0]
+ // check that the offset fits into a 12-bit displacement
+ if n1.Xoffset < 0 || n1.Xoffset >= (1<<12)-8 {
+ sudoclean()
+ return false
+ }
+ gc.Naddr(a, &n1)
+ return true
+ }
+
+ gc.Regalloc(reg, gc.Types[gc.Tptr], nil)
+ n1 := *reg
+ n1.Op = gc.OINDREG
+ if oary[0] >= 0 {
+ gc.Agen(nn, reg)
+ n1.Xoffset = oary[0]
+ } else {
+ gc.Cgen(nn, reg)
+ gc.Cgen_checknil(reg)
+ n1.Xoffset = -(oary[0] + 1)
+ }
+
+ for i := 1; i < o; i++ {
+ if oary[i] >= 0 {
+ gc.Fatalf("can't happen")
+ }
+ gins(s390x.AMOVD, &n1, reg)
+ gc.Cgen_checknil(reg)
+ n1.Xoffset = -(oary[i] + 1)
+ }
+
+ a.Type = obj.TYPE_NONE
+ a.Index = 0
+ // check that the offset fits into a 12-bit displacement
+ if n1.Xoffset < 0 || n1.Xoffset >= (1<<12)-8 {
+ tmp := n1
+ tmp.Op = gc.OREGISTER
+ tmp.Type = gc.Types[gc.Tptr]
+ tmp.Xoffset = 0
+ gc.Cgen_checknil(&tmp)
+ ginscon(s390x.AADD, n1.Xoffset, &tmp)
+ n1.Xoffset = 0
+ }
+ gc.Naddr(a, &n1)
+ return true
+ }
+
+ return false
+}
diff --git a/src/cmd/compile/internal/s390x/peep.go b/src/cmd/compile/internal/s390x/peep.go
new file mode 100644
index 0000000000..cd6a8c5d8c
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/peep.go
@@ -0,0 +1,1664 @@
+// Derived from Inferno utils/6c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package s390x
+
+import (
+ "cmd/compile/internal/gc"
+ "cmd/internal/obj"
+ "cmd/internal/obj/s390x"
+ "fmt"
+)
+
+type usage int
+
+const (
+ _None usage = iota // no usage found
+ _Read // only read from
+ _ReadWriteSame // both read from and written to in a single operand
+ _Write // only written to
+ _ReadWriteDiff // both read from and written to in different operands
+)
+
+var gactive uint32
+
+func peep(firstp *obj.Prog) {
+ g := gc.Flowstart(firstp, nil)
+ if g == nil {
+ return
+ }
+ gactive = 0
+
+ run := func(name string, pass func(r *gc.Flow) int) int {
+ n := pass(g.Start)
+ if gc.Debug['P'] != 0 {
+ fmt.Println(name, ":", n)
+ }
+ if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+ gc.Dumpit(name, g.Start, 0)
+ }
+ return n
+ }
+
+ for {
+ n := 0
+ n += run("constant propagation", constantPropagation)
+ n += run("copy propagation", copyPropagation)
+ n += run("cast propagation", castPropagation)
+ n += run("remove load-hit-stores", removeLoadHitStores)
+ n += run("dead code elimination", deadCodeElimination)
+ if n == 0 {
+ break
+ }
+ }
+ run("fuse op moves", fuseOpMoves)
+ run("fuse clears", fuseClear)
+ run("load pipelining", loadPipelining)
+ run("fuse compare branch", fuseCompareBranch)
+ run("simplify ops", simplifyOps)
+ run("dead code elimination", deadCodeElimination)
+
+ // TODO(mundaym): load/store multiple aren't currently handled by copyu
+ // so this pass must be last.
+ run("fuse multiple", fuseMultiple)
+
+ gc.Flowend(g)
+}
+
+func pushback(r0 *gc.Flow) {
+ var r *gc.Flow
+
+ var b *gc.Flow
+ p0 := r0.Prog
+ for r = gc.Uniqp(r0); r != nil && gc.Uniqs(r) != nil; r = gc.Uniqp(r) {
+ p := r.Prog
+ if p.As != obj.ANOP {
+ if !(isReg(&p.From) || isConst(&p.From)) || !isReg(&p.To) {
+ break
+ }
+ if copyu(p, &p0.To, nil) != _None || copyu(p0, &p.To, nil) != _None {
+ break
+ }
+ }
+
+ if p.As == obj.ACALL {
+ break
+ }
+ b = r
+ }
+
+ if b == nil {
+ if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+ fmt.Printf("no pushback: %v\n", r0.Prog)
+ if r != nil {
+ fmt.Printf("\t%v [%v]\n", r.Prog, gc.Uniqs(r) != nil)
+ }
+ }
+
+ return
+ }
+
+ if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+ fmt.Printf("pushback\n")
+ for r := b; ; r = r.Link {
+ fmt.Printf("\t%v\n", r.Prog)
+ if r == r0 {
+ break
+ }
+ }
+ }
+
+ t := *r0.Prog
+ for r = gc.Uniqp(r0); ; r = gc.Uniqp(r) {
+ p0 = r.Link.Prog
+ p := r.Prog
+ p0.As = p.As
+ p0.Lineno = p.Lineno
+ p0.From = p.From
+ p0.To = p.To
+ p0.From3 = p.From3
+ p0.Reg = p.Reg
+ p0.RegTo2 = p.RegTo2
+ if r == b {
+ break
+ }
+ }
+
+ p0 = r.Prog
+ p0.As = t.As
+ p0.Lineno = t.Lineno
+ p0.From = t.From
+ p0.To = t.To
+ p0.From3 = t.From3
+ p0.Reg = t.Reg
+ p0.RegTo2 = t.RegTo2
+
+ if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+ fmt.Printf("\tafter\n")
+ for r := b; ; r = r.Link {
+ fmt.Printf("\t%v\n", r.Prog)
+ if r == r0 {
+ break
+ }
+ }
+ }
+}
+
+// excise replaces the given instruction with a NOP and clears
+// its operands.
+func excise(r *gc.Flow) {
+ p := r.Prog
+ if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+ fmt.Printf("%v ===delete===\n", p)
+ }
+ obj.Nopout(p)
+ gc.Ostats.Ndelmov++
+}
+
+// isZero returns true if a is either the constant 0 or the register
+// REGZERO.
+func isZero(a *obj.Addr) bool {
+ if a.Type == obj.TYPE_CONST && a.Offset == 0 {
+ return true
+ }
+ if a.Type == obj.TYPE_REG && a.Reg == s390x.REGZERO {
+ return true
+ }
+ return false
+}
+
+// isReg returns true if a is a general purpose or floating point
+// register (GPR or FPR).
+//
+// TODO(mundaym): currently this excludes REGZER0, but not other
+// special registers.
+func isReg(a *obj.Addr) bool {
+ return a.Type == obj.TYPE_REG &&
+ s390x.REG_R0 <= a.Reg &&
+ a.Reg <= s390x.REG_F15 &&
+ a.Reg != s390x.REGZERO
+}
+
+// isGPR returns true if a is a general purpose register (GPR).
+// REGZERO is treated as a GPR.
+func isGPR(a *obj.Addr) bool {
+ return a.Type == obj.TYPE_REG &&
+ s390x.REG_R0 <= a.Reg &&
+ a.Reg <= s390x.REG_R15
+}
+
+// isFPR returns true if a is a floating point register (FPR).
+func isFPR(a *obj.Addr) bool {
+ return a.Type == obj.TYPE_REG &&
+ s390x.REG_F0 <= a.Reg &&
+ a.Reg <= s390x.REG_F15
+}
+
+// isConst returns true if a refers to a constant (integer or
+// floating point, not string currently).
+func isConst(a *obj.Addr) bool {
+ return a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_FCONST
+}
+
+// isBDMem returns true if a refers to a memory location addressable by a
+// base register (B) and a displacement (D), such as:
+// x+8(R1)
+// and
+// 0(R10)
+// It returns false if the address contains an index register (X) such as:
+// 16(R1)(R2*1)
+// or if a relocation is required.
+func isBDMem(a *obj.Addr) bool {
+ return a.Type == obj.TYPE_MEM &&
+ a.Index == 0 &&
+ (a.Name == obj.NAME_NONE || a.Name == obj.NAME_AUTO || a.Name == obj.NAME_PARAM)
+}
+
+// the idea is to substitute
+// one register for another
+// from one MOV to another
+// MOV a, R1
+// ADD b, R1 / no use of R2
+// MOV R1, R2
+// would be converted to
+// MOV a, R2
+// ADD b, R2
+// MOV R2, R1
+// hopefully, then the former or latter MOV
+// will be eliminated by copy propagation.
+//
+// r0 (the argument, not the register) is the MOV at the end of the
+// above sequences. subprop returns true if it modified any instructions.
+func subprop(r0 *gc.Flow) bool {
+ p := r0.Prog
+ v1 := &p.From
+ if !isReg(v1) {
+ return false
+ }
+ v2 := &p.To
+ if !isReg(v2) {
+ return false
+ }
+ cast := false
+ switch p.As {
+ case s390x.AMOVW, s390x.AMOVWZ,
+ s390x.AMOVH, s390x.AMOVHZ,
+ s390x.AMOVB, s390x.AMOVBZ:
+ cast = true
+ }
+ for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
+ if gc.Uniqs(r) == nil {
+ break
+ }
+ p = r.Prog
+ switch copyu(p, v1, nil) {
+ case _Write, _ReadWriteDiff:
+ if p.As == obj.ACALL {
+ return false
+ }
+ if (!cast || p.As == r0.Prog.As) && p.To.Type == v1.Type && p.To.Reg == v1.Reg {
+ copysub(&p.To, v1, v2)
+ for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
+ p = r.Prog
+ copysub(&p.From, v1, v2)
+ copysub1(p, v1, v2)
+ copysub(&p.To, v1, v2)
+ }
+ v1.Reg, v2.Reg = v2.Reg, v1.Reg
+ return true
+ }
+ if cast {
+ return false
+ }
+ case _ReadWriteSame:
+ if cast {
+ return false
+ }
+ }
+ if copyu(p, v2, nil) != _None {
+ return false
+ }
+ }
+ return false
+}
+
+// The idea is to remove redundant copies.
+// v1->v2 F=0
+// (use v2 s/v2/v1/)*
+// set v1 F=1
+// use v2 return fail (v1->v2 move must remain)
+// -----------------
+// v1->v2 F=0
+// (use v2 s/v2/v1/)*
+// set v1 F=1
+// set v2 return success (caller can remove v1->v2 move)
+func copyprop(r *gc.Flow) bool {
+ p := r.Prog
+
+ canSub := false
+ switch p.As {
+ case s390x.AFMOVS, s390x.AFMOVD, s390x.AMOVD:
+ canSub = true
+ default:
+ for rr := gc.Uniqp(r); rr != nil; rr = gc.Uniqp(rr) {
+ if gc.Uniqs(rr) == nil {
+ break
+ }
+ switch copyu(rr.Prog, &p.From, nil) {
+ case _Read, _None:
+ continue
+ }
+ // write
+ if rr.Prog.As == p.As {
+ canSub = true
+ }
+ break
+ }
+ }
+ if !canSub {
+ return false
+ }
+ if copyas(&p.From, &p.To) {
+ return true
+ }
+
+ gactive++
+ return copy1(&p.From, &p.To, r.S1, 0)
+}
+
+// copy1 replaces uses of v2 with v1 starting at r and returns true if
+// all uses were rewritten.
+func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
+ if uint32(r.Active) == gactive {
+ return true
+ }
+ r.Active = int32(gactive)
+ for ; r != nil; r = r.S1 {
+ p := r.Prog
+ if f == 0 && gc.Uniqp(r) == nil {
+ // Multiple predecessors; conservatively
+ // assume v1 was set on other path
+ f = 1
+ }
+ t := copyu(p, v2, nil)
+ switch t {
+ case _ReadWriteSame:
+ return false
+ case _Write:
+ return true
+ case _Read, _ReadWriteDiff:
+ if f != 0 {
+ return false
+ }
+ if copyu(p, v2, v1) != 0 {
+ return false
+ }
+ if t == _ReadWriteDiff {
+ return true
+ }
+ }
+ if f == 0 {
+ switch copyu(p, v1, nil) {
+ case _ReadWriteSame, _ReadWriteDiff, _Write:
+ f = 1
+ }
+ }
+ if r.S2 != nil {
+ if !copy1(v1, v2, r.S2, f) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// If s==nil, copyu returns the set/use of v in p; otherwise, it
+// modifies p to replace reads of v with reads of s and returns 0 for
+// success or non-zero for failure.
+//
+// If s==nil, copy returns one of the following values:
+// _Read if v only used
+// _ReadWriteSame if v is set and used in one address (read-alter-rewrite;
+// can't substitute)
+// _Write if v is only set
+// _ReadWriteDiff if v is set in one address and used in another (so addresses
+// can be rewritten independently)
+// _None otherwise (not touched)
+func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) usage {
+ if p.From3Type() != obj.TYPE_NONE && p.From3Type() != obj.TYPE_CONST {
+ // Currently we never generate a From3 with anything other than a constant in it.
+ fmt.Printf("copyu: From3 (%v) not implemented\n", gc.Ctxt.Dconv(p.From3))
+ }
+
+ switch p.As {
+ default:
+ fmt.Printf("copyu: can't find %v\n", obj.Aconv(p.As))
+ return _ReadWriteSame
+
+ case // read p.From, write p.To
+ s390x.AMOVH,
+ s390x.AMOVHZ,
+ s390x.AMOVB,
+ s390x.AMOVBZ,
+ s390x.AMOVW,
+ s390x.AMOVWZ,
+ s390x.AMOVD,
+ s390x.ANEG,
+ s390x.AADDME,
+ s390x.AADDZE,
+ s390x.ASUBME,
+ s390x.ASUBZE,
+ s390x.AFMOVS,
+ s390x.AFMOVD,
+ s390x.ALEDBR,
+ s390x.AFNEG,
+ s390x.ALDEBR,
+ s390x.ACLFEBR,
+ s390x.ACLGEBR,
+ s390x.ACLFDBR,
+ s390x.ACLGDBR,
+ s390x.ACFEBRA,
+ s390x.ACGEBRA,
+ s390x.ACFDBRA,
+ s390x.ACGDBRA,
+ s390x.ACELFBR,
+ s390x.ACELGBR,
+ s390x.ACDLFBR,
+ s390x.ACDLGBR,
+ s390x.ACEFBRA,
+ s390x.ACEGBRA,
+ s390x.ACDFBRA,
+ s390x.ACDGBRA,
+ s390x.AFSQRT:
+
+ if s != nil {
+ copysub(&p.From, v, s)
+
+ // Update only indirect uses of v in p.To
+ if !copyas(&p.To, v) {
+ copysub(&p.To, v, s)
+ }
+ return _None
+ }
+
+ if copyas(&p.To, v) {
+ // Fix up implicit from
+ if p.From.Type == obj.TYPE_NONE {
+ p.From = p.To
+ }
+ if copyau(&p.From, v) {
+ return _ReadWriteDiff
+ }
+ return _Write
+ }
+
+ if copyau(&p.From, v) {
+ return _Read
+ }
+ if copyau(&p.To, v) {
+ // p.To only indirectly uses v
+ return _Read
+ }
+
+ return _None
+
+ // read p.From, read p.Reg, write p.To
+ case s390x.AADD,
+ s390x.AADDC,
+ s390x.AADDE,
+ s390x.ASUB,
+ s390x.ASLW,
+ s390x.ASRW,
+ s390x.ASRAW,
+ s390x.ASLD,
+ s390x.ASRD,
+ s390x.ASRAD,
+ s390x.ARLL,
+ s390x.ARLLG,
+ s390x.AOR,
+ s390x.AORN,
+ s390x.AAND,
+ s390x.AANDN,
+ s390x.ANAND,
+ s390x.ANOR,
+ s390x.AXOR,
+ s390x.AMULLW,
+ s390x.AMULLD,
+ s390x.AMULHD,
+ s390x.AMULHDU,
+ s390x.ADIVW,
+ s390x.ADIVD,
+ s390x.ADIVWU,
+ s390x.ADIVDU,
+ s390x.AFADDS,
+ s390x.AFADD,
+ s390x.AFSUBS,
+ s390x.AFSUB,
+ s390x.AFMULS,
+ s390x.AFMUL,
+ s390x.AFDIVS,
+ s390x.AFDIV:
+ if s != nil {
+ copysub(&p.From, v, s)
+ copysub1(p, v, s)
+
+ // Update only indirect uses of v in p.To
+ if !copyas(&p.To, v) {
+ copysub(&p.To, v, s)
+ }
+ }
+
+ if copyas(&p.To, v) {
+ if p.Reg == 0 {
+ p.Reg = p.To.Reg
+ }
+ if copyau(&p.From, v) || copyau1(p, v) {
+ return _ReadWriteDiff
+ }
+ return _Write
+ }
+
+ if copyau(&p.From, v) {
+ return _Read
+ }
+ if copyau1(p, v) {
+ return _Read
+ }
+ if copyau(&p.To, v) {
+ return _Read
+ }
+ return _None
+
+ case s390x.ABEQ,
+ s390x.ABGT,
+ s390x.ABGE,
+ s390x.ABLT,
+ s390x.ABLE,
+ s390x.ABNE,
+ s390x.ABVC,
+ s390x.ABVS:
+ return _None
+
+ case obj.ACHECKNIL, // read p.From
+ s390x.ACMP, // read p.From, read p.To
+ s390x.ACMPU,
+ s390x.ACMPW,
+ s390x.ACMPWU,
+ s390x.AFCMPO,
+ s390x.AFCMPU,
+ s390x.ACEBR,
+ s390x.AMVC,
+ s390x.ACLC,
+ s390x.AXC,
+ s390x.AOC,
+ s390x.ANC:
+ if s != nil {
+ copysub(&p.From, v, s)
+ copysub(&p.To, v, s)
+ return _None
+ }
+
+ if copyau(&p.From, v) {
+ return _Read
+ }
+ if copyau(&p.To, v) {
+ return _Read
+ }
+ return _None
+
+ case s390x.ACMPBNE, s390x.ACMPBEQ,
+ s390x.ACMPBLT, s390x.ACMPBLE,
+ s390x.ACMPBGT, s390x.ACMPBGE,
+ s390x.ACMPUBNE, s390x.ACMPUBEQ,
+ s390x.ACMPUBLT, s390x.ACMPUBLE,
+ s390x.ACMPUBGT, s390x.ACMPUBGE:
+ if s != nil {
+ copysub(&p.From, v, s)
+ copysub1(p, v, s)
+ return _None
+ }
+ if copyau(&p.From, v) {
+ return _Read
+ }
+ if copyau1(p, v) {
+ return _Read
+ }
+ return _None
+
+ case s390x.ACLEAR:
+ if s != nil {
+ copysub(&p.To, v, s)
+ return _None
+ }
+ if copyau(&p.To, v) {
+ return _Read
+ }
+ return _None
+
+ // go never generates a branch to a GPR
+ // read p.To
+ case s390x.ABR:
+ if s != nil {
+ copysub(&p.To, v, s)
+ return _None
+ }
+
+ if copyau(&p.To, v) {
+ return _Read
+ }
+ return _None
+
+ case obj.ARET, obj.AUNDEF:
+ if s != nil {
+ return _None
+ }
+
+ // All registers die at this point, so claim
+ // everything is set (and not used).
+ return _Write
+
+ case s390x.ABL:
+ if v.Type == obj.TYPE_REG {
+ if s390x.REGARG != -1 && v.Reg == s390x.REGARG {
+ return _ReadWriteSame
+ }
+ if p.From.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
+ return _ReadWriteSame
+ }
+ if v.Reg == s390x.REGZERO {
+ // Deliberately inserted nops set R0.
+ return _ReadWriteSame
+ }
+ if v.Reg == s390x.REGCTXT {
+ // Context register for closures.
+ // TODO(mundaym): not sure if we need to exclude this.
+ return _ReadWriteSame
+ }
+ }
+ if s != nil {
+ copysub(&p.To, v, s)
+ return _None
+ }
+ if copyau(&p.To, v) {
+ return _ReadWriteDiff
+ }
+ return _Write
+
+ case obj.ATEXT:
+ if v.Type == obj.TYPE_REG {
+ if v.Reg == s390x.REGARG {
+ return _Write
+ }
+ }
+ return _None
+
+ case obj.APCDATA,
+ obj.AFUNCDATA,
+ obj.AVARDEF,
+ obj.AVARKILL,
+ obj.AVARLIVE,
+ obj.AUSEFIELD,
+ obj.ANOP:
+ return _None
+ }
+}
+
+// copyas returns 1 if a and v address the same register.
+//
+// If a is the from operand, this means this operation reads the
+// register in v. If a is the to operand, this means this operation
+// writes the register in v.
+func copyas(a *obj.Addr, v *obj.Addr) bool {
+ if isReg(v) {
+ if a.Type == v.Type {
+ if a.Reg == v.Reg {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// copyau returns 1 if a either directly or indirectly addresses the
+// same register as v.
+//
+// If a is the from operand, this means this operation reads the
+// register in v. If a is the to operand, this means the operation
+// either reads or writes the register in v (if !copyas(a, v), then
+// the operation reads the register in v).
+func copyau(a *obj.Addr, v *obj.Addr) bool {
+ if copyas(a, v) {
+ return true
+ }
+ if v.Type == obj.TYPE_REG {
+ if a.Type == obj.TYPE_MEM || (a.Type == obj.TYPE_ADDR && a.Reg != 0) {
+ if v.Reg == a.Reg {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// copyau1 returns 1 if p.Reg references the same register as v and v
+// is a direct reference.
+func copyau1(p *obj.Prog, v *obj.Addr) bool {
+ if isReg(v) && v.Reg != 0 {
+ if p.Reg == v.Reg {
+ return true
+ }
+ }
+ return false
+}
+
+// copysub replaces v.Reg with s.Reg if a.Reg and v.Reg are direct
+// references to the same register.
+func copysub(a, v, s *obj.Addr) {
+ if copyau(a, v) {
+ a.Reg = s.Reg
+ }
+}
+
+// copysub1 replaces p.Reg with s.Reg if p.Reg and v.Reg are direct
+// references to the same register.
+func copysub1(p *obj.Prog, v, s *obj.Addr) {
+ if copyau1(p, v) {
+ p.Reg = s.Reg
+ }
+}
+
+func sameaddr(a *obj.Addr, v *obj.Addr) bool {
+ if a.Type != v.Type {
+ return false
+ }
+ if isReg(v) && a.Reg == v.Reg {
+ return true
+ }
+ if v.Type == obj.NAME_AUTO || v.Type == obj.NAME_PARAM {
+ // TODO(mundaym): is the offset enough here? Node?
+ if v.Offset == a.Offset {
+ return true
+ }
+ }
+ return false
+}
+
+func smallindir(a *obj.Addr, reg *obj.Addr) bool {
+ return reg.Type == obj.TYPE_REG &&
+ a.Type == obj.TYPE_MEM &&
+ a.Reg == reg.Reg &&
+ 0 <= a.Offset && a.Offset < 4096
+}
+
+func stackaddr(a *obj.Addr) bool {
+ // TODO(mundaym): the name implies this should check
+ // for TYPE_ADDR with a base register REGSP.
+ return a.Type == obj.TYPE_REG && a.Reg == s390x.REGSP
+}
+
+// isMove returns true if p is a move. Moves may imply
+// sign/zero extension.
+func isMove(p *obj.Prog) bool {
+ switch p.As {
+ case s390x.AMOVD,
+ s390x.AMOVW, s390x.AMOVWZ,
+ s390x.AMOVH, s390x.AMOVHZ,
+ s390x.AMOVB, s390x.AMOVBZ,
+ s390x.AFMOVD, s390x.AFMOVS:
+ return true
+ }
+ return false
+}
+
+// isLoad returns true if p is a move from memory to a register.
+func isLoad(p *obj.Prog) bool {
+ if !isMove(p) {
+ return false
+ }
+ if !(isGPR(&p.To) || isFPR(&p.To)) {
+ return false
+ }
+ if p.From.Type != obj.TYPE_MEM {
+ return false
+ }
+ return true
+}
+
+// isStore returns true if p is a move from a register to memory.
+func isStore(p *obj.Prog) bool {
+ if !isMove(p) {
+ return false
+ }
+ if !(isGPR(&p.From) || isFPR(&p.From) || isConst(&p.From)) {
+ return false
+ }
+ if p.To.Type != obj.TYPE_MEM {
+ return false
+ }
+ return true
+}
+
+// sameStackMem returns true if a and b are both memory operands
+// and address the same location which must reside on the stack.
+func sameStackMem(a, b *obj.Addr) bool {
+ if a.Type != obj.TYPE_MEM ||
+ b.Type != obj.TYPE_MEM ||
+ a.Name != b.Name ||
+ a.Sym != b.Sym ||
+ a.Node != b.Node ||
+ a.Reg != b.Reg ||
+ a.Index != b.Index ||
+ a.Offset != b.Offset {
+ return false
+ }
+ switch a.Name {
+ case obj.NAME_NONE:
+ return a.Reg == s390x.REGSP
+ case obj.NAME_PARAM, obj.NAME_AUTO:
+ // params and autos are always on the stack
+ return true
+ }
+ return false
+}
+
+// removeLoadHitStores trys to remove loads that take place
+// immediately after a store to the same location. Returns
+// true if load-hit-stores were removed.
+//
+// For example:
+// MOVD R1, 0(R15)
+// MOVD 0(R15), R2
+// Would become:
+// MOVD R1, 0(R15)
+// MOVD R1, R2
+func removeLoadHitStores(r *gc.Flow) int {
+ n := 0
+ for ; r != nil; r = r.Link {
+ p := r.Prog
+ if !isStore(p) {
+ continue
+ }
+ for rr := gc.Uniqs(r); rr != nil; rr = gc.Uniqs(rr) {
+ pp := rr.Prog
+ if gc.Uniqp(rr) == nil {
+ break
+ }
+ if pp.As == obj.ANOP {
+ continue
+ }
+ if isLoad(pp) && sameStackMem(&p.To, &pp.From) {
+ if size(p.As) >= size(pp.As) && isGPR(&p.From) == isGPR(&pp.To) {
+ pp.From = p.From
+ }
+ }
+ if !isMove(pp) || isStore(pp) {
+ break
+ }
+ if copyau(&p.From, &pp.To) {
+ break
+ }
+ }
+ }
+ return n
+}
+
+// size returns the width of the given move.
+func size(as obj.As) int {
+ switch as {
+ case s390x.AMOVD, s390x.AFMOVD:
+ return 8
+ case s390x.AMOVW, s390x.AMOVWZ, s390x.AFMOVS:
+ return 4
+ case s390x.AMOVH, s390x.AMOVHZ:
+ return 2
+ case s390x.AMOVB, s390x.AMOVBZ:
+ return 1
+ }
+ return -1
+}
+
+// castPropagation tries to eliminate unecessary casts.
+//
+// For example:
+// MOVHZ R1, R2 // uint16
+// MOVB R2, 0(R15) // int8
+// Can be simplified to:
+// MOVB R1, 0(R15)
+func castPropagation(r *gc.Flow) int {
+ n := 0
+ for ; r != nil; r = r.Link {
+ p := r.Prog
+ if !isMove(p) || !isGPR(&p.To) {
+ continue
+ }
+
+ // r is a move with a destination register
+ var move *gc.Flow
+ for rr := gc.Uniqs(r); rr != nil; rr = gc.Uniqs(rr) {
+ if gc.Uniqp(rr) == nil {
+ // branch target: leave alone
+ break
+ }
+ pp := rr.Prog
+ if isMove(pp) && copyas(&pp.From, &p.To) {
+ if pp.To.Type == obj.TYPE_MEM {
+ if p.From.Type == obj.TYPE_MEM ||
+ p.From.Type == obj.TYPE_ADDR {
+ break
+ }
+ if p.From.Type == obj.TYPE_CONST &&
+ int64(int16(p.From.Offset)) != p.From.Offset {
+ break
+ }
+ }
+ move = rr
+ break
+ }
+ if pp.As == obj.ANOP {
+ continue
+ }
+ break
+ }
+ if move == nil {
+ continue
+ }
+
+ // we have a move that reads from our destination reg, check if any future
+ // instructions also read from the reg
+ mp := move.Prog
+ if !copyas(&mp.From, &mp.To) {
+ safe := false
+ for rr := gc.Uniqs(move); rr != nil; rr = gc.Uniqs(rr) {
+ if gc.Uniqp(rr) == nil {
+ break
+ }
+ switch copyu(rr.Prog, &p.To, nil) {
+ case _None:
+ continue
+ case _Write:
+ safe = true
+ }
+ break
+ }
+ if !safe {
+ continue
+ }
+ }
+
+ // at this point we have something like:
+ // MOV* const/mem/reg, reg
+ // MOV* reg, reg/mem
+ // now check if this is a cast that cannot be forward propagated
+ execute := false
+ if p.As == mp.As || isZero(&p.From) || size(p.As) == size(mp.As) {
+ execute = true
+ } else if isGPR(&p.From) && size(p.As) >= size(mp.As) {
+ execute = true
+ }
+
+ if execute {
+ mp.From = p.From
+ excise(r)
+ n++
+ }
+ }
+ return n
+}
+
+// fuseClear merges memory clear operations.
+//
+// Looks for this pattern (sequence of clears):
+// MOVD R0, n(R15)
+// MOVD R0, n+8(R15)
+// MOVD R0, n+16(R15)
+// Replaces with:
+// CLEAR $24, n(R15)
+func fuseClear(r *gc.Flow) int {
+ n := 0
+ var align int64
+ var clear *obj.Prog
+ for ; r != nil; r = r.Link {
+ // If there is a branch into the instruction stream then
+ // we can't fuse into previous instructions.
+ if gc.Uniqp(r) == nil {
+ clear = nil
+ }
+
+ p := r.Prog
+ if p.As == obj.ANOP {
+ continue
+ }
+ if p.As == s390x.AXC {
+ if p.From.Reg == p.To.Reg && p.From.Offset == p.To.Offset {
+ // TODO(mundaym): merge clears?
+ p.As = s390x.ACLEAR
+ p.From.Offset = p.From3.Offset
+ p.From3 = nil
+ p.From.Type = obj.TYPE_CONST
+ p.From.Reg = 0
+ clear = p
+ } else {
+ clear = nil
+ }
+ continue
+ }
+
+ // Is our source a constant zero?
+ if !isZero(&p.From) {
+ clear = nil
+ continue
+ }
+
+ // Are we moving to memory?
+ if p.To.Type != obj.TYPE_MEM ||
+ p.To.Index != 0 ||
+ p.To.Offset >= 4096 ||
+ !(p.To.Name == obj.NAME_NONE || p.To.Name == obj.NAME_AUTO || p.To.Name == obj.NAME_PARAM) {
+ clear = nil
+ continue
+ }
+
+ size := int64(0)
+ switch p.As {
+ default:
+ clear = nil
+ continue
+ case s390x.AMOVB, s390x.AMOVBZ:
+ size = 1
+ case s390x.AMOVH, s390x.AMOVHZ:
+ size = 2
+ case s390x.AMOVW, s390x.AMOVWZ:
+ size = 4
+ case s390x.AMOVD:
+ size = 8
+ }
+
+ // doubleword aligned clears should be kept doubleword
+ // aligned
+ if (size == 8 && align != 8) || (size != 8 && align == 8) {
+ clear = nil
+ }
+
+ if clear != nil &&
+ clear.To.Reg == p.To.Reg &&
+ clear.To.Name == p.To.Name &&
+ clear.To.Node == p.To.Node &&
+ clear.To.Sym == p.To.Sym {
+
+ min := clear.To.Offset
+ max := clear.To.Offset + clear.From.Offset
+
+ // previous clear is already clearing this region
+ if min <= p.To.Offset && max >= p.To.Offset+size {
+ excise(r)
+ n++
+ continue
+ }
+
+ // merge forwards
+ if max == p.To.Offset {
+ clear.From.Offset += size
+ excise(r)
+ n++
+ continue
+ }
+
+ // merge backwards
+ if min-size == p.To.Offset {
+ clear.From.Offset += size
+ clear.To.Offset -= size
+ excise(r)
+ n++
+ continue
+ }
+ }
+
+ // transform into clear
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = size
+ p.From.Reg = 0
+ p.As = s390x.ACLEAR
+ clear = p
+ align = size
+ }
+ return n
+}
+
+// fuseMultiple merges memory loads and stores into load multiple and
+// store multiple operations.
+//
+// Looks for this pattern (sequence of loads or stores):
+// MOVD R1, 0(R15)
+// MOVD R2, 8(R15)
+// MOVD R3, 16(R15)
+// Replaces with:
+// STMG R1, R3, 0(R15)
+func fuseMultiple(r *gc.Flow) int {
+ n := 0
+ var fused *obj.Prog
+ for ; r != nil; r = r.Link {
+ // If there is a branch into the instruction stream then
+ // we can't fuse into previous instructions.
+ if gc.Uniqp(r) == nil {
+ fused = nil
+ }
+
+ p := r.Prog
+
+ isStore := isGPR(&p.From) && isBDMem(&p.To)
+ isLoad := isGPR(&p.To) && isBDMem(&p.From)
+
+ // are we a candidate?
+ size := int64(0)
+ switch p.As {
+ default:
+ fused = nil
+ continue
+ case obj.ANOP:
+ // skip over nops
+ continue
+ case s390x.AMOVW, s390x.AMOVWZ:
+ size = 4
+ // TODO(mundaym): 32-bit load multiple is currently not supported
+ // as it requires sign/zero extension.
+ if !isStore {
+ fused = nil
+ continue
+ }
+ case s390x.AMOVD:
+ size = 8
+ if !isLoad && !isStore {
+ fused = nil
+ continue
+ }
+ }
+
+ // If we merge two loads/stores with different source/destination Nodes
+ // then we will lose a reference the second Node which means that the
+ // compiler might mark the Node as unused and free its slot on the stack.
+ // TODO(mundaym): allow this by adding a dummy reference to the Node.
+ if fused == nil ||
+ fused.From.Node != p.From.Node ||
+ fused.From.Type != p.From.Type ||
+ fused.To.Node != p.To.Node ||
+ fused.To.Type != p.To.Type {
+ fused = p
+ continue
+ }
+
+ // check two addresses
+ ca := func(a, b *obj.Addr, offset int64) bool {
+ return a.Reg == b.Reg && a.Offset+offset == b.Offset &&
+ a.Sym == b.Sym && a.Name == b.Name
+ }
+
+ switch fused.As {
+ default:
+ fused = p
+ case s390x.AMOVW, s390x.AMOVWZ:
+ if size == 4 && fused.From.Reg+1 == p.From.Reg && ca(&fused.To, &p.To, 4) {
+ fused.As = s390x.ASTMY
+ fused.Reg = p.From.Reg
+ excise(r)
+ n++
+ } else {
+ fused = p
+ }
+ case s390x.AMOVD:
+ if size == 8 && fused.From.Reg+1 == p.From.Reg && ca(&fused.To, &p.To, 8) {
+ fused.As = s390x.ASTMG
+ fused.Reg = p.From.Reg
+ excise(r)
+ n++
+ } else if size == 8 && fused.To.Reg+1 == p.To.Reg && ca(&fused.From, &p.From, 8) {
+ fused.As = s390x.ALMG
+ fused.Reg = fused.To.Reg
+ fused.To.Reg = p.To.Reg
+ excise(r)
+ n++
+ } else {
+ fused = p
+ }
+ case s390x.ASTMG, s390x.ASTMY:
+ if (fused.As == s390x.ASTMY && size != 4) ||
+ (fused.As == s390x.ASTMG && size != 8) {
+ fused = p
+ continue
+ }
+ offset := size * int64(fused.Reg-fused.From.Reg+1)
+ if fused.Reg+1 == p.From.Reg && ca(&fused.To, &p.To, offset) {
+ fused.Reg = p.From.Reg
+ excise(r)
+ n++
+ } else {
+ fused = p
+ }
+ case s390x.ALMG:
+ offset := 8 * int64(fused.To.Reg-fused.Reg+1)
+ if size == 8 && fused.To.Reg+1 == p.To.Reg && ca(&fused.From, &p.From, offset) {
+ fused.To.Reg = p.To.Reg
+ excise(r)
+ n++
+ } else {
+ fused = p
+ }
+ }
+ }
+ return n
+}
+
+// simplifyOps looks for side-effect free ops that can be removed or
+// replaced with moves.
+//
+// For example:
+// XOR $0, R1 => NOP
+// ADD $0, R1, R2 => MOVD R1, R2
+func simplifyOps(r *gc.Flow) int {
+ n := 0
+ for ; r != nil; r = r.Link {
+ p := r.Prog
+
+ // if the target is R0 then this is a required NOP
+ if isGPR(&p.To) && p.To.Reg == s390x.REGZERO {
+ continue
+ }
+
+ switch p.As {
+ case s390x.AADD, s390x.ASUB,
+ s390x.AOR, s390x.AXOR,
+ s390x.ASLW, s390x.ASRW, s390x.ASRAW,
+ s390x.ASLD, s390x.ASRD, s390x.ASRAD,
+ s390x.ARLL, s390x.ARLLG:
+ if isZero(&p.From) && isGPR(&p.To) {
+ if p.Reg == 0 || p.Reg == p.To.Reg {
+ excise(r)
+ n++
+ } else {
+ p.As = s390x.AMOVD
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = p.Reg
+ p.Reg = 0
+ }
+ }
+ case s390x.AMULLW, s390x.AAND:
+ if isZero(&p.From) && isGPR(&p.To) {
+ p.As = s390x.AMOVD
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = s390x.REGZERO
+ p.Reg = 0
+ }
+ }
+ }
+ return n
+}
+
+// fuseOpMoves looks for moves following 2-operand operations and trys to merge them into
+// a 3-operand operation.
+//
+// For example:
+// ADD R1, R2
+// MOVD R2, R3
+// might become
+// ADD R1, R2, R3
+func fuseOpMoves(r *gc.Flow) int {
+ n := 0
+ for ; r != nil; r = r.Link {
+ p := r.Prog
+ switch p.As {
+ case s390x.AADD:
+ case s390x.ASUB:
+ if isConst(&p.From) && int64(int16(p.From.Offset)) != p.From.Offset {
+ continue
+ }
+ case s390x.ASLW,
+ s390x.ASRW,
+ s390x.ASRAW,
+ s390x.ASLD,
+ s390x.ASRD,
+ s390x.ASRAD,
+ s390x.ARLL,
+ s390x.ARLLG:
+ // ok - p.From will be a reg or a constant
+ case s390x.AOR,
+ s390x.AORN,
+ s390x.AAND,
+ s390x.AANDN,
+ s390x.ANAND,
+ s390x.ANOR,
+ s390x.AXOR,
+ s390x.AMULLW,
+ s390x.AMULLD:
+ if isConst(&p.From) {
+ // these instructions can either use 3 register form
+ // or have an immediate but not both
+ continue
+ }
+ default:
+ continue
+ }
+
+ if p.Reg != 0 && p.Reg != p.To.Reg {
+ continue
+ }
+
+ var move *gc.Flow
+ rr := gc.Uniqs(r)
+ for {
+ if rr == nil || gc.Uniqp(rr) == nil || rr == r {
+ break
+ }
+ pp := rr.Prog
+ switch copyu(pp, &p.To, nil) {
+ case _None:
+ rr = gc.Uniqs(rr)
+ continue
+ case _Read:
+ if move == nil && pp.As == s390x.AMOVD && isGPR(&pp.From) && isGPR(&pp.To) {
+ move = rr
+ rr = gc.Uniqs(rr)
+ continue
+ }
+ case _Write:
+ if move == nil {
+ // dead code
+ excise(r)
+ n++
+ } else {
+ for prev := gc.Uniqp(move); prev != r; prev = gc.Uniqp(prev) {
+ if copyu(prev.Prog, &move.Prog.To, nil) != 0 {
+ move = nil
+ break
+ }
+ }
+ if move == nil {
+ break
+ }
+ p.Reg, p.To.Reg = p.To.Reg, move.Prog.To.Reg
+ excise(move)
+ n++
+
+ // clean up
+ if p.From.Reg == p.To.Reg && isCommutative(p.As) {
+ p.From.Reg, p.Reg = p.Reg, 0
+ }
+ if p.To.Reg == p.Reg {
+ p.Reg = 0
+ }
+ // we could try again if p has become a 2-operand op
+ // but in testing nothing extra was extracted
+ }
+ }
+ break
+ }
+ }
+ return n
+}
+
+// isCommutative returns true if the order of input operands
+// does not affect the result. For example:
+// x + y == y + x so ADD is commutative
+// x ^ y == y ^ x so XOR is commutative
+func isCommutative(as obj.As) bool {
+ switch as {
+ case s390x.AADD,
+ s390x.AOR,
+ s390x.AAND,
+ s390x.AXOR,
+ s390x.AMULLW,
+ s390x.AMULLD:
+ return true
+ }
+ return false
+}
+
+// applyCast applies the cast implied by the given move
+// instruction to v and returns the result.
+func applyCast(cast obj.As, v int64) int64 {
+ switch cast {
+ case s390x.AMOVWZ:
+ return int64(uint32(v))
+ case s390x.AMOVHZ:
+ return int64(uint16(v))
+ case s390x.AMOVBZ:
+ return int64(uint8(v))
+ case s390x.AMOVW:
+ return int64(int32(v))
+ case s390x.AMOVH:
+ return int64(int16(v))
+ case s390x.AMOVB:
+ return int64(int8(v))
+ }
+ return v
+}
+
+// constantPropagation removes redundant constant copies.
+func constantPropagation(r *gc.Flow) int {
+ n := 0
+ // find MOV $con,R followed by
+ // another MOV $con,R without
+ // setting R in the interim
+ for ; r != nil; r = r.Link {
+ p := r.Prog
+ if isMove(p) {
+ if !isReg(&p.To) {
+ continue
+ }
+ if !isConst(&p.From) {
+ continue
+ }
+ } else {
+ continue
+ }
+
+ rr := r
+ for {
+ rr = gc.Uniqs(rr)
+ if rr == nil || rr == r {
+ break
+ }
+ if gc.Uniqp(rr) == nil {
+ break
+ }
+
+ pp := rr.Prog
+ t := copyu(pp, &p.To, nil)
+ switch t {
+ case _None:
+ continue
+ case _Read:
+ if !isGPR(&pp.From) || !isMove(pp) {
+ continue
+ }
+ if p.From.Type == obj.TYPE_CONST {
+ v := applyCast(p.As, p.From.Offset)
+ if isGPR(&pp.To) {
+ if int64(int32(v)) == v || ((v>>32)<<32) == v {
+ pp.From.Reg = 0
+ pp.From.Offset = v
+ pp.From.Type = obj.TYPE_CONST
+ n++
+ }
+ } else if int64(int16(v)) == v {
+ pp.From.Reg = 0
+ pp.From.Offset = v
+ pp.From.Type = obj.TYPE_CONST
+ n++
+ }
+ }
+ continue
+ case _Write:
+ if p.As != pp.As || p.From.Type != pp.From.Type {
+ break
+ }
+ if p.From.Type == obj.TYPE_CONST && p.From.Offset == pp.From.Offset {
+ excise(rr)
+ n++
+ continue
+ } else if p.From.Type == obj.TYPE_FCONST {
+ if p.From.Val.(float64) == pp.From.Val.(float64) {
+ excise(rr)
+ n++
+ continue
+ }
+ }
+ }
+ break
+ }
+ }
+ return n
+}
+
+// copyPropagation tries to eliminate register-to-register moves.
+func copyPropagation(r *gc.Flow) int {
+ n := 0
+ for ; r != nil; r = r.Link {
+ p := r.Prog
+ if isMove(p) && isReg(&p.To) {
+ // Convert uses to $0 to uses of R0 and
+ // propagate R0
+ if isGPR(&p.To) && isZero(&p.From) {
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = s390x.REGZERO
+ }
+
+ // Try to eliminate reg->reg moves
+ if isGPR(&p.From) || isFPR(&p.From) {
+ if copyprop(r) || (subprop(r) && copyprop(r)) {
+ excise(r)
+ n++
+ }
+ }
+ }
+ }
+ return n
+}
+
+// loadPipelining pushes any load from memory as early as possible.
+func loadPipelining(r *gc.Flow) int {
+ for ; r != nil; r = r.Link {
+ p := r.Prog
+ if isLoad(p) {
+ pushback(r)
+ }
+ }
+ return 0
+}
+
+// fuseCompareBranch finds comparisons followed by a branch and converts
+// them into a compare-and-branch instruction (which avoid setting the
+// condition code).
+func fuseCompareBranch(r *gc.Flow) int {
+ n := 0
+ for ; r != nil; r = r.Link {
+ p := r.Prog
+ r1 := gc.Uniqs(r)
+ if r1 == nil {
+ continue
+ }
+ p1 := r1.Prog
+
+ var ins obj.As
+ switch p.As {
+ case s390x.ACMP:
+ switch p1.As {
+ case s390x.ABCL, s390x.ABC:
+ continue
+ case s390x.ABEQ:
+ ins = s390x.ACMPBEQ
+ case s390x.ABGE:
+ ins = s390x.ACMPBGE
+ case s390x.ABGT:
+ ins = s390x.ACMPBGT
+ case s390x.ABLE:
+ ins = s390x.ACMPBLE
+ case s390x.ABLT:
+ ins = s390x.ACMPBLT
+ case s390x.ABNE:
+ ins = s390x.ACMPBNE
+ default:
+ continue
+ }
+
+ case s390x.ACMPU:
+ switch p1.As {
+ case s390x.ABCL, s390x.ABC:
+ continue
+ case s390x.ABEQ:
+ ins = s390x.ACMPUBEQ
+ case s390x.ABGE:
+ ins = s390x.ACMPUBGE
+ case s390x.ABGT:
+ ins = s390x.ACMPUBGT
+ case s390x.ABLE:
+ ins = s390x.ACMPUBLE
+ case s390x.ABLT:
+ ins = s390x.ACMPUBLT
+ case s390x.ABNE:
+ ins = s390x.ACMPUBNE
+ default:
+ continue
+ }
+
+ case s390x.ACMPW, s390x.ACMPWU:
+ continue
+
+ default:
+ continue
+ }
+
+ if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+ fmt.Printf("cnb %v; %v ", p, p1)
+ }
+
+ if p1.To.Sym != nil {
+ continue
+ }
+
+ if p.To.Type == obj.TYPE_REG {
+ p1.As = ins
+ p1.From = p.From
+ p1.Reg = p.To.Reg
+ p1.From3 = nil
+ } else if p.To.Type == obj.TYPE_CONST {
+ switch p.As {
+ case s390x.ACMP, s390x.ACMPW:
+ if (p.To.Offset < -(1 << 7)) || (p.To.Offset >= ((1 << 7) - 1)) {
+ continue
+ }
+ case s390x.ACMPU, s390x.ACMPWU:
+ if p.To.Offset >= (1 << 8) {
+ continue
+ }
+ default:
+ }
+ p1.As = ins
+ p1.From = p.From
+ p1.Reg = 0
+ p1.From3 = new(obj.Addr)
+ *(p1.From3) = p.To
+ } else {
+ continue
+ }
+
+ if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+ fmt.Printf("%v\n", p1)
+ }
+ excise(r)
+ n++
+ }
+ return n
+}
+
+// deadCodeElimination removes writes to registers which are written
+// to again before they are next read.
+func deadCodeElimination(r *gc.Flow) int {
+ n := 0
+ for ; r != nil; r = r.Link {
+ p := r.Prog
+ // Currently there are no instructions which write to multiple
+ // registers in copyu. This check will need to change if there
+ // ever are.
+ if !(isGPR(&p.To) || isFPR(&p.To)) || copyu(p, &p.To, nil) != _Write {
+ continue
+ }
+ for rr := gc.Uniqs(r); rr != nil; rr = gc.Uniqs(rr) {
+ t := copyu(rr.Prog, &p.To, nil)
+ if t == _None {
+ continue
+ }
+ if t == _Write {
+ excise(r)
+ n++
+ }
+ break
+ }
+ }
+ return n
+}
diff --git a/src/cmd/compile/internal/s390x/prog.go b/src/cmd/compile/internal/s390x/prog.go
new file mode 100644
index 0000000000..306adf85c3
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/prog.go
@@ -0,0 +1,179 @@
+// Copyright 2016 The Go 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 s390x
+
+import (
+ "cmd/compile/internal/gc"
+ "cmd/internal/obj"
+ "cmd/internal/obj/s390x"
+)
+
+// This table gives the basic information about instruction
+// generated by the compiler and processed in the optimizer.
+// See opt.h for bit definitions.
+//
+// Instructions not generated need not be listed.
+// As an exception to that rule, we typically write down all the
+// size variants of an operation even if we just use a subset.
+var progtable = [s390x.ALAST & obj.AMask]obj.ProgInfo{
+ obj.ATYPE & obj.AMask: {Flags: gc.Pseudo | gc.Skip},
+ obj.ATEXT & obj.AMask: {Flags: gc.Pseudo},
+ obj.AFUNCDATA & obj.AMask: {Flags: gc.Pseudo},
+ obj.APCDATA & obj.AMask: {Flags: gc.Pseudo},
+ obj.AUNDEF & obj.AMask: {Flags: gc.Break},
+ obj.AUSEFIELD & obj.AMask: {Flags: gc.OK},
+ obj.ACHECKNIL & obj.AMask: {Flags: gc.LeftRead},
+ obj.AVARDEF & obj.AMask: {Flags: gc.Pseudo | gc.RightWrite},
+ obj.AVARKILL & obj.AMask: {Flags: gc.Pseudo | gc.RightWrite},
+ obj.AVARLIVE & obj.AMask: {Flags: gc.Pseudo | gc.LeftRead},
+
+ // NOP is an internal no-op that also stands
+ // for USED and SET annotations.
+ obj.ANOP & obj.AMask: {Flags: gc.LeftRead | gc.RightWrite},
+
+ // Integer
+ s390x.AADD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.ASUB & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.ANEG & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AAND & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AOR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AXOR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AMULLD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AMULLW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AMULHD & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AMULHDU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.ADIVD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.ADIVDU & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.ASLD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.ASRD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.ASRAD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.ARLL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.ARLLG & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.ACMP & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead},
+ s390x.ACMPU & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead},
+
+ // Floating point.
+ s390x.AFADD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AFADDS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AFSUB & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AFSUBS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AFMUL & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AFMULS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AFDIV & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AFDIVS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+ s390x.AFCMPU & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
+ s390x.ACEBR & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightRead},
+ s390x.ALEDBR & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ALDEBR & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.AFSQRT & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
+
+ // Conversions
+ s390x.ACEFBRA & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACDFBRA & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACEGBRA & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACDGBRA & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACFEBRA & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACFDBRA & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACGEBRA & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACGDBRA & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACELFBR & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACDLFBR & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACELGBR & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACDLGBR & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACLFEBR & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACLFDBR & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACLGEBR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+ s390x.ACLGDBR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+
+ // Moves
+ s390x.AMOVB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+ s390x.AMOVBZ & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+ s390x.AMOVH & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+ s390x.AMOVHZ & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+ s390x.AMOVW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+ s390x.AMOVWZ & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+ s390x.AMOVD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
+ s390x.AFMOVS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+ s390x.AFMOVD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
+
+ // Storage operations
+ s390x.AMVC & obj.AMask: {Flags: gc.LeftRead | gc.LeftAddr | gc.RightWrite | gc.RightAddr},
+ s390x.ACLC & obj.AMask: {Flags: gc.LeftRead | gc.LeftAddr | gc.RightRead | gc.RightAddr},
+ s390x.AXC & obj.AMask: {Flags: gc.LeftRead | gc.LeftAddr | gc.RightWrite | gc.RightAddr},
+ s390x.AOC & obj.AMask: {Flags: gc.LeftRead | gc.LeftAddr | gc.RightWrite | gc.RightAddr},
+ s390x.ANC & obj.AMask: {Flags: gc.LeftRead | gc.LeftAddr | gc.RightWrite | gc.RightAddr},
+
+ // Jumps
+ s390x.ABR & obj.AMask: {Flags: gc.Jump | gc.Break},
+ s390x.ABL & obj.AMask: {Flags: gc.Call},
+ s390x.ABEQ & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ABNE & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ABGE & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ABLT & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ABGT & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ABLE & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ACMPBEQ & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ACMPBNE & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ACMPBGE & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ACMPBLT & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ACMPBGT & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ACMPBLE & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ACMPUBEQ & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ACMPUBNE & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ACMPUBGE & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ACMPUBLT & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ACMPUBGT & obj.AMask: {Flags: gc.Cjmp},
+ s390x.ACMPUBLE & obj.AMask: {Flags: gc.Cjmp},
+
+ // Macros
+ s390x.ACLEAR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightAddr | gc.RightWrite},
+
+ // Load/store multiple
+ s390x.ASTMG & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightAddr | gc.RightWrite},
+ s390x.ASTMY & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightAddr | gc.RightWrite},
+ s390x.ALMG & obj.AMask: {Flags: gc.SizeQ | gc.LeftAddr | gc.LeftRead | gc.RightWrite},
+ s390x.ALMY & obj.AMask: {Flags: gc.SizeL | gc.LeftAddr | gc.LeftRead | gc.RightWrite},
+
+ obj.ARET & obj.AMask: {Flags: gc.Break},
+}
+
+func proginfo(p *obj.Prog) {
+ info := &p.Info
+ *info = progtable[p.As&obj.AMask]
+ if info.Flags == 0 {
+ gc.Fatalf("proginfo: unknown instruction %v", p)
+ }
+
+ if (info.Flags&gc.RegRead != 0) && p.Reg == 0 {
+ info.Flags &^= gc.RegRead
+ info.Flags |= gc.RightRead /*CanRegRead |*/
+ }
+
+ if (p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_ADDR) && p.From.Reg != 0 {
+ info.Regindex |= RtoB(int(p.From.Reg))
+ }
+
+ if (p.To.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_ADDR) && p.To.Reg != 0 {
+ info.Regindex |= RtoB(int(p.To.Reg))
+ }
+
+ if p.From.Type == obj.TYPE_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) {
+ info.Flags &^= gc.LeftRead
+ info.Flags |= gc.LeftAddr
+ }
+
+ switch p.As {
+ // load multiple sets a range of registers
+ case s390x.ALMG, s390x.ALMY:
+ for r := p.Reg; r <= p.To.Reg; r++ {
+ info.Regset |= RtoB(int(r))
+ }
+ // store multiple reads a range of registers
+ case s390x.ASTMG, s390x.ASTMY:
+ for r := p.From.Reg; r <= p.Reg; r++ {
+ info.Reguse |= RtoB(int(r))
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/s390x/reg.go b/src/cmd/compile/internal/s390x/reg.go
new file mode 100644
index 0000000000..4cb8a9da05
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/reg.go
@@ -0,0 +1,130 @@
+// Derived from Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package s390x
+
+import "cmd/internal/obj/s390x"
+import "cmd/compile/internal/gc"
+
+const (
+ NREGVAR = 32 /* 16 general + 16 floating */
+)
+
+var regname = []string{
+ ".R0",
+ ".R1",
+ ".R2",
+ ".R3",
+ ".R4",
+ ".R5",
+ ".R6",
+ ".R7",
+ ".R8",
+ ".R9",
+ ".R10",
+ ".R11",
+ ".R12",
+ ".R13",
+ ".R14",
+ ".R15",
+ ".F0",
+ ".F1",
+ ".F2",
+ ".F3",
+ ".F4",
+ ".F5",
+ ".F6",
+ ".F7",
+ ".F8",
+ ".F9",
+ ".F10",
+ ".F11",
+ ".F12",
+ ".F13",
+ ".F14",
+ ".F15",
+}
+
+func regnames(n *int) []string {
+ *n = NREGVAR
+ return regname
+}
+
+func excludedregs() uint64 {
+ // Exclude registers with fixed functions
+ return RtoB(s390x.REG_R0) |
+ RtoB(s390x.REGSP) |
+ RtoB(s390x.REGG) |
+ RtoB(s390x.REGTMP) |
+ RtoB(s390x.REGTMP2) |
+ RtoB(s390x.REG_LR)
+}
+
+func doregbits(r int) uint64 {
+ return 0
+}
+
+/*
+ * track register variables including external registers:
+ * bit reg
+ * 0 R0
+ * ... ...
+ * 15 R15
+ * 16+0 F0
+ * 16+1 F1
+ * ... ...
+ * 16+15 F15
+ */
+func RtoB(r int) uint64 {
+ if r >= s390x.REG_R0 && r <= s390x.REG_R15 {
+ return 1 << uint(r-s390x.REG_R0)
+ }
+ if r >= s390x.REG_F0 && r <= s390x.REG_F15 {
+ return 1 << uint(16+r-s390x.REG_F0)
+ }
+ return 0
+}
+
+func BtoR(b uint64) int {
+ b &= 0xffff
+ if b == 0 {
+ return 0
+ }
+ return gc.Bitno(b) + s390x.REG_R0
+}
+
+func BtoF(b uint64) int {
+ b >>= 16
+ b &= 0xffff
+ if b == 0 {
+ return 0
+ }
+ return gc.Bitno(b) + s390x.REG_F0
+}
diff --git a/src/cmd/compile/internal/ssa/TODO b/src/cmd/compile/internal/ssa/TODO
index e081856bd3..dad4880994 100644
--- a/src/cmd/compile/internal/ssa/TODO
+++ b/src/cmd/compile/internal/ssa/TODO
@@ -41,8 +41,6 @@ Future/other
------------
- Start another architecture (arm?)
- 64-bit ops on 32-bit machines
-- Investigate type equality. During SSA generation, should we use n.Type or (say) TypeBool?
- Should we get rid of named types in favor of underlying types during SSA generation?
-- Should we introduce a new type equality routine that is less strict than the frontend's?
- Infrastructure for enabling/disabling/configuring passes
- Modify logging for at least pass=1, to be Warnl compatible
diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go
index 5a17735304..4a10606d3c 100644
--- a/src/cmd/compile/internal/ssa/check.go
+++ b/src/cmd/compile/internal/ssa/check.go
@@ -162,7 +162,7 @@ func checkFunc(f *Func) {
// variable length args)
nArgs := opcodeTable[v.Op].argLen
if nArgs != -1 && int32(len(v.Args)) != nArgs {
- f.Fatalf("value %v has %d args, expected %d", v.LongString(),
+ f.Fatalf("value %s has %d args, expected %d", v.LongString(),
len(v.Args), nArgs)
}
@@ -193,6 +193,8 @@ func checkFunc(f *Func) {
canHaveAuxInt = true
case auxInt64, auxFloat64:
canHaveAuxInt = true
+ case auxInt128:
+ // AuxInt must be zero, so leave canHaveAuxInt set to false.
case auxFloat32:
canHaveAuxInt = true
if !isExactFloat32(v) {
@@ -203,19 +205,25 @@ func checkFunc(f *Func) {
case auxSymOff, auxSymValAndOff:
canHaveAuxInt = true
canHaveAux = true
+ case auxSymInt32:
+ if v.AuxInt != int64(int32(v.AuxInt)) {
+ f.Fatalf("bad int32 AuxInt value for %v", v)
+ }
+ canHaveAuxInt = true
+ canHaveAux = true
default:
f.Fatalf("unknown aux type for %s", v.Op)
}
if !canHaveAux && v.Aux != nil {
- f.Fatalf("value %v has an Aux value %v but shouldn't", v.LongString(), v.Aux)
+ f.Fatalf("value %s has an Aux value %v but shouldn't", v.LongString(), v.Aux)
}
if !canHaveAuxInt && v.AuxInt != 0 {
- f.Fatalf("value %v has an AuxInt value %d but shouldn't", v.LongString(), v.AuxInt)
+ f.Fatalf("value %s has an AuxInt value %d but shouldn't", v.LongString(), v.AuxInt)
}
for _, arg := range v.Args {
if arg == nil {
- f.Fatalf("value %v has nil arg", v.LongString())
+ f.Fatalf("value %s has nil arg", v.LongString())
}
}
@@ -271,7 +279,7 @@ func checkFunc(f *Func) {
for _, v := range b.Values {
for i, a := range v.Args {
if !valueMark[a.ID] {
- f.Fatalf("%v, arg %d of %v, is missing", a, i, v)
+ f.Fatalf("%v, arg %d of %s, is missing", a, i, v.LongString())
}
}
}
@@ -338,7 +346,7 @@ func checkFunc(f *Func) {
// domCheck reports whether x dominates y (including x==y).
func domCheck(f *Func, sdom sparseTree, x, y *Block) bool {
- if !sdom.isAncestorEq(y, f.Entry) {
+ if !sdom.isAncestorEq(f.Entry, y) {
// unreachable - ignore
return true
}
diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go
index d52ae9c6da..bc9c830ee9 100644
--- a/src/cmd/compile/internal/ssa/compile.go
+++ b/src/cmd/compile/internal/ssa/compile.go
@@ -230,9 +230,10 @@ var passes = [...]pass{
{name: "early deadcode", fn: deadcode}, // remove generated dead code to avoid doing pointless work during opt
{name: "short circuit", fn: shortcircuit},
{name: "decompose user", fn: decomposeUser, required: true},
- {name: "opt", fn: opt, required: true}, // TODO: split required rules and optimizing rules
- {name: "zero arg cse", fn: zcse, required: true}, // required to merge OpSB values
- {name: "opt deadcode", fn: deadcode}, // remove any blocks orphaned during opt
+ {name: "opt", fn: opt, required: true}, // TODO: split required rules and optimizing rules
+ {name: "zero arg cse", fn: zcse, required: true}, // required to merge OpSB values
+ {name: "opt deadcode", fn: deadcode, required: true}, // remove any blocks orphaned during opt
+ {name: "generic domtree", fn: domTree},
{name: "generic cse", fn: cse},
{name: "phiopt", fn: phiopt},
{name: "nilcheckelim", fn: nilcheckelim},
@@ -288,6 +289,12 @@ var passOrder = [...]constraint{
{"opt", "nilcheckelim"},
// tighten should happen before lowering to avoid splitting naturally paired instructions such as CMP/SET
{"tighten", "lower"},
+ // cse, phiopt, nilcheckelim, prove and loopbce share idom.
+ {"generic domtree", "generic cse"},
+ {"generic domtree", "phiopt"},
+ {"generic domtree", "nilcheckelim"},
+ {"generic domtree", "prove"},
+ {"generic domtree", "loopbce"},
// tighten will be most effective when as many values have been removed as possible
{"generic deadcode", "tighten"},
{"generic cse", "tighten"},
diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
index 33357124fc..a60291ea53 100644
--- a/src/cmd/compile/internal/ssa/config.go
+++ b/src/cmd/compile/internal/ssa/config.go
@@ -103,6 +103,7 @@ type Frontend interface {
SplitInterface(LocalSlot) (LocalSlot, LocalSlot)
SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot)
SplitComplex(LocalSlot) (LocalSlot, LocalSlot)
+ SplitStruct(LocalSlot, int) LocalSlot
// Line returns a string describing the given line number.
Line(int32) string
@@ -115,6 +116,12 @@ type GCNode interface {
String() string
}
+// GCSym is an interface that *gc.Sym implements.
+// Using *gc.Sym directly would lead to import cycles.
+type GCSym interface {
+ IsRuntimeCall(name string) bool
+}
+
// NewConfig returns a new configuration object for the given architecture.
func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config {
c := &Config{arch: arch, fe: fe}
diff --git a/src/cmd/compile/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go
index 1ec5712be0..d501f75e02 100644
--- a/src/cmd/compile/internal/ssa/cse.go
+++ b/src/cmd/compile/internal/ssa/cse.go
@@ -108,7 +108,7 @@ func cse(f *Func) {
break
}
}
- if !equivalent || !v.Type.Equal(w.Type) {
+ if !equivalent || v.Type.Compare(w.Type) != CMPeq {
// w is not equivalent to v.
// move it to the end and shrink e.
e[j], e[len(e)-1] = e[len(e)-1], e[j]
@@ -131,33 +131,36 @@ func cse(f *Func) {
}
}
- // Compute dominator tree
- idom := dominators(f)
- sdom := newSparseTree(f, idom)
+ // Dominator tree (f.sdom) is computed by the generic domtree pass.
// Compute substitutions we would like to do. We substitute v for w
// if v and w are in the same equivalence class and v dominates w.
rewrite := make([]*Value, f.NumValues())
for _, e := range partition {
- for len(e) > 1 {
- // Find a maximal dominant element in e
- v := e[0]
- for _, w := range e[1:] {
- if sdom.isAncestorEq(w.Block, v.Block) {
- v = w
- }
+ sort.Sort(sortbyentry{e, f.sdom})
+ for i := 0; i < len(e)-1; i++ {
+ // e is sorted by entry value so maximal dominant element should be
+ // found first in the slice
+ v := e[i]
+ if v == nil {
+ continue
}
+ e[i] = nil
// Replace all elements of e which v dominates
- for i := 0; i < len(e); {
- w := e[i]
- if w == v {
- e, e[i] = e[:len(e)-1], e[len(e)-1]
- } else if sdom.isAncestorEq(v.Block, w.Block) {
+ for j := i + 1; j < len(e); j++ {
+ w := e[j]
+ if w == nil {
+ continue
+ }
+ if f.sdom.isAncestorEq(v.Block, w.Block) {
rewrite[w.ID] = v
- e, e[i] = e[:len(e)-1], e[len(e)-1]
+ e[j] = nil
} else {
- i++
+ // since the blocks are assorted in ascending order by entry number
+ // once we know that we don't dominate a block we can't dominate any
+ // 'later' block
+ break
}
}
}
@@ -255,6 +258,14 @@ func cmpVal(v, w *Value, auxIDs auxmap, depth int) Cmp {
return lt2Cmp(v.Block.ID < w.Block.ID)
}
+ switch v.Op {
+ case OpStaticCall, OpAMD64CALLstatic, OpARMCALLstatic:
+ sym := v.Aux.(GCSym)
+ if sym.IsRuntimeCall("newobject") {
+ return lt2Cmp(v.ID < w.ID)
+ }
+ }
+
if tc := v.Type.Compare(w.Type); tc != CMPeq {
return tc
}
@@ -302,3 +313,16 @@ func (sv sortvalues) Less(i, j int) bool {
// Sort by value ID last to keep the sort result deterministic.
return v.ID < w.ID
}
+
+type sortbyentry struct {
+ a []*Value // array of values
+ sdom sparseTree
+}
+
+func (sv sortbyentry) Len() int { return len(sv.a) }
+func (sv sortbyentry) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
+func (sv sortbyentry) Less(i, j int) bool {
+ v := sv.a[i]
+ w := sv.a[j]
+ return sv.sdom.maxdomorder(v.Block) < sv.sdom.maxdomorder(w.Block)
+}
diff --git a/src/cmd/compile/internal/ssa/cse_test.go b/src/cmd/compile/internal/ssa/cse_test.go
index 905939fc32..d5be2b52ec 100644
--- a/src/cmd/compile/internal/ssa/cse_test.go
+++ b/src/cmd/compile/internal/ssa/cse_test.go
@@ -44,6 +44,7 @@ func TestCSEAuxPartitionBug(t *testing.T) {
Exit("rstore")))
CheckFunc(fun.f)
+ domTree(fun.f)
cse(fun.f)
deadcode(fun.f)
CheckFunc(fun.f)
diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go
index eab9974106..53116ba593 100644
--- a/src/cmd/compile/internal/ssa/decompose.go
+++ b/src/cmd/compile/internal/ssa/decompose.go
@@ -21,6 +21,7 @@ func decomposeBuiltIn(f *Func) {
// NOTE: the component values we are making are dead at this point.
// We must do the opt pass before any deadcode elimination or we will
// lose the name->value correspondence.
+ var newNames []LocalSlot
for _, name := range f.Names {
t := name.Type
switch {
@@ -32,29 +33,31 @@ func decomposeBuiltIn(f *Func) {
elemType = f.Config.fe.TypeFloat32()
}
rName, iName := f.Config.fe.SplitComplex(name)
- f.Names = append(f.Names, rName, iName)
+ newNames = append(newNames, rName, iName)
for _, v := range f.NamedValues[name] {
r := v.Block.NewValue1(v.Line, OpComplexReal, elemType, v)
i := v.Block.NewValue1(v.Line, OpComplexImag, elemType, v)
f.NamedValues[rName] = append(f.NamedValues[rName], r)
f.NamedValues[iName] = append(f.NamedValues[iName], i)
}
+ delete(f.NamedValues, name)
case t.IsString():
ptrType := f.Config.fe.TypeBytePtr()
lenType := f.Config.fe.TypeInt()
ptrName, lenName := f.Config.fe.SplitString(name)
- f.Names = append(f.Names, ptrName, lenName)
+ newNames = append(newNames, ptrName, lenName)
for _, v := range f.NamedValues[name] {
ptr := v.Block.NewValue1(v.Line, OpStringPtr, ptrType, v)
len := v.Block.NewValue1(v.Line, OpStringLen, lenType, v)
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
}
+ delete(f.NamedValues, name)
case t.IsSlice():
ptrType := f.Config.fe.TypeBytePtr()
lenType := f.Config.fe.TypeInt()
ptrName, lenName, capName := f.Config.fe.SplitSlice(name)
- f.Names = append(f.Names, ptrName, lenName, capName)
+ newNames = append(newNames, ptrName, lenName, capName)
for _, v := range f.NamedValues[name] {
ptr := v.Block.NewValue1(v.Line, OpSlicePtr, ptrType, v)
len := v.Block.NewValue1(v.Line, OpSliceLen, lenType, v)
@@ -63,20 +66,25 @@ func decomposeBuiltIn(f *Func) {
f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
f.NamedValues[capName] = append(f.NamedValues[capName], cap)
}
+ delete(f.NamedValues, name)
case t.IsInterface():
ptrType := f.Config.fe.TypeBytePtr()
typeName, dataName := f.Config.fe.SplitInterface(name)
- f.Names = append(f.Names, typeName, dataName)
+ newNames = append(newNames, typeName, dataName)
for _, v := range f.NamedValues[name] {
typ := v.Block.NewValue1(v.Line, OpITab, ptrType, v)
data := v.Block.NewValue1(v.Line, OpIData, ptrType, v)
f.NamedValues[typeName] = append(f.NamedValues[typeName], typ)
f.NamedValues[dataName] = append(f.NamedValues[dataName], data)
}
+ delete(f.NamedValues, name)
case t.Size() > f.Config.IntSize:
- f.Unimplementedf("undecomposed named type %s", t)
+ f.Unimplementedf("undecomposed named type %s %s", name, t)
+ default:
+ newNames = append(newNames, name)
}
}
+ f.Names = newNames
}
func decomposeBuiltInPhi(v *Value) {
@@ -181,25 +189,32 @@ func decomposeUser(f *Func) {
// We must do the opt pass before any deadcode elimination or we will
// lose the name->value correspondence.
i := 0
+ var fnames []LocalSlot
+ var newNames []LocalSlot
for _, name := range f.Names {
t := name.Type
switch {
case t.IsStruct():
n := t.NumFields()
+ fnames = fnames[:0]
+ for i := 0; i < n; i++ {
+ fnames = append(fnames, f.Config.fe.SplitStruct(name, i))
+ }
for _, v := range f.NamedValues[name] {
for i := 0; i < n; i++ {
- fname := LocalSlot{name.N, t.FieldType(i), name.Off + t.FieldOff(i)} // TODO: use actual field name?
x := v.Block.NewValue1I(v.Line, OpStructSelect, t.FieldType(i), int64(i), v)
- f.NamedValues[fname] = append(f.NamedValues[fname], x)
+ f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], x)
}
}
delete(f.NamedValues, name)
+ newNames = append(newNames, fnames...)
default:
f.Names[i] = name
i++
}
}
f.Names = f.Names[:i]
+ f.Names = append(f.Names, newNames...)
}
func decomposeUserPhi(v *Value) {
diff --git a/src/cmd/compile/internal/ssa/dom.go b/src/cmd/compile/internal/ssa/dom.go
index 0fffcdc2af..c0a4bb4188 100644
--- a/src/cmd/compile/internal/ssa/dom.go
+++ b/src/cmd/compile/internal/ssa/dom.go
@@ -5,11 +5,13 @@
package ssa
// mark values
+type markKind uint8
+
const (
- notFound = 0 // block has not been discovered yet
- notExplored = 1 // discovered and in queue, outedges not processed yet
- explored = 2 // discovered and in queue, outedges processed
- done = 3 // all done, in output ordering
+ notFound markKind = 0 // block has not been discovered yet
+ notExplored markKind = 1 // discovered and in queue, outedges not processed yet
+ explored markKind = 2 // discovered and in queue, outedges processed
+ done markKind = 3 // all done, in output ordering
)
// This file contains code to compute the dominator tree
@@ -18,7 +20,10 @@ const (
// postorder computes a postorder traversal ordering for the
// basic blocks in f. Unreachable blocks will not appear.
func postorder(f *Func) []*Block {
- mark := make([]byte, f.NumBlocks())
+ return postorderWithNumbering(f, []int{})
+}
+func postorderWithNumbering(f *Func, ponums []int) []*Block {
+ mark := make([]markKind, f.NumBlocks())
// result ordering
var order []*Block
@@ -34,6 +39,9 @@ func postorder(f *Func) []*Block {
// Children have all been visited. Pop & output block.
s = s[:len(s)-1]
mark[b.ID] = done
+ if len(ponums) > 0 {
+ ponums[b.ID] = len(order)
+ }
order = append(order, b)
case notExplored:
// Children have not been visited yet. Mark as explored
@@ -54,14 +62,14 @@ func postorder(f *Func) []*Block {
type linkedBlocks func(*Block) []*Block
-const nscratchslices = 8
+const nscratchslices = 7
// experimentally, functions with 512 or fewer blocks account
// for 75% of memory (size) allocation for dominator computation
// in make.bash.
const minscratchblocks = 512
-func (cfg *Config) scratchBlocksForDom(maxBlockID int) (a, b, c, d, e, f, g, h []ID) {
+func (cfg *Config) scratchBlocksForDom(maxBlockID int) (a, b, c, d, e, f, g []ID) {
tot := maxBlockID * nscratchslices
scratch := cfg.domblockstore
if len(scratch) < tot {
@@ -88,213 +96,143 @@ func (cfg *Config) scratchBlocksForDom(maxBlockID int) (a, b, c, d, e, f, g, h [
e = scratch[4*maxBlockID : 5*maxBlockID]
f = scratch[5*maxBlockID : 6*maxBlockID]
g = scratch[6*maxBlockID : 7*maxBlockID]
- h = scratch[7*maxBlockID : 8*maxBlockID]
return
}
-// dfs performs a depth first search over the blocks starting at the set of
-// blocks in the entries list (in arbitrary order). dfnum contains a mapping
-// from block id to an int indicating the order the block was reached or
-// notFound if the block was not reached. order contains a mapping from dfnum
-// to block.
-func (f *Func) dfs(entries []*Block, succFn linkedBlocks, dfnum, order, parent []ID) (fromID []*Block) {
- maxBlockID := entries[0].Func.NumBlocks()
-
- fromID = make([]*Block, maxBlockID)
-
- for _, entry := range entries[0].Func.Blocks {
- eid := entry.ID
- if fromID[eid] != nil {
- panic("Colliding entry IDs")
- }
- fromID[eid] = entry
- }
-
- n := ID(0)
- s := make([]*Block, 0, 256)
- for _, entry := range entries {
- if dfnum[entry.ID] != notFound {
- continue // already found from a previous entry
- }
- s = append(s, entry)
- parent[entry.ID] = entry.ID
- for len(s) > 0 {
- node := s[len(s)-1]
- s = s[:len(s)-1]
-
- n++
- for _, w := range succFn(node) {
- // if it has a dfnum, we've already visited it
- if dfnum[w.ID] == notFound {
- s = append(s, w)
- parent[w.ID] = node.ID
- dfnum[w.ID] = notExplored
- }
- }
- dfnum[node.ID] = n
- order[n] = node.ID
- }
- }
-
- return
-}
-
-// dominators computes the dominator tree for f. It returns a slice
-// which maps block ID to the immediate dominator of that block.
-// Unreachable blocks map to nil. The entry block maps to nil.
func dominators(f *Func) []*Block {
preds := func(b *Block) []*Block { return b.Preds }
succs := func(b *Block) []*Block { return b.Succs }
//TODO: benchmark and try to find criteria for swapping between
// dominatorsSimple and dominatorsLT
- return f.dominatorsLT([]*Block{f.Entry}, preds, succs)
+ return f.dominatorsLTOrig(f.Entry, preds, succs)
}
-// postDominators computes the post-dominator tree for f.
-func postDominators(f *Func) []*Block {
- preds := func(b *Block) []*Block { return b.Preds }
- succs := func(b *Block) []*Block { return b.Succs }
-
- if len(f.Blocks) == 0 {
- return nil
- }
-
- // find the exit blocks
- var exits []*Block
- for _, b := range f.Blocks {
- switch b.Kind {
- case BlockExit, BlockRet, BlockRetJmp, BlockCall, BlockCheck:
- exits = append(exits, b)
- }
- }
-
- // infinite loop with no exit
- if exits == nil {
- return make([]*Block, f.NumBlocks())
- }
- return f.dominatorsLT(exits, succs, preds)
-}
-
-// dominatorsLt runs Lengauer-Tarjan to compute a dominator tree starting at
+// dominatorsLTOrig runs Lengauer-Tarjan to compute a dominator tree starting at
// entry and using predFn/succFn to find predecessors/successors to allow
// computing both dominator and post-dominator trees.
-func (f *Func) dominatorsLT(entries []*Block, predFn linkedBlocks, succFn linkedBlocks) []*Block {
- // Based on Lengauer-Tarjan from Modern Compiler Implementation in C -
- // Appel with optimizations from Finding Dominators in Practice -
- // Georgiadis
+func (f *Func) dominatorsLTOrig(entry *Block, predFn linkedBlocks, succFn linkedBlocks) []*Block {
+ // Adapted directly from the original TOPLAS article's "simple" algorithm
- maxBlockID := entries[0].Func.NumBlocks()
+ maxBlockID := entry.Func.NumBlocks()
+ semi, vertex, label, parent, ancestor, bucketHead, bucketLink := f.Config.scratchBlocksForDom(maxBlockID)
- dfnum, vertex, parent, semi, samedom, ancestor, best, bucket := f.Config.scratchBlocksForDom(maxBlockID)
-
- // dfnum := make([]ID, maxBlockID) // conceptually int32, but punning for allocation purposes.
- // vertex := make([]ID, maxBlockID)
- // parent := make([]ID, maxBlockID)
-
- // semi := make([]ID, maxBlockID)
- // samedom := make([]ID, maxBlockID)
- // ancestor := make([]ID, maxBlockID)
- // best := make([]ID, maxBlockID)
- // bucket := make([]ID, maxBlockID)
+ // This version uses integers for most of the computation,
+ // to make the work arrays smaller and pointer-free.
+ // fromID translates from ID to *Block where that is needed.
+ fromID := make([]*Block, maxBlockID)
+ for _, v := range f.Blocks {
+ fromID[v.ID] = v
+ }
+ idom := make([]*Block, maxBlockID)
// Step 1. Carry out a depth first search of the problem graph. Number
// the vertices from 1 to n as they are reached during the search.
- fromID := f.dfs(entries, succFn, dfnum, vertex, parent)
+ n := f.dfsOrig(entry, succFn, semi, vertex, label, parent)
- idom := make([]*Block, maxBlockID)
-
- // Step 2. Compute the semidominators of all vertices by applying
- // Theorem 4. Carry out the computation vertex by vertex in decreasing
- // order by number.
- for i := maxBlockID - 1; i > 0; i-- {
+ for i := n; i >= 2; i-- {
w := vertex[i]
- if w == 0 {
- continue
- }
-
- if dfnum[w] == notFound {
- // skip unreachable node
- continue
- }
-
- // Step 3. Implicitly define the immediate dominator of each
- // vertex by applying Corollary 1. (reordered)
- for v := bucket[w]; v != 0; v = bucket[v] {
- u := eval(v, ancestor, semi, dfnum, best)
- if semi[u] == semi[v] {
- idom[v] = fromID[w] // true dominator
- } else {
- samedom[v] = u // v has same dominator as u
- }
- }
-
- p := parent[w]
- s := p // semidominator
- var sp ID
- // calculate the semidominator of w
+ // step2 in TOPLAS paper
for _, v := range predFn(fromID[w]) {
- if dfnum[v.ID] == notFound {
+ if semi[v.ID] == 0 {
// skip unreachable predecessor
+ // not in original, but we're using existing pred instead of building one.
continue
}
-
- if dfnum[v.ID] <= dfnum[w] {
- sp = v.ID
- } else {
- sp = semi[eval(v.ID, ancestor, semi, dfnum, best)]
- }
-
- if dfnum[sp] < dfnum[s] {
- s = sp
+ u := evalOrig(v.ID, ancestor, semi, label)
+ if semi[u] < semi[w] {
+ semi[w] = semi[u]
}
}
- // link
- ancestor[w] = p
- best[w] = w
+ // add w to bucket[vertex[semi[w]]]
+ // implement bucket as a linked list implemented
+ // in a pair of arrays.
+ vsw := vertex[semi[w]]
+ bucketLink[w] = bucketHead[vsw]
+ bucketHead[vsw] = w
+
+ linkOrig(parent[w], w, ancestor)
- semi[w] = s
- if semi[s] != parent[s] {
- bucket[w] = bucket[s]
- bucket[s] = w
+ // step3 in TOPLAS paper
+ for v := bucketHead[parent[w]]; v != 0; v = bucketLink[v] {
+ u := evalOrig(v, ancestor, semi, label)
+ if semi[u] < semi[v] {
+ idom[v] = fromID[u]
+ } else {
+ idom[v] = fromID[parent[w]]
+ }
}
}
-
- // Final pass of step 3
- for v := bucket[0]; v != 0; v = bucket[v] {
- idom[v] = fromID[bucket[0]]
+ // step 4 in toplas paper
+ for i := ID(2); i <= n; i++ {
+ w := vertex[i]
+ if idom[w].ID != vertex[semi[w]] {
+ idom[w] = idom[idom[w].ID]
+ }
}
- // Step 4. Explicitly define the immediate dominator of each vertex,
- // carrying out the computation vertex by vertex in increasing order by
- // number.
- for i := 1; i < maxBlockID-1; i++ {
- w := vertex[i]
- if w == 0 {
- continue
+ return idom
+}
+
+// dfs performs a depth first search over the blocks starting at entry block
+// (in arbitrary order). This is a de-recursed version of dfs from the
+// original Tarjan-Lengauer TOPLAS article. It's important to return the
+// same values for parent as the original algorithm.
+func (f *Func) dfsOrig(entry *Block, succFn linkedBlocks, semi, vertex, label, parent []ID) ID {
+ n := ID(0)
+ s := make([]*Block, 0, 256)
+ s = append(s, entry)
+
+ for len(s) > 0 {
+ v := s[len(s)-1]
+ s = s[:len(s)-1]
+ // recursing on v
+
+ if semi[v.ID] != 0 {
+ continue // already visited
}
- // w has the same dominator as samedom[w]
- if samedom[w] != 0 {
- idom[w] = idom[samedom[w]]
+ n++
+ semi[v.ID] = n
+ vertex[n] = v.ID
+ label[v.ID] = v.ID
+ // ancestor[v] already zero
+ for _, w := range succFn(v) {
+ // if it has a dfnum, we've already visited it
+ if semi[w.ID] == 0 {
+ // yes, w can be pushed multiple times.
+ s = append(s, w)
+ parent[w.ID] = v.ID // keep overwriting this till it is visited.
+ }
}
}
- return idom
+ return n
}
-// eval function from LT paper with path compression
-func eval(v ID, ancestor []ID, semi []ID, dfnum []ID, best []ID) ID {
- a := ancestor[v]
- if ancestor[a] != 0 {
- bid := eval(a, ancestor, semi, dfnum, best)
- ancestor[v] = ancestor[a]
- if dfnum[semi[bid]] < dfnum[semi[best[v]]] {
- best[v] = bid
+// compressOrig is the "simple" compress function from LT paper
+func compressOrig(v ID, ancestor, semi, label []ID) {
+ if ancestor[ancestor[v]] != 0 {
+ compressOrig(ancestor[v], ancestor, semi, label)
+ if semi[label[ancestor[v]]] < semi[label[v]] {
+ label[v] = label[ancestor[v]]
}
+ ancestor[v] = ancestor[ancestor[v]]
+ }
+}
+
+// evalOrig is the "simple" eval function from LT paper
+func evalOrig(v ID, ancestor, semi, label []ID) ID {
+ if ancestor[v] == 0 {
+ return v
}
- return best[v]
+ compressOrig(v, ancestor, semi, label)
+ return label[v]
+}
+
+func linkOrig(v, w ID, ancestor []ID) {
+ ancestor[w] = v
}
// dominators computes the dominator tree for f. It returns a slice
@@ -364,3 +302,9 @@ func intersect(b, c *Block, postnum []int, idom []*Block) *Block {
}
return b
}
+
+// build immediate dominators.
+func domTree(f *Func) {
+ f.idom = dominators(f)
+ f.sdom = newSparseTree(f, f.idom)
+}
diff --git a/src/cmd/compile/internal/ssa/dom_test.go b/src/cmd/compile/internal/ssa/dom_test.go
index 9741edf331..6ecbe923d4 100644
--- a/src/cmd/compile/internal/ssa/dom_test.go
+++ b/src/cmd/compile/internal/ssa/dom_test.go
@@ -372,32 +372,6 @@ func TestDominatorsMultPred(t *testing.T) {
verifyDominators(t, fun, dominatorsSimple, doms)
}
-func TestPostDominators(t *testing.T) {
- c := testConfig(t)
- fun := Fun(c, "entry",
- Bloc("entry",
- Valu("mem", OpInitMem, TypeMem, 0, nil),
- Valu("p", OpConstBool, TypeBool, 1, nil),
- If("p", "a", "c")),
- Bloc("a",
- If("p", "b", "c")),
- Bloc("b",
- Goto("c")),
- Bloc("c",
- If("p", "b", "exit")),
- Bloc("exit",
- Exit("mem")))
-
- doms := map[string]string{"entry": "c",
- "a": "c",
- "b": "c",
- "c": "exit",
- }
-
- CheckFunc(fun.f)
- verifyDominators(t, fun, postDominators, doms)
-}
-
func TestInfiniteLoop(t *testing.T) {
c := testConfig(t)
// note lack of an exit block
@@ -415,8 +389,184 @@ func TestInfiniteLoop(t *testing.T) {
doms := map[string]string{"a": "entry",
"b": "a"}
verifyDominators(t, fun, dominators, doms)
+}
- // no exit block, so there are no post-dominators
- postDoms := map[string]string{}
- verifyDominators(t, fun, postDominators, postDoms)
+func TestDomTricky(t *testing.T) {
+ doms := map[string]string{
+ "4": "1",
+ "2": "4",
+ "5": "4",
+ "11": "4",
+ "15": "4", // the incorrect answer is "5"
+ "10": "15",
+ "19": "15",
+ }
+
+ if4 := [2]string{"2", "5"}
+ if5 := [2]string{"15", "11"}
+ if15 := [2]string{"19", "10"}
+
+ for i := 0; i < 8; i++ {
+ a := 1 & i
+ b := 1 & i >> 1
+ c := 1 & i >> 2
+
+ fun := Fun(testConfig(t), "1",
+ Bloc("1",
+ Valu("mem", OpInitMem, TypeMem, 0, nil),
+ Valu("p", OpConstBool, TypeBool, 1, nil),
+ Goto("4")),
+ Bloc("2",
+ Goto("11")),
+ Bloc("4",
+ If("p", if4[a], if4[1-a])), // 2, 5
+ Bloc("5",
+ If("p", if5[b], if5[1-b])), //15, 11
+ Bloc("10",
+ Exit("mem")),
+ Bloc("11",
+ Goto("15")),
+ Bloc("15",
+ If("p", if15[c], if15[1-c])), //19, 10
+ Bloc("19",
+ Goto("10")))
+ CheckFunc(fun.f)
+ verifyDominators(t, fun, dominators, doms)
+ verifyDominators(t, fun, dominatorsSimple, doms)
+ }
+}
+
+// generateDominatorMap uses dominatorsSimple to obtain a
+// reference dominator tree for testing faster algorithms.
+func generateDominatorMap(fut fun) map[string]string {
+ blockNames := map[*Block]string{}
+ for n, b := range fut.blocks {
+ blockNames[b] = n
+ }
+ referenceDom := dominatorsSimple(fut.f)
+ doms := make(map[string]string)
+ for _, b := range fut.f.Blocks {
+ if d := referenceDom[b.ID]; d != nil {
+ doms[blockNames[b]] = blockNames[d]
+ }
+ }
+ return doms
+}
+
+func TestDominatorsPostTricky(t *testing.T) {
+ c := testConfig(t)
+ fun := Fun(c, "b1",
+ Bloc("b1",
+ Valu("mem", OpInitMem, TypeMem, 0, nil),
+ Valu("p", OpConstBool, TypeBool, 1, nil),
+ If("p", "b3", "b2")),
+ Bloc("b3",
+ If("p", "b5", "b6")),
+ Bloc("b5",
+ Goto("b7")),
+ Bloc("b7",
+ If("p", "b8", "b11")),
+ Bloc("b8",
+ Goto("b13")),
+ Bloc("b13",
+ If("p", "b14", "b15")),
+ Bloc("b14",
+ Goto("b10")),
+ Bloc("b15",
+ Goto("b16")),
+ Bloc("b16",
+ Goto("b9")),
+ Bloc("b9",
+ Goto("b7")),
+ Bloc("b11",
+ Goto("b12")),
+ Bloc("b12",
+ If("p", "b10", "b8")),
+ Bloc("b10",
+ Goto("b6")),
+ Bloc("b6",
+ Goto("b17")),
+ Bloc("b17",
+ Goto("b18")),
+ Bloc("b18",
+ If("p", "b22", "b19")),
+ Bloc("b22",
+ Goto("b23")),
+ Bloc("b23",
+ If("p", "b21", "b19")),
+ Bloc("b19",
+ If("p", "b24", "b25")),
+ Bloc("b24",
+ Goto("b26")),
+ Bloc("b26",
+ Goto("b25")),
+ Bloc("b25",
+ If("p", "b27", "b29")),
+ Bloc("b27",
+ Goto("b30")),
+ Bloc("b30",
+ Goto("b28")),
+ Bloc("b29",
+ Goto("b31")),
+ Bloc("b31",
+ Goto("b28")),
+ Bloc("b28",
+ If("p", "b32", "b33")),
+ Bloc("b32",
+ Goto("b21")),
+ Bloc("b21",
+ Goto("b47")),
+ Bloc("b47",
+ If("p", "b45", "b46")),
+ Bloc("b45",
+ Goto("b48")),
+ Bloc("b48",
+ Goto("b49")),
+ Bloc("b49",
+ If("p", "b50", "b51")),
+ Bloc("b50",
+ Goto("b52")),
+ Bloc("b52",
+ Goto("b53")),
+ Bloc("b53",
+ Goto("b51")),
+ Bloc("b51",
+ Goto("b54")),
+ Bloc("b54",
+ Goto("b46")),
+ Bloc("b46",
+ Exit("mem")),
+ Bloc("b33",
+ Goto("b34")),
+ Bloc("b34",
+ Goto("b37")),
+ Bloc("b37",
+ If("p", "b35", "b36")),
+ Bloc("b35",
+ Goto("b38")),
+ Bloc("b38",
+ Goto("b39")),
+ Bloc("b39",
+ If("p", "b40", "b41")),
+ Bloc("b40",
+ Goto("b42")),
+ Bloc("b42",
+ Goto("b43")),
+ Bloc("b43",
+ Goto("b41")),
+ Bloc("b41",
+ Goto("b44")),
+ Bloc("b44",
+ Goto("b36")),
+ Bloc("b36",
+ Goto("b20")),
+ Bloc("b20",
+ Goto("b18")),
+ Bloc("b2",
+ Goto("b4")),
+ Bloc("b4",
+ Exit("mem")))
+ CheckFunc(fun.f)
+ doms := generateDominatorMap(fun)
+ verifyDominators(t, fun, dominators, doms)
}
diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go
index ce577ef055..0a67de9f05 100644
--- a/src/cmd/compile/internal/ssa/export_test.go
+++ b/src/cmd/compile/internal/ssa/export_test.go
@@ -48,6 +48,9 @@ func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) {
}
return LocalSlot{s.N, d.TypeFloat32(), s.Off}, LocalSlot{s.N, d.TypeFloat32(), s.Off + 4}
}
+func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
+ return LocalSlot{s.N, s.Type.FieldType(i), s.Off + s.Type.FieldOff(i)}
+}
func (DummyFrontend) Line(line int32) string {
return "unknown.go:0"
}
diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go
index 6e47b7f19c..11ff8d3792 100644
--- a/src/cmd/compile/internal/ssa/func.go
+++ b/src/cmd/compile/internal/ssa/func.go
@@ -36,6 +36,9 @@ type Func struct {
freeValues *Value // free Values linked by argstorage[0]. All other fields except ID are 0/nil.
freeBlocks *Block // free Blocks linked by succstorage[0]. All other fields except ID are 0/nil.
+ idom []*Block // precomputed immediate dominators
+ sdom sparseTree // precomputed dominator tree
+
constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type
}
@@ -284,7 +287,10 @@ func (b *Block) NewValue2I(line int32, op Op, t Type, auxint int64, arg0, arg1 *
func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *Value {
v := b.Func.newValue(op, t, b, line)
v.AuxInt = 0
- v.Args = []*Value{arg0, arg1, arg2}
+ v.Args = v.argstorage[:3]
+ v.argstorage[0] = arg0
+ v.argstorage[1] = arg1
+ v.argstorage[2] = arg2
arg0.Uses++
arg1.Uses++
arg2.Uses++
@@ -295,7 +301,10 @@ func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *V
func (b *Block) NewValue3I(line int32, op Op, t Type, auxint int64, arg0, arg1, arg2 *Value) *Value {
v := b.Func.newValue(op, t, b, line)
v.AuxInt = auxint
- v.Args = []*Value{arg0, arg1, arg2}
+ v.Args = v.argstorage[:3]
+ v.argstorage[0] = arg0
+ v.argstorage[1] = arg1
+ v.argstorage[2] = arg2
arg0.Uses++
arg1.Uses++
arg2.Uses++
@@ -309,7 +318,7 @@ func (f *Func) constVal(line int32, op Op, t Type, c int64, setAux bool) *Value
}
vv := f.constants[c]
for _, v := range vv {
- if v.Op == op && v.Type.Equal(t) {
+ if v.Op == op && v.Type.Compare(t) == CMPeq {
if setAux && v.AuxInt != c {
panic(fmt.Sprintf("cached const %s should have AuxInt of %d", v.LongString(), c))
}
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
index 4ad0f883b0..86123ac5c5 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64.rules
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -6,23 +6,23 @@
(Add64 x y) -> (ADDQ x y)
(AddPtr x y) -> (ADDQ x y)
(Add32 x y) -> (ADDL x y)
-(Add16 x y) -> (ADDW x y)
-(Add8 x y) -> (ADDB x y)
+(Add16 x y) -> (ADDL x y)
+(Add8 x y) -> (ADDL x y)
(Add32F x y) -> (ADDSS x y)
(Add64F x y) -> (ADDSD x y)
(Sub64 x y) -> (SUBQ x y)
(SubPtr x y) -> (SUBQ x y)
(Sub32 x y) -> (SUBL x y)
-(Sub16 x y) -> (SUBW x y)
-(Sub8 x y) -> (SUBB x y)
+(Sub16 x y) -> (SUBL x y)
+(Sub8 x y) -> (SUBL x y)
(Sub32F x y) -> (SUBSS x y)
(Sub64F x y) -> (SUBSD x y)
(Mul64 x y) -> (MULQ x y)
(Mul32 x y) -> (MULL x y)
-(Mul16 x y) -> (MULW x y)
-(Mul8 x y) -> (MULB x y)
+(Mul16 x y) -> (MULL x y)
+(Mul8 x y) -> (MULL x y)
(Mul32F x y) -> (MULSS x y)
(Mul64F x y) -> (MULSD x y)
@@ -60,30 +60,30 @@
(And64 x y) -> (ANDQ x y)
(And32 x y) -> (ANDL x y)
-(And16 x y) -> (ANDW x y)
-(And8 x y) -> (ANDB x y)
+(And16 x y) -> (ANDL x y)
+(And8 x y) -> (ANDL x y)
(Or64 x y) -> (ORQ x y)
(Or32 x y) -> (ORL x y)
-(Or16 x y) -> (ORW x y)
-(Or8 x y) -> (ORB x y)
+(Or16 x y) -> (ORL x y)
+(Or8 x y) -> (ORL x y)
(Xor64 x y) -> (XORQ x y)
(Xor32 x y) -> (XORL x y)
-(Xor16 x y) -> (XORW x y)
-(Xor8 x y) -> (XORB x y)
+(Xor16 x y) -> (XORL x y)
+(Xor8 x y) -> (XORL x y)
(Neg64 x) -> (NEGQ x)
(Neg32 x) -> (NEGL x)
-(Neg16 x) -> (NEGW x)
-(Neg8 x) -> (NEGB x)
+(Neg16 x) -> (NEGL x)
+(Neg8 x) -> (NEGL x)
(Neg32F x) -> (PXOR x (MOVSSconst <config.Frontend().TypeFloat32()> [f2i(math.Copysign(0, -1))]))
(Neg64F x) -> (PXOR x (MOVSDconst <config.Frontend().TypeFloat64()> [f2i(math.Copysign(0, -1))]))
(Com64 x) -> (NOTQ x)
(Com32 x) -> (NOTL x)
-(Com16 x) -> (NOTW x)
-(Com8 x) -> (NOTB x)
+(Com16 x) -> (NOTL x)
+(Com8 x) -> (NOTL x)
// CMPQconst 0 below is redundant because BSF sets Z but how to remove?
(Ctz64 <t> x) -> (CMOVQEQconst (BSFQ <t> x) (CMPQconst x [0]) [64])
@@ -169,15 +169,15 @@
(Lsh32x16 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
(Lsh32x8 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
-(Lsh16x64 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPQconst y [16])))
-(Lsh16x32 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
-(Lsh16x16 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPWconst y [16])))
-(Lsh16x8 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
+(Lsh16x64 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+(Lsh16x32 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+(Lsh16x16 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+(Lsh16x8 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
-(Lsh8x64 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPQconst y [8])))
-(Lsh8x32 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
-(Lsh8x16 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
-(Lsh8x8 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
+(Lsh8x64 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+(Lsh8x32 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+(Lsh8x16 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+(Lsh8x8 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
(Lrot64 <t> x [c]) -> (ROLQconst <t> [c&63] x)
(Lrot32 <t> x [c]) -> (ROLLconst <t> [c&31] x)
@@ -194,38 +194,38 @@
(Rsh32Ux16 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
(Rsh32Ux8 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
-(Rsh16Ux64 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPQconst y [16])))
-(Rsh16Ux32 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
-(Rsh16Ux16 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPWconst y [16])))
-(Rsh16Ux8 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
+(Rsh16Ux64 <t> x y) -> (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPQconst y [16])))
+(Rsh16Ux32 <t> x y) -> (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
+(Rsh16Ux16 <t> x y) -> (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPWconst y [16])))
+(Rsh16Ux8 <t> x y) -> (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
-(Rsh8Ux64 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPQconst y [8])))
-(Rsh8Ux32 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
-(Rsh8Ux16 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
-(Rsh8Ux8 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
+(Rsh8Ux64 <t> x y) -> (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPQconst y [8])))
+(Rsh8Ux32 <t> x y) -> (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
+(Rsh8Ux16 <t> x y) -> (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
+(Rsh8Ux8 <t> x y) -> (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
// Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value.
// We implement this by setting the shift value to -1 (all ones) if the shift value is >= width.
// Note: for small shift widths we generate 32 bits of mask even when we don't need it all.
(Rsh64x64 <t> x y) -> (SARQ <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [64])))))
(Rsh64x32 <t> x y) -> (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [64])))))
-(Rsh64x16 <t> x y) -> (SARQ <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [64])))))
-(Rsh64x8 <t> x y) -> (SARQ <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [64])))))
+(Rsh64x16 <t> x y) -> (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [64])))))
+(Rsh64x8 <t> x y) -> (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [64])))))
(Rsh32x64 <t> x y) -> (SARL <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [32])))))
(Rsh32x32 <t> x y) -> (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [32])))))
-(Rsh32x16 <t> x y) -> (SARL <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [32])))))
-(Rsh32x8 <t> x y) -> (SARL <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [32])))))
+(Rsh32x16 <t> x y) -> (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [32])))))
+(Rsh32x8 <t> x y) -> (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [32])))))
(Rsh16x64 <t> x y) -> (SARW <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [16])))))
(Rsh16x32 <t> x y) -> (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [16])))))
-(Rsh16x16 <t> x y) -> (SARW <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [16])))))
-(Rsh16x8 <t> x y) -> (SARW <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [16])))))
+(Rsh16x16 <t> x y) -> (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [16])))))
+(Rsh16x8 <t> x y) -> (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [16])))))
(Rsh8x64 <t> x y) -> (SARB <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [8])))))
(Rsh8x32 <t> x y) -> (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [8])))))
-(Rsh8x16 <t> x y) -> (SARB <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [8])))))
-(Rsh8x8 <t> x y) -> (SARB <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [8])))))
+(Rsh8x16 <t> x y) -> (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [8])))))
+(Rsh8x8 <t> x y) -> (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [8])))))
(Less64 x y) -> (SETL (CMPQ x y))
(Less32 x y) -> (SETL (CMPL x y))
@@ -281,6 +281,7 @@
(Eq32 x y) -> (SETEQ (CMPL x y))
(Eq16 x y) -> (SETEQ (CMPW x y))
(Eq8 x y) -> (SETEQ (CMPB x y))
+(EqB x y) -> (SETEQ (CMPB x y))
(EqPtr x y) -> (SETEQ (CMPQ x y))
(Eq64F x y) -> (SETEQF (UCOMISD x y))
(Eq32F x y) -> (SETEQF (UCOMISS x y))
@@ -289,6 +290,7 @@
(Neq32 x y) -> (SETNE (CMPL x y))
(Neq16 x y) -> (SETNE (CMPW x y))
(Neq8 x y) -> (SETNE (CMPB x y))
+(NeqB x y) -> (SETNE (CMPB x y))
(NeqPtr x y) -> (SETNE (CMPQ x y))
(Neq64F x y) -> (SETNEF (UCOMISD x y))
(Neq32F x y) -> (SETNEF (UCOMISS x y))
@@ -366,19 +368,21 @@
(Move [size] dst src mem) && (size > 16*64 || config.noDuffDevice) && size%8 == 0 ->
(REPMOVSQ dst src (MOVQconst [size/8]) mem)
-(Not x) -> (XORBconst [1] x)
+(AndB x y) -> (ANDL x y)
+(OrB x y) -> (ORL x y)
+(Not x) -> (XORLconst [1] x)
(OffPtr [off] ptr) && is32Bit(off) -> (ADDQconst [off] ptr)
(OffPtr [off] ptr) -> (ADDQ (MOVQconst [off]) ptr)
-(Const8 [val]) -> (MOVBconst [val])
-(Const16 [val]) -> (MOVWconst [val])
+(Const8 [val]) -> (MOVLconst [val])
+(Const16 [val]) -> (MOVLconst [val])
(Const32 [val]) -> (MOVLconst [val])
(Const64 [val]) -> (MOVQconst [val])
(Const32F [val]) -> (MOVSSconst [val])
(Const64F [val]) -> (MOVSDconst [val])
(ConstNil) -> (MOVQconst [0])
-(ConstBool [b]) -> (MOVBconst [b])
+(ConstBool [b]) -> (MOVLconst [b])
(Addr {sym} base) -> (LEAQ {sym} base)
@@ -404,22 +408,22 @@
(If cond yes no) -> (NE (TESTB cond cond) yes no)
-(NE (TESTB (SETL cmp)) yes no) -> (LT cmp yes no)
-(NE (TESTB (SETLE cmp)) yes no) -> (LE cmp yes no)
-(NE (TESTB (SETG cmp)) yes no) -> (GT cmp yes no)
-(NE (TESTB (SETGE cmp)) yes no) -> (GE cmp yes no)
-(NE (TESTB (SETEQ cmp)) yes no) -> (EQ cmp yes no)
-(NE (TESTB (SETNE cmp)) yes no) -> (NE cmp yes no)
-(NE (TESTB (SETB cmp)) yes no) -> (ULT cmp yes no)
-(NE (TESTB (SETBE cmp)) yes no) -> (ULE cmp yes no)
-(NE (TESTB (SETA cmp)) yes no) -> (UGT cmp yes no)
-(NE (TESTB (SETAE cmp)) yes no) -> (UGE cmp yes no)
+(NE (TESTB (SETL cmp) (SETL cmp)) yes no) -> (LT cmp yes no)
+(NE (TESTB (SETLE cmp) (SETLE cmp)) yes no) -> (LE cmp yes no)
+(NE (TESTB (SETG cmp) (SETG cmp)) yes no) -> (GT cmp yes no)
+(NE (TESTB (SETGE cmp) (SETGE cmp)) yes no) -> (GE cmp yes no)
+(NE (TESTB (SETEQ cmp) (SETEQ cmp)) yes no) -> (EQ cmp yes no)
+(NE (TESTB (SETNE cmp) (SETNE cmp)) yes no) -> (NE cmp yes no)
+(NE (TESTB (SETB cmp) (SETB cmp)) yes no) -> (ULT cmp yes no)
+(NE (TESTB (SETBE cmp) (SETBE cmp)) yes no) -> (ULE cmp yes no)
+(NE (TESTB (SETA cmp) (SETA cmp)) yes no) -> (UGT cmp yes no)
+(NE (TESTB (SETAE cmp) (SETAE cmp)) yes no) -> (UGE cmp yes no)
// Special case for floating point - LF/LEF not generated
-(NE (TESTB (SETGF cmp)) yes no) -> (UGT cmp yes no)
-(NE (TESTB (SETGEF cmp)) yes no) -> (UGE cmp yes no)
-(NE (TESTB (SETEQF cmp)) yes no) -> (EQF cmp yes no)
-(NE (TESTB (SETNEF cmp)) yes no) -> (NEF cmp yes no)
+(NE (TESTB (SETGF cmp) (SETGF cmp)) yes no) -> (UGT cmp yes no)
+(NE (TESTB (SETGEF cmp) (SETGEF cmp)) yes no) -> (UGE cmp yes no)
+(NE (TESTB (SETEQF cmp) (SETEQF cmp)) yes no) -> (EQF cmp yes no)
+(NE (TESTB (SETNEF cmp) (SETNEF cmp)) yes no) -> (NEF cmp yes no)
// Disabled because it interferes with the pattern match above and makes worse code.
// (SETNEF x) -> (ORQ (SETNE <config.Frontend().TypeInt8()> x) (SETNAN <config.Frontend().TypeInt8()> x))
@@ -439,44 +443,22 @@
(ADDQ (MOVQconst [c]) x) && is32Bit(c) -> (ADDQconst [c] x)
(ADDL x (MOVLconst [c])) -> (ADDLconst [c] x)
(ADDL (MOVLconst [c]) x) -> (ADDLconst [c] x)
-(ADDW x (MOVWconst [c])) -> (ADDWconst [c] x)
-(ADDW (MOVWconst [c]) x) -> (ADDWconst [c] x)
-(ADDB x (MOVBconst [c])) -> (ADDBconst [c] x)
-(ADDB (MOVBconst [c]) x) -> (ADDBconst [c] x)
(SUBQ x (MOVQconst [c])) && is32Bit(c) -> (SUBQconst x [c])
(SUBQ (MOVQconst [c]) x) && is32Bit(c) -> (NEGQ (SUBQconst <v.Type> x [c]))
(SUBL x (MOVLconst [c])) -> (SUBLconst x [c])
(SUBL (MOVLconst [c]) x) -> (NEGL (SUBLconst <v.Type> x [c]))
-(SUBW x (MOVWconst [c])) -> (SUBWconst x [c])
-(SUBW (MOVWconst [c]) x) -> (NEGW (SUBWconst <v.Type> x [c]))
-(SUBB x (MOVBconst [c])) -> (SUBBconst x [c])
-(SUBB (MOVBconst [c]) x) -> (NEGB (SUBBconst <v.Type> x [c]))
(MULQ x (MOVQconst [c])) && is32Bit(c) -> (MULQconst [c] x)
(MULQ (MOVQconst [c]) x) && is32Bit(c) -> (MULQconst [c] x)
(MULL x (MOVLconst [c])) -> (MULLconst [c] x)
(MULL (MOVLconst [c]) x) -> (MULLconst [c] x)
-(MULW x (MOVWconst [c])) -> (MULWconst [c] x)
-(MULW (MOVWconst [c]) x) -> (MULWconst [c] x)
-(MULB x (MOVBconst [c])) -> (MULBconst [c] x)
-(MULB (MOVBconst [c]) x) -> (MULBconst [c] x)
(ANDQ x (MOVQconst [c])) && is32Bit(c) -> (ANDQconst [c] x)
(ANDQ (MOVQconst [c]) x) && is32Bit(c) -> (ANDQconst [c] x)
(ANDL x (MOVLconst [c])) -> (ANDLconst [c] x)
(ANDL (MOVLconst [c]) x) -> (ANDLconst [c] x)
-(ANDW x (MOVLconst [c])) -> (ANDWconst [c] x)
-(ANDW (MOVLconst [c]) x) -> (ANDWconst [c] x)
-(ANDW x (MOVWconst [c])) -> (ANDWconst [c] x)
-(ANDW (MOVWconst [c]) x) -> (ANDWconst [c] x)
-(ANDB x (MOVLconst [c])) -> (ANDBconst [c] x)
-(ANDB (MOVLconst [c]) x) -> (ANDBconst [c] x)
-(ANDB x (MOVBconst [c])) -> (ANDBconst [c] x)
-(ANDB (MOVBconst [c]) x) -> (ANDBconst [c] x)
-(ANDBconst [c] (ANDBconst [d] x)) -> (ANDBconst [c & d] x)
-(ANDWconst [c] (ANDWconst [d] x)) -> (ANDWconst [c & d] x)
(ANDLconst [c] (ANDLconst [d] x)) -> (ANDLconst [c & d] x)
(ANDQconst [c] (ANDQconst [d] x)) -> (ANDQconst [c & d] x)
@@ -484,108 +466,69 @@
(ORQ (MOVQconst [c]) x) && is32Bit(c) -> (ORQconst [c] x)
(ORL x (MOVLconst [c])) -> (ORLconst [c] x)
(ORL (MOVLconst [c]) x) -> (ORLconst [c] x)
-(ORW x (MOVWconst [c])) -> (ORWconst [c] x)
-(ORW (MOVWconst [c]) x) -> (ORWconst [c] x)
-(ORB x (MOVBconst [c])) -> (ORBconst [c] x)
-(ORB (MOVBconst [c]) x) -> (ORBconst [c] x)
(XORQ x (MOVQconst [c])) && is32Bit(c) -> (XORQconst [c] x)
(XORQ (MOVQconst [c]) x) && is32Bit(c) -> (XORQconst [c] x)
(XORL x (MOVLconst [c])) -> (XORLconst [c] x)
(XORL (MOVLconst [c]) x) -> (XORLconst [c] x)
-(XORW x (MOVWconst [c])) -> (XORWconst [c] x)
-(XORW (MOVWconst [c]) x) -> (XORWconst [c] x)
-(XORB x (MOVBconst [c])) -> (XORBconst [c] x)
-(XORB (MOVBconst [c]) x) -> (XORBconst [c] x)
(SHLQ x (MOVQconst [c])) -> (SHLQconst [c&63] x)
(SHLQ x (MOVLconst [c])) -> (SHLQconst [c&63] x)
-(SHLQ x (MOVWconst [c])) -> (SHLQconst [c&63] x)
-(SHLQ x (MOVBconst [c])) -> (SHLQconst [c&63] x)
(SHLL x (MOVQconst [c])) -> (SHLLconst [c&31] x)
(SHLL x (MOVLconst [c])) -> (SHLLconst [c&31] x)
-(SHLL x (MOVWconst [c])) -> (SHLLconst [c&31] x)
-(SHLL x (MOVBconst [c])) -> (SHLLconst [c&31] x)
-
-(SHLW x (MOVQconst [c])) -> (SHLWconst [c&31] x)
-(SHLW x (MOVLconst [c])) -> (SHLWconst [c&31] x)
-(SHLW x (MOVWconst [c])) -> (SHLWconst [c&31] x)
-(SHLW x (MOVBconst [c])) -> (SHLWconst [c&31] x)
-
-(SHLB x (MOVQconst [c])) -> (SHLBconst [c&31] x)
-(SHLB x (MOVLconst [c])) -> (SHLBconst [c&31] x)
-(SHLB x (MOVWconst [c])) -> (SHLBconst [c&31] x)
-(SHLB x (MOVBconst [c])) -> (SHLBconst [c&31] x)
(SHRQ x (MOVQconst [c])) -> (SHRQconst [c&63] x)
(SHRQ x (MOVLconst [c])) -> (SHRQconst [c&63] x)
-(SHRQ x (MOVWconst [c])) -> (SHRQconst [c&63] x)
-(SHRQ x (MOVBconst [c])) -> (SHRQconst [c&63] x)
(SHRL x (MOVQconst [c])) -> (SHRLconst [c&31] x)
(SHRL x (MOVLconst [c])) -> (SHRLconst [c&31] x)
-(SHRL x (MOVWconst [c])) -> (SHRLconst [c&31] x)
-(SHRL x (MOVBconst [c])) -> (SHRLconst [c&31] x)
(SHRW x (MOVQconst [c])) -> (SHRWconst [c&31] x)
(SHRW x (MOVLconst [c])) -> (SHRWconst [c&31] x)
-(SHRW x (MOVWconst [c])) -> (SHRWconst [c&31] x)
-(SHRW x (MOVBconst [c])) -> (SHRWconst [c&31] x)
(SHRB x (MOVQconst [c])) -> (SHRBconst [c&31] x)
(SHRB x (MOVLconst [c])) -> (SHRBconst [c&31] x)
-(SHRB x (MOVWconst [c])) -> (SHRBconst [c&31] x)
-(SHRB x (MOVBconst [c])) -> (SHRBconst [c&31] x)
(SARQ x (MOVQconst [c])) -> (SARQconst [c&63] x)
(SARQ x (MOVLconst [c])) -> (SARQconst [c&63] x)
-(SARQ x (MOVWconst [c])) -> (SARQconst [c&63] x)
-(SARQ x (MOVBconst [c])) -> (SARQconst [c&63] x)
(SARL x (MOVQconst [c])) -> (SARLconst [c&31] x)
(SARL x (MOVLconst [c])) -> (SARLconst [c&31] x)
-(SARL x (MOVWconst [c])) -> (SARLconst [c&31] x)
-(SARL x (MOVBconst [c])) -> (SARLconst [c&31] x)
(SARW x (MOVQconst [c])) -> (SARWconst [c&31] x)
(SARW x (MOVLconst [c])) -> (SARWconst [c&31] x)
-(SARW x (MOVWconst [c])) -> (SARWconst [c&31] x)
-(SARW x (MOVBconst [c])) -> (SARWconst [c&31] x)
(SARB x (MOVQconst [c])) -> (SARBconst [c&31] x)
(SARB x (MOVLconst [c])) -> (SARBconst [c&31] x)
-(SARB x (MOVWconst [c])) -> (SARBconst [c&31] x)
-(SARB x (MOVBconst [c])) -> (SARBconst [c&31] x)
-(SARB x (ANDBconst [31] y)) -> (SARB x y)
-(SARW x (ANDWconst [31] y)) -> (SARW x y)
(SARL x (ANDLconst [31] y)) -> (SARL x y)
(SARQ x (ANDQconst [63] y)) -> (SARQ x y)
-(SHLB x (ANDBconst [31] y)) -> (SHLB x y)
-(SHLW x (ANDWconst [31] y)) -> (SHLW x y)
(SHLL x (ANDLconst [31] y)) -> (SHLL x y)
(SHLQ x (ANDQconst [63] y)) -> (SHLQ x y)
-(SHRB x (ANDBconst [31] y)) -> (SHRB x y)
-(SHRW x (ANDWconst [31] y)) -> (SHRW x y)
(SHRL x (ANDLconst [31] y)) -> (SHRL x y)
(SHRQ x (ANDQconst [63] y)) -> (SHRQ x y)
// Note: the word and byte shifts keep the low 5 bits (not the low 4 or 3 bits)
// because the x86 instructions are defined to use all 5 bits of the shift even
// for the small shifts. I don't think we'll ever generate a weird shift (e.g.
-// (SHLW x (MOVWconst [24])), but just in case.
+// (SHRW x (MOVLconst [24])), but just in case.
(CMPQ x (MOVQconst [c])) && is32Bit(c) -> (CMPQconst x [c])
(CMPQ (MOVQconst [c]) x) && is32Bit(c) -> (InvertFlags (CMPQconst x [c]))
(CMPL x (MOVLconst [c])) -> (CMPLconst x [c])
(CMPL (MOVLconst [c]) x) -> (InvertFlags (CMPLconst x [c]))
-(CMPW x (MOVWconst [c])) -> (CMPWconst x [c])
-(CMPW (MOVWconst [c]) x) -> (InvertFlags (CMPWconst x [c]))
-(CMPB x (MOVBconst [c])) -> (CMPBconst x [c])
-(CMPB (MOVBconst [c]) x) -> (InvertFlags (CMPBconst x [c]))
+(CMPW x (MOVLconst [c])) -> (CMPWconst x [int64(int16(c))])
+(CMPW (MOVLconst [c]) x) -> (InvertFlags (CMPWconst x [int64(int16(c))]))
+(CMPB x (MOVLconst [c])) -> (CMPBconst x [int64(int8(c))])
+(CMPB (MOVLconst [c]) x) -> (InvertFlags (CMPBconst x [int64(int8(c))]))
+
+// Using MOVBQZX instead of ANDQ is cheaper.
+(ANDQconst [0xFF] x) -> (MOVBQZX x)
+(ANDQconst [0xFFFF] x) -> (MOVWQZX x)
+(ANDQconst [0xFFFFFFFF] x) -> (MOVLQZX x)
// strength reduction
// Assumes that the following costs from https://gmplib.org/~tege/x86-timing.pdf:
@@ -684,18 +627,18 @@
// Make sure we don't combine these ops if the load has another use.
// This prevents a single load from being split into multiple loads
// which then might return different values. See test/atomicload.go.
-(MOVBQSX x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 -> @x.Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
-(MOVBQZX x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 -> @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
-(MOVWQSX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 -> @x.Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
-(MOVWQZX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
-(MOVLQSX x:(MOVLload [off] {sym} ptr mem)) && x.Uses == 1 -> @x.Block (MOVLQSXload <v.Type> [off] {sym} ptr mem)
-(MOVLQZX x:(MOVLload [off] {sym} ptr mem)) && x.Uses == 1 -> @x.Block (MOVLload <v.Type> [off] {sym} ptr mem)
+(MOVBQSX x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
+(MOVBQZX x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
+(MOVWQSX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
+(MOVWQZX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
+(MOVLQSX x:(MOVLload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLQSXload <v.Type> [off] {sym} ptr mem)
+(MOVLQZX x:(MOVLload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLload <v.Type> [off] {sym} ptr mem)
-(MOVBQZX x:(MOVBloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 -> @x.Block (MOVBloadidx1 <v.Type> [off] {sym} ptr idx mem)
-(MOVWQZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 -> @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem)
-(MOVWQZX x:(MOVWloadidx2 [off] {sym} ptr idx mem)) && x.Uses == 1 -> @x.Block (MOVWloadidx2 <v.Type> [off] {sym} ptr idx mem)
-(MOVLQZX x:(MOVLloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 -> @x.Block (MOVLloadidx1 <v.Type> [off] {sym} ptr idx mem)
-(MOVLQZX x:(MOVLloadidx4 [off] {sym} ptr idx mem)) && x.Uses == 1 -> @x.Block (MOVLloadidx4 <v.Type> [off] {sym} ptr idx mem)
+(MOVBQZX x:(MOVBloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBloadidx1 <v.Type> [off] {sym} ptr idx mem)
+(MOVWQZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem)
+(MOVWQZX x:(MOVWloadidx2 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx2 <v.Type> [off] {sym} ptr idx mem)
+(MOVLQZX x:(MOVLloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLloadidx1 <v.Type> [off] {sym} ptr idx mem)
+(MOVLQZX x:(MOVLloadidx4 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLloadidx4 <v.Type> [off] {sym} ptr idx mem)
// replace load from same location as preceding store with copy
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
@@ -704,12 +647,12 @@
(MOVQload [off] {sym} ptr (MOVQstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
// Fold extensions and ANDs together.
-(MOVBQZX (ANDBconst [c] x)) -> (ANDQconst [c & 0xff] x)
-(MOVWQZX (ANDWconst [c] x)) -> (ANDQconst [c & 0xffff] x)
-(MOVLQZX (ANDLconst [c] x)) && c & 0x80000000 == 0 -> (ANDQconst [c & 0x7fffffff] x)
-(MOVBQSX (ANDBconst [c] x)) && c & 0x80 == 0 -> (ANDQconst [c & 0x7f] x)
-(MOVWQSX (ANDWconst [c] x)) && c & 0x8000 == 0 -> (ANDQconst [c & 0x7fff] x)
-(MOVLQSX (ANDLconst [c] x)) && c & 0x80000000 == 0 -> (ANDQconst [c & 0x7fffffff] x)
+(MOVBQZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xff] x)
+(MOVWQZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xffff] x)
+(MOVLQZX (ANDLconst [c] x)) -> (ANDLconst [c] x)
+(MOVBQSX (ANDLconst [c] x)) && c & 0x80 == 0 -> (ANDLconst [c & 0x7f] x)
+(MOVWQSX (ANDLconst [c] x)) && c & 0x8000 == 0 -> (ANDLconst [c & 0x7fff] x)
+(MOVLQSX (ANDLconst [c] x)) && c & 0x80000000 == 0 -> (ANDLconst [c & 0x7fffffff] x)
// Don't extend before storing
(MOVLstore [off] {sym} ptr (MOVLQSX x) mem) -> (MOVLstore [off] {sym} ptr x mem)
@@ -745,9 +688,9 @@
(MOVQstoreconst [makeValAndOff(c,off)] {sym} ptr mem)
(MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
(MOVLstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
-(MOVWstore [off] {sym} ptr (MOVWconst [c]) mem) && validOff(off) ->
+(MOVWstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
(MOVWstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
-(MOVBstore [off] {sym} ptr (MOVBconst [c]) mem) && validOff(off) ->
+(MOVBstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
(MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
// Fold address offsets into constant stores.
@@ -1081,22 +1024,27 @@
(CMPLconst (MOVLconst [x]) [y]) && int32(x)<int32(y) && uint32(x)>uint32(y) -> (FlagLT_UGT)
(CMPLconst (MOVLconst [x]) [y]) && int32(x)>int32(y) && uint32(x)<uint32(y) -> (FlagGT_ULT)
(CMPLconst (MOVLconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT)
-(CMPWconst (MOVWconst [x]) [y]) && int16(x)==int16(y) -> (FlagEQ)
-(CMPWconst (MOVWconst [x]) [y]) && int16(x)<int16(y) && uint16(x)<uint16(y) -> (FlagLT_ULT)
-(CMPWconst (MOVWconst [x]) [y]) && int16(x)<int16(y) && uint16(x)>uint16(y) -> (FlagLT_UGT)
-(CMPWconst (MOVWconst [x]) [y]) && int16(x)>int16(y) && uint16(x)<uint16(y) -> (FlagGT_ULT)
-(CMPWconst (MOVWconst [x]) [y]) && int16(x)>int16(y) && uint16(x)>uint16(y) -> (FlagGT_UGT)
-(CMPBconst (MOVBconst [x]) [y]) && int8(x)==int8(y) -> (FlagEQ)
-(CMPBconst (MOVBconst [x]) [y]) && int8(x)<int8(y) && uint8(x)<uint8(y) -> (FlagLT_ULT)
-(CMPBconst (MOVBconst [x]) [y]) && int8(x)<int8(y) && uint8(x)>uint8(y) -> (FlagLT_UGT)
-(CMPBconst (MOVBconst [x]) [y]) && int8(x)>int8(y) && uint8(x)<uint8(y) -> (FlagGT_ULT)
-(CMPBconst (MOVBconst [x]) [y]) && int8(x)>int8(y) && uint8(x)>uint8(y) -> (FlagGT_UGT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)==int16(y) -> (FlagEQ)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)<int16(y) && uint16(x)<uint16(y) -> (FlagLT_ULT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)<int16(y) && uint16(x)>uint16(y) -> (FlagLT_UGT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)>int16(y) && uint16(x)<uint16(y) -> (FlagGT_ULT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)>int16(y) && uint16(x)>uint16(y) -> (FlagGT_UGT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)==int8(y) -> (FlagEQ)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)<int8(y) && uint8(x)<uint8(y) -> (FlagLT_ULT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)<int8(y) && uint8(x)>uint8(y) -> (FlagLT_UGT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)>int8(y) && uint8(x)<uint8(y) -> (FlagGT_ULT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)>int8(y) && uint8(x)>uint8(y) -> (FlagGT_UGT)
// Other known comparisons.
+(CMPQconst (MOVBQZX _) [c]) && 0xFF < c -> (FlagLT_ULT)
+(CMPQconst (MOVWQZX _) [c]) && 0xFFFF < c -> (FlagLT_ULT)
+(CMPQconst (MOVLQZX _) [c]) && 0xFFFFFFFF < c -> (FlagLT_ULT)
+(CMPLconst (SHRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n) -> (FlagLT_ULT)
+(CMPQconst (SHRQconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n) -> (FlagLT_ULT)
(CMPQconst (ANDQconst _ [m]) [n]) && 0 <= m && m < n -> (FlagLT_ULT)
(CMPLconst (ANDLconst _ [m]) [n]) && 0 <= int32(m) && int32(m) < int32(n) -> (FlagLT_ULT)
-(CMPWconst (ANDWconst _ [m]) [n]) && 0 <= int16(m) && int16(m) < int16(n) -> (FlagLT_ULT)
-(CMPBconst (ANDBconst _ [m]) [n]) && 0 <= int8(m) && int8(m) < int8(n) -> (FlagLT_ULT)
+(CMPWconst (ANDLconst _ [m]) [n]) && 0 <= int16(m) && int16(m) < int16(n) -> (FlagLT_ULT)
+(CMPBconst (ANDLconst _ [m]) [n]) && 0 <= int8(m) && int8(m) < int8(n) -> (FlagLT_ULT)
// TODO: DIVxU also.
// Absorb flag constants into SBB ops.
@@ -1173,175 +1121,140 @@
(UGE (FlagGT_UGT) yes no) -> (First nil yes no)
// Absorb flag constants into SETxx ops.
-(SETEQ (FlagEQ)) -> (MOVBconst [1])
-(SETEQ (FlagLT_ULT)) -> (MOVBconst [0])
-(SETEQ (FlagLT_UGT)) -> (MOVBconst [0])
-(SETEQ (FlagGT_ULT)) -> (MOVBconst [0])
-(SETEQ (FlagGT_UGT)) -> (MOVBconst [0])
+(SETEQ (FlagEQ)) -> (MOVLconst [1])
+(SETEQ (FlagLT_ULT)) -> (MOVLconst [0])
+(SETEQ (FlagLT_UGT)) -> (MOVLconst [0])
+(SETEQ (FlagGT_ULT)) -> (MOVLconst [0])
+(SETEQ (FlagGT_UGT)) -> (MOVLconst [0])
-(SETNE (FlagEQ)) -> (MOVBconst [0])
-(SETNE (FlagLT_ULT)) -> (MOVBconst [1])
-(SETNE (FlagLT_UGT)) -> (MOVBconst [1])
-(SETNE (FlagGT_ULT)) -> (MOVBconst [1])
-(SETNE (FlagGT_UGT)) -> (MOVBconst [1])
+(SETNE (FlagEQ)) -> (MOVLconst [0])
+(SETNE (FlagLT_ULT)) -> (MOVLconst [1])
+(SETNE (FlagLT_UGT)) -> (MOVLconst [1])
+(SETNE (FlagGT_ULT)) -> (MOVLconst [1])
+(SETNE (FlagGT_UGT)) -> (MOVLconst [1])
-(SETL (FlagEQ)) -> (MOVBconst [0])
-(SETL (FlagLT_ULT)) -> (MOVBconst [1])
-(SETL (FlagLT_UGT)) -> (MOVBconst [1])
-(SETL (FlagGT_ULT)) -> (MOVBconst [0])
-(SETL (FlagGT_UGT)) -> (MOVBconst [0])
+(SETL (FlagEQ)) -> (MOVLconst [0])
+(SETL (FlagLT_ULT)) -> (MOVLconst [1])
+(SETL (FlagLT_UGT)) -> (MOVLconst [1])
+(SETL (FlagGT_ULT)) -> (MOVLconst [0])
+(SETL (FlagGT_UGT)) -> (MOVLconst [0])
-(SETLE (FlagEQ)) -> (MOVBconst [1])
-(SETLE (FlagLT_ULT)) -> (MOVBconst [1])
-(SETLE (FlagLT_UGT)) -> (MOVBconst [1])
-(SETLE (FlagGT_ULT)) -> (MOVBconst [0])
-(SETLE (FlagGT_UGT)) -> (MOVBconst [0])
+(SETLE (FlagEQ)) -> (MOVLconst [1])
+(SETLE (FlagLT_ULT)) -> (MOVLconst [1])
+(SETLE (FlagLT_UGT)) -> (MOVLconst [1])
+(SETLE (FlagGT_ULT)) -> (MOVLconst [0])
+(SETLE (FlagGT_UGT)) -> (MOVLconst [0])
-(SETG (FlagEQ)) -> (MOVBconst [0])
-(SETG (FlagLT_ULT)) -> (MOVBconst [0])
-(SETG (FlagLT_UGT)) -> (MOVBconst [0])
-(SETG (FlagGT_ULT)) -> (MOVBconst [1])
-(SETG (FlagGT_UGT)) -> (MOVBconst [1])
+(SETG (FlagEQ)) -> (MOVLconst [0])
+(SETG (FlagLT_ULT)) -> (MOVLconst [0])
+(SETG (FlagLT_UGT)) -> (MOVLconst [0])
+(SETG (FlagGT_ULT)) -> (MOVLconst [1])
+(SETG (FlagGT_UGT)) -> (MOVLconst [1])
-(SETGE (FlagEQ)) -> (MOVBconst [1])
-(SETGE (FlagLT_ULT)) -> (MOVBconst [0])
-(SETGE (FlagLT_UGT)) -> (MOVBconst [0])
-(SETGE (FlagGT_ULT)) -> (MOVBconst [1])
-(SETGE (FlagGT_UGT)) -> (MOVBconst [1])
+(SETGE (FlagEQ)) -> (MOVLconst [1])
+(SETGE (FlagLT_ULT)) -> (MOVLconst [0])
+(SETGE (FlagLT_UGT)) -> (MOVLconst [0])
+(SETGE (FlagGT_ULT)) -> (MOVLconst [1])
+(SETGE (FlagGT_UGT)) -> (MOVLconst [1])
-(SETB (FlagEQ)) -> (MOVBconst [0])
-(SETB (FlagLT_ULT)) -> (MOVBconst [1])
-(SETB (FlagLT_UGT)) -> (MOVBconst [0])
-(SETB (FlagGT_ULT)) -> (MOVBconst [1])
-(SETB (FlagGT_UGT)) -> (MOVBconst [0])
+(SETB (FlagEQ)) -> (MOVLconst [0])
+(SETB (FlagLT_ULT)) -> (MOVLconst [1])
+(SETB (FlagLT_UGT)) -> (MOVLconst [0])
+(SETB (FlagGT_ULT)) -> (MOVLconst [1])
+(SETB (FlagGT_UGT)) -> (MOVLconst [0])
-(SETBE (FlagEQ)) -> (MOVBconst [1])
-(SETBE (FlagLT_ULT)) -> (MOVBconst [1])
-(SETBE (FlagLT_UGT)) -> (MOVBconst [0])
-(SETBE (FlagGT_ULT)) -> (MOVBconst [1])
-(SETBE (FlagGT_UGT)) -> (MOVBconst [0])
+(SETBE (FlagEQ)) -> (MOVLconst [1])
+(SETBE (FlagLT_ULT)) -> (MOVLconst [1])
+(SETBE (FlagLT_UGT)) -> (MOVLconst [0])
+(SETBE (FlagGT_ULT)) -> (MOVLconst [1])
+(SETBE (FlagGT_UGT)) -> (MOVLconst [0])
-(SETA (FlagEQ)) -> (MOVBconst [0])
-(SETA (FlagLT_ULT)) -> (MOVBconst [0])
-(SETA (FlagLT_UGT)) -> (MOVBconst [1])
-(SETA (FlagGT_ULT)) -> (MOVBconst [0])
-(SETA (FlagGT_UGT)) -> (MOVBconst [1])
+(SETA (FlagEQ)) -> (MOVLconst [0])
+(SETA (FlagLT_ULT)) -> (MOVLconst [0])
+(SETA (FlagLT_UGT)) -> (MOVLconst [1])
+(SETA (FlagGT_ULT)) -> (MOVLconst [0])
+(SETA (FlagGT_UGT)) -> (MOVLconst [1])
-(SETAE (FlagEQ)) -> (MOVBconst [1])
-(SETAE (FlagLT_ULT)) -> (MOVBconst [0])
-(SETAE (FlagLT_UGT)) -> (MOVBconst [1])
-(SETAE (FlagGT_ULT)) -> (MOVBconst [0])
-(SETAE (FlagGT_UGT)) -> (MOVBconst [1])
+(SETAE (FlagEQ)) -> (MOVLconst [1])
+(SETAE (FlagLT_ULT)) -> (MOVLconst [0])
+(SETAE (FlagLT_UGT)) -> (MOVLconst [1])
+(SETAE (FlagGT_ULT)) -> (MOVLconst [0])
+(SETAE (FlagGT_UGT)) -> (MOVLconst [1])
// Remove redundant *const ops
(ADDQconst [0] x) -> x
(ADDLconst [c] x) && int32(c)==0 -> x
-(ADDWconst [c] x) && int16(c)==0 -> x
-(ADDBconst [c] x) && int8(c)==0 -> x
(SUBQconst [0] x) -> x
(SUBLconst [c] x) && int32(c) == 0 -> x
-(SUBWconst [c] x) && int16(c) == 0 -> x
-(SUBBconst [c] x) && int8(c) == 0 -> x
(ANDQconst [0] _) -> (MOVQconst [0])
(ANDLconst [c] _) && int32(c)==0 -> (MOVLconst [0])
-(ANDWconst [c] _) && int16(c)==0 -> (MOVWconst [0])
-(ANDBconst [c] _) && int8(c)==0 -> (MOVBconst [0])
(ANDQconst [-1] x) -> x
(ANDLconst [c] x) && int32(c)==-1 -> x
-(ANDWconst [c] x) && int16(c)==-1 -> x
-(ANDBconst [c] x) && int8(c)==-1 -> x
(ORQconst [0] x) -> x
(ORLconst [c] x) && int32(c)==0 -> x
-(ORWconst [c] x) && int16(c)==0 -> x
-(ORBconst [c] x) && int8(c)==0 -> x
(ORQconst [-1] _) -> (MOVQconst [-1])
(ORLconst [c] _) && int32(c)==-1 -> (MOVLconst [-1])
-(ORWconst [c] _) && int16(c)==-1 -> (MOVWconst [-1])
-(ORBconst [c] _) && int8(c)==-1 -> (MOVBconst [-1])
(XORQconst [0] x) -> x
(XORLconst [c] x) && int32(c)==0 -> x
-(XORWconst [c] x) && int16(c)==0 -> x
-(XORBconst [c] x) && int8(c)==0 -> x
+// TODO: since we got rid of the W/B versions, we might miss
+// things like (ANDLconst [0x100] x) which were formerly
+// (ANDBconst [0] x). Probably doesn't happen very often.
+// If we cared, we might do:
+// (ANDLconst <t> [c] x) && t.Size()==1 && int8(x)==0 -> (MOVLconst [0])
+
+// Convert constant subtracts to constant adds
+(SUBQconst [c] x) && c != -(1<<31) -> (ADDQconst [-c] x)
+(SUBLconst [c] x) -> (ADDLconst [int64(int32(-c))] x)
// generic constant folding
// TODO: more of this
(ADDQconst [c] (MOVQconst [d])) -> (MOVQconst [c+d])
(ADDLconst [c] (MOVLconst [d])) -> (MOVLconst [int64(int32(c+d))])
-(ADDWconst [c] (MOVWconst [d])) -> (MOVWconst [int64(int16(c+d))])
-(ADDBconst [c] (MOVBconst [d])) -> (MOVBconst [int64(int8(c+d))])
(ADDQconst [c] (ADDQconst [d] x)) && is32Bit(c+d) -> (ADDQconst [c+d] x)
(ADDLconst [c] (ADDLconst [d] x)) -> (ADDLconst [int64(int32(c+d))] x)
-(ADDWconst [c] (ADDWconst [d] x)) -> (ADDWconst [int64(int16(c+d))] x)
-(ADDBconst [c] (ADDBconst [d] x)) -> (ADDBconst [int64(int8(c+d))] x)
(SUBQconst (MOVQconst [d]) [c]) -> (MOVQconst [d-c])
(SUBLconst (MOVLconst [d]) [c]) -> (MOVLconst [int64(int32(d-c))])
-(SUBWconst (MOVWconst [d]) [c]) -> (MOVWconst [int64(int16(d-c))])
-(SUBBconst (MOVBconst [d]) [c]) -> (MOVBconst [int64(int8(d-c))])
(SUBQconst (SUBQconst x [d]) [c]) && is32Bit(-c-d) -> (ADDQconst [-c-d] x)
(SUBLconst (SUBLconst x [d]) [c]) -> (ADDLconst [int64(int32(-c-d))] x)
-(SUBWconst (SUBWconst x [d]) [c]) -> (ADDWconst [int64(int16(-c-d))] x)
-(SUBBconst (SUBBconst x [d]) [c]) -> (ADDBconst [int64(int8(-c-d))] x)
(SARQconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
(SARLconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
(SARWconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
(SARBconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
(NEGQ (MOVQconst [c])) -> (MOVQconst [-c])
(NEGL (MOVLconst [c])) -> (MOVLconst [int64(int32(-c))])
-(NEGW (MOVWconst [c])) -> (MOVWconst [int64(int16(-c))])
-(NEGB (MOVBconst [c])) -> (MOVBconst [int64(int8(-c))])
(MULQconst [c] (MOVQconst [d])) -> (MOVQconst [c*d])
(MULLconst [c] (MOVLconst [d])) -> (MOVLconst [int64(int32(c*d))])
-(MULWconst [c] (MOVWconst [d])) -> (MOVWconst [int64(int16(c*d))])
-(MULBconst [c] (MOVBconst [d])) -> (MOVBconst [int64(int8(c*d))])
(ANDQconst [c] (MOVQconst [d])) -> (MOVQconst [c&d])
(ANDLconst [c] (MOVLconst [d])) -> (MOVLconst [c&d])
-(ANDWconst [c] (MOVWconst [d])) -> (MOVWconst [c&d])
-(ANDBconst [c] (MOVBconst [d])) -> (MOVBconst [c&d])
(ORQconst [c] (MOVQconst [d])) -> (MOVQconst [c|d])
(ORLconst [c] (MOVLconst [d])) -> (MOVLconst [c|d])
-(ORWconst [c] (MOVWconst [d])) -> (MOVWconst [c|d])
-(ORBconst [c] (MOVBconst [d])) -> (MOVBconst [c|d])
(XORQconst [c] (MOVQconst [d])) -> (MOVQconst [c^d])
(XORLconst [c] (MOVLconst [d])) -> (MOVLconst [c^d])
-(XORWconst [c] (MOVWconst [d])) -> (MOVWconst [c^d])
-(XORBconst [c] (MOVBconst [d])) -> (MOVBconst [c^d])
(NOTQ (MOVQconst [c])) -> (MOVQconst [^c])
(NOTL (MOVLconst [c])) -> (MOVLconst [^c])
-(NOTW (MOVWconst [c])) -> (MOVWconst [^c])
-(NOTB (MOVBconst [c])) -> (MOVBconst [^c])
// generic simplifications
// TODO: more of this
(ADDQ x (NEGQ y)) -> (SUBQ x y)
(ADDL x (NEGL y)) -> (SUBL x y)
-(ADDW x (NEGW y)) -> (SUBW x y)
-(ADDB x (NEGB y)) -> (SUBB x y)
(SUBQ x x) -> (MOVQconst [0])
(SUBL x x) -> (MOVLconst [0])
-(SUBW x x) -> (MOVWconst [0])
-(SUBB x x) -> (MOVBconst [0])
(ANDQ x x) -> x
(ANDL x x) -> x
-(ANDW x x) -> x
-(ANDB x x) -> x
(ORQ x x) -> x
(ORL x x) -> x
-(ORW x x) -> x
-(ORB x x) -> x
(XORQ x x) -> (MOVQconst [0])
(XORL x x) -> (MOVLconst [0])
-(XORW x x) -> (MOVWconst [0])
-(XORB x x) -> (MOVBconst [0])
// checking AND against 0.
(CMPQconst (ANDQ x y) [0]) -> (TESTQ x y)
(CMPLconst (ANDL x y) [0]) -> (TESTL x y)
-(CMPWconst (ANDW x y) [0]) -> (TESTW x y)
-(CMPBconst (ANDB x y) [0]) -> (TESTB x y)
+(CMPWconst (ANDL x y) [0]) -> (TESTW x y)
+(CMPBconst (ANDL x y) [0]) -> (TESTB x y)
(CMPQconst (ANDQconst [c] x) [0]) -> (TESTQconst [c] x)
(CMPLconst (ANDLconst [c] x) [0]) -> (TESTLconst [c] x)
-(CMPWconst (ANDWconst [c] x) [0]) -> (TESTWconst [c] x)
-(CMPBconst (ANDBconst [c] x) [0]) -> (TESTBconst [c] x)
+(CMPWconst (ANDLconst [c] x) [0]) -> (TESTWconst [int64(int16(c))] x)
+(CMPBconst (ANDLconst [c] x) [0]) -> (TESTBconst [int64(int8(c))] x)
// TEST %reg,%reg is shorter than CMP
(CMPQconst x [0]) -> (TESTQ x x)
@@ -1352,40 +1265,296 @@
// Combining byte loads into larger (unaligned) loads.
// There are many ways these combinations could occur. This is
// designed to match the way encoding/binary.LittleEndian does it.
-(ORW x0:(MOVBload [i] {s} p mem)
- (SHLWconst [8] x1:(MOVBload [i+1] {s} p mem))) && mergePoint(b,x0,x1) != nil -> @mergePoint(b,x0,x1) (MOVWload [i] {s} p mem)
+(ORL x0:(MOVBload [i] {s} p mem)
+ s0:(SHLLconst [8] x1:(MOVBload [i+1] {s} p mem)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && s0.Uses == 1
+ && mergePoint(b,x0,x1) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(s0)
+ -> @mergePoint(b,x0,x1) (MOVWload [i] {s} p mem)
+
+(ORL o0:(ORL o1:(ORL
+ x0:(MOVBload [i] {s} p mem)
+ s0:(SHLLconst [8] x1:(MOVBload [i+1] {s} p mem)))
+ s1:(SHLLconst [16] x2:(MOVBload [i+2] {s} p mem)))
+ s2:(SHLLconst [24] x3:(MOVBload [i+3] {s} p mem)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && x2.Uses == 1
+ && x3.Uses == 1
+ && s0.Uses == 1
+ && s1.Uses == 1
+ && s2.Uses == 1
+ && o0.Uses == 1
+ && o1.Uses == 1
+ && mergePoint(b,x0,x1,x2,x3) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(x2)
+ && clobber(x3)
+ && clobber(s0)
+ && clobber(s1)
+ && clobber(s2)
+ && clobber(o0)
+ && clobber(o1)
+ -> @mergePoint(b,x0,x1,x2,x3) (MOVLload [i] {s} p mem)
+
+(ORQ o0:(ORQ o1:(ORQ o2:(ORQ o3:(ORQ o4:(ORQ o5:(ORQ
+ x0:(MOVBload [i] {s} p mem)
+ s0:(SHLQconst [8] x1:(MOVBload [i+1] {s} p mem)))
+ s1:(SHLQconst [16] x2:(MOVBload [i+2] {s} p mem)))
+ s2:(SHLQconst [24] x3:(MOVBload [i+3] {s} p mem)))
+ s3:(SHLQconst [32] x4:(MOVBload [i+4] {s} p mem)))
+ s4:(SHLQconst [40] x5:(MOVBload [i+5] {s} p mem)))
+ s5:(SHLQconst [48] x6:(MOVBload [i+6] {s} p mem)))
+ s6:(SHLQconst [56] x7:(MOVBload [i+7] {s} p mem)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && x2.Uses == 1
+ && x3.Uses == 1
+ && x4.Uses == 1
+ && x5.Uses == 1
+ && x6.Uses == 1
+ && x7.Uses == 1
+ && s0.Uses == 1
+ && s1.Uses == 1
+ && s2.Uses == 1
+ && s3.Uses == 1
+ && s4.Uses == 1
+ && s5.Uses == 1
+ && s6.Uses == 1
+ && o0.Uses == 1
+ && o1.Uses == 1
+ && o2.Uses == 1
+ && o3.Uses == 1
+ && o4.Uses == 1
+ && o5.Uses == 1
+ && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(x2)
+ && clobber(x3)
+ && clobber(x4)
+ && clobber(x5)
+ && clobber(x6)
+ && clobber(x7)
+ && clobber(s0)
+ && clobber(s1)
+ && clobber(s2)
+ && clobber(s3)
+ && clobber(s4)
+ && clobber(s5)
+ && clobber(s6)
+ && clobber(o0)
+ && clobber(o1)
+ && clobber(o2)
+ && clobber(o3)
+ && clobber(o4)
+ && clobber(o5)
+ -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVQload [i] {s} p mem)
+
+(ORL x0:(MOVBloadidx1 [i] {s} p idx mem)
+ s0:(SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && s0.Uses == 1
+ && mergePoint(b,x0,x1) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(s0)
+ -> @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i] {s} p idx mem)
+
+(ORL o0:(ORL o1:(ORL
+ x0:(MOVBloadidx1 [i] {s} p idx mem)
+ s0:(SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
+ s1:(SHLLconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem)))
+ s2:(SHLLconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && x2.Uses == 1
+ && x3.Uses == 1
+ && s0.Uses == 1
+ && s1.Uses == 1
+ && s2.Uses == 1
+ && o0.Uses == 1
+ && o1.Uses == 1
+ && mergePoint(b,x0,x1,x2,x3) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(x2)
+ && clobber(x3)
+ && clobber(s0)
+ && clobber(s1)
+ && clobber(s2)
+ && clobber(o0)
+ && clobber(o1)
+ -> @mergePoint(b,x0,x1,x2,x3) (MOVLloadidx1 <v.Type> [i] {s} p idx mem)
+
+(ORQ o0:(ORQ o1:(ORQ o2:(ORQ o3:(ORQ o4:(ORQ o5:(ORQ
+ x0:(MOVBloadidx1 [i] {s} p idx mem)
+ s0:(SHLQconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
+ s1:(SHLQconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem)))
+ s2:(SHLQconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem)))
+ s3:(SHLQconst [32] x4:(MOVBloadidx1 [i+4] {s} p idx mem)))
+ s4:(SHLQconst [40] x5:(MOVBloadidx1 [i+5] {s} p idx mem)))
+ s5:(SHLQconst [48] x6:(MOVBloadidx1 [i+6] {s} p idx mem)))
+ s6:(SHLQconst [56] x7:(MOVBloadidx1 [i+7] {s} p idx mem)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && x2.Uses == 1
+ && x3.Uses == 1
+ && x4.Uses == 1
+ && x5.Uses == 1
+ && x6.Uses == 1
+ && x7.Uses == 1
+ && s0.Uses == 1
+ && s1.Uses == 1
+ && s2.Uses == 1
+ && s3.Uses == 1
+ && s4.Uses == 1
+ && s5.Uses == 1
+ && s6.Uses == 1
+ && o0.Uses == 1
+ && o1.Uses == 1
+ && o2.Uses == 1
+ && o3.Uses == 1
+ && o4.Uses == 1
+ && o5.Uses == 1
+ && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(x2)
+ && clobber(x3)
+ && clobber(x4)
+ && clobber(x5)
+ && clobber(x6)
+ && clobber(x7)
+ && clobber(s0)
+ && clobber(s1)
+ && clobber(s2)
+ && clobber(s3)
+ && clobber(s4)
+ && clobber(s5)
+ && clobber(s6)
+ && clobber(o0)
+ && clobber(o1)
+ && clobber(o2)
+ && clobber(o3)
+ && clobber(o4)
+ && clobber(o5)
+ -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVQloadidx1 <v.Type> [i] {s} p idx mem)
+
+// Combine constant stores into larger (unaligned) stores.
+(MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
+(MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem)
+(MOVLstoreconst [c] {s} p x:(MOVLstoreconst [a] {s} p mem))
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVQstore [ValAndOff(a).Off()] {s} p (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
-(ORL (ORL (ORL
- x0:(MOVBload [i] {s} p mem)
- (SHLLconst [8] x1:(MOVBload [i+1] {s} p mem)))
- (SHLLconst [16] x2:(MOVBload [i+2] {s} p mem)))
- (SHLLconst [24] x3:(MOVBload [i+3] {s} p mem))) && mergePoint(b,x0,x1,x2,x3) != nil -> @mergePoint(b,x0,x1,x2,x3) (MOVLload [i] {s} p mem)
+(MOVBstoreconstidx1 [c] {s} p i x:(MOVBstoreconstidx1 [a] {s} p i mem))
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVWstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p i mem)
+(MOVWstoreconstidx1 [c] {s} p i x:(MOVWstoreconstidx1 [a] {s} p i mem))
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p i mem)
+(MOVLstoreconstidx1 [c] {s} p i x:(MOVLstoreconstidx1 [a] {s} p i mem))
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVQstoreidx1 [ValAndOff(a).Off()] {s} p i (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
-(ORQ (ORQ (ORQ (ORQ (ORQ (ORQ (ORQ
- x0:(MOVBload [i] {s} p mem)
- (SHLQconst [8] x1:(MOVBload [i+1] {s} p mem)))
- (SHLQconst [16] x2:(MOVBload [i+2] {s} p mem)))
- (SHLQconst [24] x3:(MOVBload [i+3] {s} p mem)))
- (SHLQconst [32] x4:(MOVBload [i+4] {s} p mem)))
- (SHLQconst [40] x5:(MOVBload [i+5] {s} p mem)))
- (SHLQconst [48] x6:(MOVBload [i+6] {s} p mem)))
- (SHLQconst [56] x7:(MOVBload [i+7] {s} p mem))) && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVQload [i] {s} p mem)
+(MOVWstoreconstidx2 [c] {s} p i x:(MOVWstoreconstidx2 [a] {s} p i mem))
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p (SHLQconst <i.Type> [1] i) mem)
+(MOVLstoreconstidx4 [c] {s} p i x:(MOVLstoreconstidx4 [a] {s} p i mem))
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVQstoreidx1 [ValAndOff(a).Off()] {s} p (SHLQconst <i.Type> [2] i) (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
-(ORW x0:(MOVBloadidx1 [i] {s} p idx mem)
- (SHLWconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem))) && mergePoint(b,x0,x1) != nil -> @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i] {s} p idx mem)
+// Combine stores into larger (unaligned) stores.
+(MOVBstore [i] {s} p (SHRQconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstore [i-1] {s} p w mem)
+(MOVBstore [i] {s} p (SHRQconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SHRQconst [j-8] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstore [i-1] {s} p w0 mem)
+(MOVWstore [i] {s} p (SHRQconst [16] w) x:(MOVWstore [i-2] {s} p w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVLstore [i-2] {s} p w mem)
+(MOVWstore [i] {s} p (SHRQconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRQconst [j-16] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVLstore [i-2] {s} p w0 mem)
+(MOVLstore [i] {s} p (SHRQconst [32] w) x:(MOVLstore [i-4] {s} p w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVQstore [i-4] {s} p w mem)
+(MOVLstore [i] {s} p (SHRQconst [j] w) x:(MOVLstore [i-4] {s} p w0:(SHRQconst [j-32] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVQstore [i-4] {s} p w0 mem)
-(ORL (ORL (ORL
- x0:(MOVBloadidx1 [i] {s} p idx mem)
- (SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
- (SHLLconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem)))
- (SHLLconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem))) && mergePoint(b,x0,x1,x2,x3) != nil -> @mergePoint(b,x0,x1,x2,x3) (MOVLloadidx1 <v.Type> [i] {s} p idx mem)
+(MOVBstoreidx1 [i] {s} p idx (SHRQconst [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstoreidx1 [i-1] {s} p idx w mem)
+(MOVBstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRQconst [j-8] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
+(MOVWstoreidx1 [i] {s} p idx (SHRQconst [16] w) x:(MOVWstoreidx1 [i-2] {s} p idx w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVLstoreidx1 [i-2] {s} p idx w mem)
+(MOVWstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVWstoreidx1 [i-2] {s} p idx w0:(SHRQconst [j-16] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVLstoreidx1 [i-2] {s} p idx w0 mem)
+(MOVLstoreidx1 [i] {s} p idx (SHRQconst [32] w) x:(MOVLstoreidx1 [i-4] {s} p idx w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVQstoreidx1 [i-4] {s} p idx w mem)
+(MOVLstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVLstoreidx1 [i-4] {s} p idx w0:(SHRQconst [j-32] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVQstoreidx1 [i-4] {s} p idx w0 mem)
-(ORQ (ORQ (ORQ (ORQ (ORQ (ORQ (ORQ
- x0:(MOVBloadidx1 [i] {s} p idx mem)
- (SHLQconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
- (SHLQconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem)))
- (SHLQconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem)))
- (SHLQconst [32] x4:(MOVBloadidx1 [i+4] {s} p idx mem)))
- (SHLQconst [40] x5:(MOVBloadidx1 [i+5] {s} p idx mem)))
- (SHLQconst [48] x6:(MOVBloadidx1 [i+6] {s} p idx mem)))
- (SHLQconst [56] x7:(MOVBloadidx1 [i+7] {s} p idx mem))) && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVQloadidx1 <v.Type> [i] {s} p idx mem)
+(MOVWstoreidx2 [i] {s} p idx (SHRQconst [16] w) x:(MOVWstoreidx2 [i-2] {s} p idx w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVLstoreidx1 [i-2] {s} p (SHLQconst <idx.Type> [1] idx) w mem)
+(MOVWstoreidx2 [i] {s} p idx (SHRQconst [j] w) x:(MOVWstoreidx2 [i-2] {s} p idx w0:(SHRQconst [j-16] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVLstoreidx1 [i-2] {s} p (SHLQconst <idx.Type> [1] idx) w0 mem)
+(MOVLstoreidx4 [i] {s} p idx (SHRQconst [32] w) x:(MOVLstoreidx4 [i-4] {s} p idx w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVQstoreidx1 [i-4] {s} p (SHLQconst <idx.Type> [2] idx) w mem)
+(MOVLstoreidx4 [i] {s} p idx (SHRQconst [j] w) x:(MOVLstoreidx4 [i-4] {s} p idx w0:(SHRQconst [j-32] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVQstoreidx1 [i-4] {s} p (SHLQconst <idx.Type> [2] idx) w0 mem)
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
index b1698c0cf1..b684b9ccdf 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
@@ -111,12 +111,14 @@ func init() {
// Common regInfo
var (
gp01 = regInfo{inputs: []regMask{}, outputs: gponly}
- gp11 = regInfo{inputs: []regMask{gpsp}, outputs: gponly, clobbers: flags}
+ gp11 = regInfo{inputs: []regMask{gp}, outputs: gponly, clobbers: flags}
+ gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly, clobbers: flags}
gp11nf = regInfo{inputs: []regMask{gpsp}, outputs: gponly} // nf: no flags clobbered
gp11sb = regInfo{inputs: []regMask{gpspsb}, outputs: gponly}
- gp21 = regInfo{inputs: []regMask{gpsp, gpsp}, outputs: gponly, clobbers: flags}
+ gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly, clobbers: flags}
+ gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly, clobbers: flags}
gp21sb = regInfo{inputs: []regMask{gpspsb, gpsp}, outputs: gponly}
- gp21shift = regInfo{inputs: []regMask{gpsp, cx}, outputs: []regMask{gp &^ cx}, clobbers: flags}
+ gp21shift = regInfo{inputs: []regMask{gp, cx}, outputs: []regMask{gp}, clobbers: flags}
gp11div = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{ax},
clobbers: dx | flags}
gp11hmul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx},
@@ -128,8 +130,8 @@ func init() {
gp1flags = regInfo{inputs: []regMask{gpsp}, outputs: flagsonly}
flagsgp = regInfo{inputs: flagsonly, outputs: gponly}
- // for CMOVconst -- uses AX to hold constant temporary. AX input is moved before temp.
- gp1flagsgp = regInfo{inputs: []regMask{gp, flags}, clobbers: ax | flags, outputs: []regMask{gp &^ ax}}
+ // for CMOVconst -- uses AX to hold constant temporary.
+ gp1flagsgp = regInfo{inputs: []regMask{gp &^ ax, flags}, clobbers: ax | flags, outputs: []regMask{gp &^ ax}}
readflags = regInfo{inputs: flagsonly, outputs: gponly}
flagsgpax = regInfo{inputs: flagsonly, clobbers: ax | flags, outputs: []regMask{gp &^ ax}}
@@ -186,32 +188,20 @@ func init() {
{name: "MOVSDstoreidx8", argLength: 4, reg: fpstoreidx, asm: "MOVSD", aux: "SymOff"}, // fp64 indexed by 8i store
// binary ops
- {name: "ADDQ", argLength: 2, reg: gp21, asm: "ADDQ", commutative: true, resultInArg0: true}, // arg0 + arg1
- {name: "ADDL", argLength: 2, reg: gp21, asm: "ADDL", commutative: true, resultInArg0: true}, // arg0 + arg1
- {name: "ADDW", argLength: 2, reg: gp21, asm: "ADDL", commutative: true, resultInArg0: true}, // arg0 + arg1
- {name: "ADDB", argLength: 2, reg: gp21, asm: "ADDL", commutative: true, resultInArg0: true}, // arg0 + arg1
- {name: "ADDQconst", argLength: 1, reg: gp11, asm: "ADDQ", aux: "Int64", resultInArg0: true, typ: "UInt64"}, // arg0 + auxint
- {name: "ADDLconst", argLength: 1, reg: gp11, asm: "ADDL", aux: "Int32", resultInArg0: true}, // arg0 + auxint
- {name: "ADDWconst", argLength: 1, reg: gp11, asm: "ADDL", aux: "Int16", resultInArg0: true}, // arg0 + auxint
- {name: "ADDBconst", argLength: 1, reg: gp11, asm: "ADDL", aux: "Int8", resultInArg0: true}, // arg0 + auxint
+ {name: "ADDQ", argLength: 2, reg: gp21sp, asm: "ADDQ", commutative: true}, // arg0 + arg1
+ {name: "ADDL", argLength: 2, reg: gp21sp, asm: "ADDL", commutative: true}, // arg0 + arg1
+ {name: "ADDQconst", argLength: 1, reg: gp11sp, asm: "ADDQ", aux: "Int64", typ: "UInt64"}, // arg0 + auxint
+ {name: "ADDLconst", argLength: 1, reg: gp11sp, asm: "ADDL", aux: "Int32"}, // arg0 + auxint
{name: "SUBQ", argLength: 2, reg: gp21, asm: "SUBQ", resultInArg0: true}, // arg0 - arg1
{name: "SUBL", argLength: 2, reg: gp21, asm: "SUBL", resultInArg0: true}, // arg0 - arg1
- {name: "SUBW", argLength: 2, reg: gp21, asm: "SUBL", resultInArg0: true}, // arg0 - arg1
- {name: "SUBB", argLength: 2, reg: gp21, asm: "SUBL", resultInArg0: true}, // arg0 - arg1
{name: "SUBQconst", argLength: 1, reg: gp11, asm: "SUBQ", aux: "Int64", resultInArg0: true}, // arg0 - auxint
{name: "SUBLconst", argLength: 1, reg: gp11, asm: "SUBL", aux: "Int32", resultInArg0: true}, // arg0 - auxint
- {name: "SUBWconst", argLength: 1, reg: gp11, asm: "SUBL", aux: "Int16", resultInArg0: true}, // arg0 - auxint
- {name: "SUBBconst", argLength: 1, reg: gp11, asm: "SUBL", aux: "Int8", resultInArg0: true}, // arg0 - auxint
{name: "MULQ", argLength: 2, reg: gp21, asm: "IMULQ", commutative: true, resultInArg0: true}, // arg0 * arg1
{name: "MULL", argLength: 2, reg: gp21, asm: "IMULL", commutative: true, resultInArg0: true}, // arg0 * arg1
- {name: "MULW", argLength: 2, reg: gp21, asm: "IMULW", commutative: true, resultInArg0: true}, // arg0 * arg1
- {name: "MULB", argLength: 2, reg: gp21, asm: "IMULW", commutative: true, resultInArg0: true}, // arg0 * arg1
{name: "MULQconst", argLength: 1, reg: gp11, asm: "IMULQ", aux: "Int64", resultInArg0: true}, // arg0 * auxint
{name: "MULLconst", argLength: 1, reg: gp11, asm: "IMULL", aux: "Int32", resultInArg0: true}, // arg0 * auxint
- {name: "MULWconst", argLength: 1, reg: gp11, asm: "IMULW", aux: "Int16", resultInArg0: true}, // arg0 * auxint
- {name: "MULBconst", argLength: 1, reg: gp11, asm: "IMULW", aux: "Int8", resultInArg0: true}, // arg0 * auxint
{name: "HMULQ", argLength: 2, reg: gp11hmul, asm: "IMULQ"}, // (arg0 * arg1) >> width
{name: "HMULL", argLength: 2, reg: gp11hmul, asm: "IMULL"}, // (arg0 * arg1) >> width
@@ -240,30 +230,18 @@ func init() {
{name: "ANDQ", argLength: 2, reg: gp21, asm: "ANDQ", commutative: true, resultInArg0: true}, // arg0 & arg1
{name: "ANDL", argLength: 2, reg: gp21, asm: "ANDL", commutative: true, resultInArg0: true}, // arg0 & arg1
- {name: "ANDW", argLength: 2, reg: gp21, asm: "ANDL", commutative: true, resultInArg0: true}, // arg0 & arg1
- {name: "ANDB", argLength: 2, reg: gp21, asm: "ANDL", commutative: true, resultInArg0: true}, // arg0 & arg1
{name: "ANDQconst", argLength: 1, reg: gp11, asm: "ANDQ", aux: "Int64", resultInArg0: true}, // arg0 & auxint
{name: "ANDLconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int32", resultInArg0: true}, // arg0 & auxint
- {name: "ANDWconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int16", resultInArg0: true}, // arg0 & auxint
- {name: "ANDBconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int8", resultInArg0: true}, // arg0 & auxint
{name: "ORQ", argLength: 2, reg: gp21, asm: "ORQ", commutative: true, resultInArg0: true}, // arg0 | arg1
{name: "ORL", argLength: 2, reg: gp21, asm: "ORL", commutative: true, resultInArg0: true}, // arg0 | arg1
- {name: "ORW", argLength: 2, reg: gp21, asm: "ORL", commutative: true, resultInArg0: true}, // arg0 | arg1
- {name: "ORB", argLength: 2, reg: gp21, asm: "ORL", commutative: true, resultInArg0: true}, // arg0 | arg1
{name: "ORQconst", argLength: 1, reg: gp11, asm: "ORQ", aux: "Int64", resultInArg0: true}, // arg0 | auxint
{name: "ORLconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int32", resultInArg0: true}, // arg0 | auxint
- {name: "ORWconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int16", resultInArg0: true}, // arg0 | auxint
- {name: "ORBconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int8", resultInArg0: true}, // arg0 | auxint
{name: "XORQ", argLength: 2, reg: gp21, asm: "XORQ", commutative: true, resultInArg0: true}, // arg0 ^ arg1
{name: "XORL", argLength: 2, reg: gp21, asm: "XORL", commutative: true, resultInArg0: true}, // arg0 ^ arg1
- {name: "XORW", argLength: 2, reg: gp21, asm: "XORL", commutative: true, resultInArg0: true}, // arg0 ^ arg1
- {name: "XORB", argLength: 2, reg: gp21, asm: "XORL", commutative: true, resultInArg0: true}, // arg0 ^ arg1
{name: "XORQconst", argLength: 1, reg: gp11, asm: "XORQ", aux: "Int64", resultInArg0: true}, // arg0 ^ auxint
{name: "XORLconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int32", resultInArg0: true}, // arg0 ^ auxint
- {name: "XORWconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int16", resultInArg0: true}, // arg0 ^ auxint
- {name: "XORBconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int8", resultInArg0: true}, // arg0 ^ auxint
{name: "CMPQ", argLength: 2, reg: gp2flags, asm: "CMPQ", typ: "Flags"}, // arg0 compare to arg1
{name: "CMPL", argLength: 2, reg: gp2flags, asm: "CMPL", typ: "Flags"}, // arg0 compare to arg1
@@ -288,12 +266,8 @@ func init() {
{name: "SHLQ", argLength: 2, reg: gp21shift, asm: "SHLQ", resultInArg0: true}, // arg0 << arg1, shift amount is mod 64
{name: "SHLL", argLength: 2, reg: gp21shift, asm: "SHLL", resultInArg0: true}, // arg0 << arg1, shift amount is mod 32
- {name: "SHLW", argLength: 2, reg: gp21shift, asm: "SHLL", resultInArg0: true}, // arg0 << arg1, shift amount is mod 32
- {name: "SHLB", argLength: 2, reg: gp21shift, asm: "SHLL", resultInArg0: true}, // arg0 << arg1, shift amount is mod 32
{name: "SHLQconst", argLength: 1, reg: gp11, asm: "SHLQ", aux: "Int64", resultInArg0: true}, // arg0 << auxint, shift amount 0-63
{name: "SHLLconst", argLength: 1, reg: gp11, asm: "SHLL", aux: "Int32", resultInArg0: true}, // arg0 << auxint, shift amount 0-31
- {name: "SHLWconst", argLength: 1, reg: gp11, asm: "SHLL", aux: "Int16", resultInArg0: true}, // arg0 << auxint, shift amount 0-31
- {name: "SHLBconst", argLength: 1, reg: gp11, asm: "SHLL", aux: "Int8", resultInArg0: true}, // arg0 << auxint, shift amount 0-31
// Note: x86 is weird, the 16 and 8 byte shifts still use all 5 bits of shift amount!
{name: "SHRQ", argLength: 2, reg: gp21shift, asm: "SHRQ", resultInArg0: true}, // unsigned arg0 >> arg1, shift amount is mod 64
@@ -322,13 +296,9 @@ func init() {
// unary ops
{name: "NEGQ", argLength: 1, reg: gp11, asm: "NEGQ", resultInArg0: true}, // -arg0
{name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true}, // -arg0
- {name: "NEGW", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true}, // -arg0
- {name: "NEGB", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true}, // -arg0
{name: "NOTQ", argLength: 1, reg: gp11, asm: "NOTQ", resultInArg0: true}, // ^arg0
{name: "NOTL", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true}, // ^arg0
- {name: "NOTW", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true}, // ^arg0
- {name: "NOTB", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true}, // ^arg0
{name: "BSFQ", argLength: 1, reg: gp11, asm: "BSFQ"}, // arg0 # of low-order zeroes ; undef if zero
{name: "BSFL", argLength: 1, reg: gp11, asm: "BSFL"}, // arg0 # of low-order zeroes ; undef if zero
@@ -383,8 +353,6 @@ func init() {
{name: "MOVLQSX", argLength: 1, reg: gp11nf, asm: "MOVLQSX"}, // sign extend arg0 from int32 to int64
{name: "MOVLQZX", argLength: 1, reg: gp11nf, asm: "MOVLQZX"}, // zero extend arg0 from int32 to int64
- {name: "MOVBconst", reg: gp01, asm: "MOVB", typ: "UInt8", aux: "Int8", rematerializeable: true}, // 8 low bits of auxint
- {name: "MOVWconst", reg: gp01, asm: "MOVW", typ: "UInt16", aux: "Int16", rematerializeable: true}, // 16 low bits of auxint
{name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32", aux: "Int32", rematerializeable: true}, // 32 low bits of auxint
{name: "MOVQconst", reg: gp01, asm: "MOVQ", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint
@@ -471,7 +439,7 @@ func init() {
clobbers: buildReg("DI FLAGS"),
},
},
- {name: "MOVOconst", reg: regInfo{nil, 0, []regMask{fp}}, typ: "Int128", rematerializeable: true},
+ {name: "MOVOconst", reg: regInfo{nil, 0, []regMask{fp}}, typ: "Int128", aux: "Int128", rematerializeable: true},
// arg0 = address of memory to zero
// arg1 = # of 8-byte words to zero
diff --git a/src/cmd/compile/internal/ssa/gen/ARMOps.go b/src/cmd/compile/internal/ssa/gen/ARMOps.go
index a4f7b17e87..23e8f63471 100644
--- a/src/cmd/compile/internal/ssa/gen/ARMOps.go
+++ b/src/cmd/compile/internal/ssa/gen/ARMOps.go
@@ -25,13 +25,13 @@ func init() {
{name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1
- {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW"}, // load from arg0 + auxInt + aux. arg1=mem.
- {name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
+ {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW"}, // load from arg0 + auxInt + aux. arg1=mem.
+ {name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff"}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
// pseudo-ops
- {name: "LessThan", argLength: 2, reg: flagsgp}, // bool, 1 flags encode x<y 0 otherwise.
+ {name: "LessThan", argLength: 1, reg: flagsgp}, // bool, 1 flags encode x<y 0 otherwise.
}
blocks := []blockData{
diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules
index b56e3f1b2d..b33037f100 100644
--- a/src/cmd/compile/internal/ssa/gen/generic.rules
+++ b/src/cmd/compile/internal/ssa/gen/generic.rules
@@ -81,13 +81,13 @@
(Rsh64Ux64 (Const64 [c]) (Const64 [d])) -> (Const64 [int64(uint64(c) >> uint64(d))])
(Lsh32x64 (Const32 [c]) (Const64 [d])) -> (Const32 [int64(int32(c) << uint64(d))])
(Rsh32x64 (Const32 [c]) (Const64 [d])) -> (Const32 [int64(int32(c) >> uint64(d))])
-(Rsh32Ux64 (Const32 [c]) (Const64 [d])) -> (Const32 [int64(uint32(c) >> uint64(d))])
+(Rsh32Ux64 (Const32 [c]) (Const64 [d])) -> (Const32 [int64(int32(uint32(c) >> uint64(d)))])
(Lsh16x64 (Const16 [c]) (Const64 [d])) -> (Const16 [int64(int16(c) << uint64(d))])
(Rsh16x64 (Const16 [c]) (Const64 [d])) -> (Const16 [int64(int16(c) >> uint64(d))])
-(Rsh16Ux64 (Const16 [c]) (Const64 [d])) -> (Const16 [int64(uint16(c) >> uint64(d))])
+(Rsh16Ux64 (Const16 [c]) (Const64 [d])) -> (Const16 [int64(int16(uint16(c) >> uint64(d)))])
(Lsh8x64 (Const8 [c]) (Const64 [d])) -> (Const8 [int64(int8(c) << uint64(d))])
(Rsh8x64 (Const8 [c]) (Const64 [d])) -> (Const8 [int64(int8(c) >> uint64(d))])
-(Rsh8Ux64 (Const8 [c]) (Const64 [d])) -> (Const8 [int64(uint8(c) >> uint64(d))])
+(Rsh8Ux64 (Const8 [c]) (Const64 [d])) -> (Const8 [int64(int8(uint8(c) >> uint64(d)))])
(Lsh64x64 (Const64 [0]) _) -> (Const64 [0])
(Rsh64x64 (Const64 [0]) _) -> (Const64 [0])
@@ -114,7 +114,7 @@
(Lsh16x16 (Rsh16Ux16 (Lsh16x16 x (Const16 [c1])) (Const16 [c2])) (Const16 [c3])) && uint16(c1) >= uint16(c2) && uint16(c3) >= uint16(c2) -> (Lsh16x16 x (Const16 <config.fe.TypeUInt16()> [int64(int16(c1-c2+c3))]))
(Lsh8x8 (Rsh8Ux8 (Lsh8x8 x (Const8 [c1])) (Const8 [c2])) (Const8 [c3])) && uint8(c1) >= uint8(c2) && uint8(c3) >= uint8(c2) -> (Lsh8x8 x (Const8 <config.fe.TypeUInt8()> [int64(int8(c1-c2+c3))]))
-// Fold IsInBounds when the range of the index cannot exceed the limt.
+// Fold IsInBounds when the range of the index cannot exceed the limit.
(IsInBounds (ZeroExt8to32 _) (Const32 [c])) && (1 << 8) <= c -> (ConstBool [1])
(IsInBounds (ZeroExt8to64 _) (Const64 [c])) && (1 << 8) <= c -> (ConstBool [1])
(IsInBounds (ZeroExt16to32 _) (Const32 [c])) && (1 << 16) <= c -> (ConstBool [1])
@@ -141,17 +141,17 @@
(Eq32 x x) -> (ConstBool [1])
(Eq16 x x) -> (ConstBool [1])
(Eq8 x x) -> (ConstBool [1])
-(Eq8 (ConstBool [c]) (ConstBool [d])) -> (ConstBool [b2i(c == d)])
-(Eq8 (ConstBool [0]) x) -> (Not x)
-(Eq8 (ConstBool [1]) x) -> x
+(EqB (ConstBool [c]) (ConstBool [d])) -> (ConstBool [b2i(c == d)])
+(EqB (ConstBool [0]) x) -> (Not x)
+(EqB (ConstBool [1]) x) -> x
(Neq64 x x) -> (ConstBool [0])
(Neq32 x x) -> (ConstBool [0])
(Neq16 x x) -> (ConstBool [0])
(Neq8 x x) -> (ConstBool [0])
-(Neq8 (ConstBool [c]) (ConstBool [d])) -> (ConstBool [b2i(c != d)])
-(Neq8 (ConstBool [0]) x) -> x
-(Neq8 (ConstBool [1]) x) -> (Not x)
+(NeqB (ConstBool [c]) (ConstBool [d])) -> (ConstBool [b2i(c != d)])
+(NeqB (ConstBool [0]) x) -> x
+(NeqB (ConstBool [1]) x) -> (Not x)
(Eq64 (Const64 <t> [c]) (Add64 (Const64 <t> [d]) x)) -> (Eq64 (Const64 <t> [c-d]) x)
(Eq32 (Const32 <t> [c]) (Add32 (Const32 <t> [d]) x)) -> (Eq32 (Const32 <t> [int64(int32(c-d))]) x)
@@ -168,13 +168,11 @@
(Eq32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Eq32 (Const32 <t> [c]) x)
(Eq16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Eq16 (Const16 <t> [c]) x)
(Eq8 x (Const8 <t> [c])) && x.Op != OpConst8 -> (Eq8 (Const8 <t> [c]) x)
-(Eq8 x (ConstBool <t> [c])) && x.Op != OpConstBool -> (Eq8 (ConstBool <t> [c]) x)
(Neq64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Neq64 (Const64 <t> [c]) x)
(Neq32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Neq32 (Const32 <t> [c]) x)
(Neq16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Neq16 (Const16 <t> [c]) x)
(Neq8 x (Const8 <t> [c])) && x.Op != OpConst8 -> (Neq8 (Const8 <t> [c]) x)
-(Neq8 x (ConstBool <t> [c])) && x.Op != OpConstBool -> (Neq8 (ConstBool <t> [c]) x)
// AddPtr is not canonicalized because nilcheck ptr checks the first argument to be non-nil.
(Add64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Add64 (Const64 <t> [c]) x)
@@ -414,6 +412,55 @@
(Neg32 (Sub32 x y)) -> (Sub32 y x)
(Neg64 (Sub64 x y)) -> (Sub64 y x)
+(And64 x (And64 x y)) -> (And64 x y)
+(And32 x (And32 x y)) -> (And32 x y)
+(And16 x (And16 x y)) -> (And16 x y)
+(And8 x (And8 x y)) -> (And8 x y)
+(And64 x (And64 y x)) -> (And64 x y)
+(And32 x (And32 y x)) -> (And32 x y)
+(And16 x (And16 y x)) -> (And16 x y)
+(And8 x (And8 y x)) -> (And8 x y)
+(And64 (And64 x y) x) -> (And64 x y)
+(And32 (And32 x y) x) -> (And32 x y)
+(And16 (And16 x y) x) -> (And16 x y)
+(And8 (And8 x y) x) -> (And8 x y)
+(And64 (And64 x y) y) -> (And64 x y)
+(And32 (And32 x y) y) -> (And32 x y)
+(And16 (And16 x y) y) -> (And16 x y)
+(And8 (And8 x y) y) -> (And8 x y)
+(Or64 x (Or64 x y)) -> (Or64 x y)
+(Or32 x (Or32 x y)) -> (Or32 x y)
+(Or16 x (Or16 x y)) -> (Or16 x y)
+(Or8 x (Or8 x y)) -> (Or8 x y)
+(Or64 x (Or64 y x)) -> (Or64 x y)
+(Or32 x (Or32 y x)) -> (Or32 x y)
+(Or16 x (Or16 y x)) -> (Or16 x y)
+(Or8 x (Or8 y x)) -> (Or8 x y)
+(Or64 (Or64 x y) x) -> (Or64 x y)
+(Or32 (Or32 x y) x) -> (Or32 x y)
+(Or16 (Or16 x y) x) -> (Or16 x y)
+(Or8 (Or8 x y) x) -> (Or8 x y)
+(Or64 (Or64 x y) y) -> (Or64 x y)
+(Or32 (Or32 x y) y) -> (Or32 x y)
+(Or16 (Or16 x y) y) -> (Or16 x y)
+(Or8 (Or8 x y) y) -> (Or8 x y)
+(Xor64 x (Xor64 x y)) -> y
+(Xor32 x (Xor32 x y)) -> y
+(Xor16 x (Xor16 x y)) -> y
+(Xor8 x (Xor8 x y)) -> y
+(Xor64 x (Xor64 y x)) -> y
+(Xor32 x (Xor32 y x)) -> y
+(Xor16 x (Xor16 y x)) -> y
+(Xor8 x (Xor8 y x)) -> y
+(Xor64 (Xor64 x y) x) -> y
+(Xor32 (Xor32 x y) x) -> y
+(Xor16 (Xor16 x y) x) -> y
+(Xor8 (Xor8 x y) x) -> y
+(Xor64 (Xor64 x y) y) -> x
+(Xor32 (Xor32 x y) y) -> x
+(Xor16 (Xor16 x y) y) -> x
+(Xor8 (Xor8 x y) y) -> x
+
(Trunc64to8 (And64 (Const64 [y]) x)) && y&0xFF == 0xFF -> (Trunc64to8 x)
(Trunc64to16 (And64 (Const64 [y]) x)) && y&0xFFFF == 0xFFFF -> (Trunc64to16 x)
(Trunc64to32 (And64 (Const64 [y]) x)) && y&0xFFFFFFFF == 0xFFFFFFFF -> (Trunc64to32 x)
diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go
index e6a0e8355b..88ae8b189d 100644
--- a/src/cmd/compile/internal/ssa/gen/genericOps.go
+++ b/src/cmd/compile/internal/ssa/gen/genericOps.go
@@ -237,9 +237,14 @@ var genericOps = []opData{
{name: "Geq32F", argLength: 2},
{name: "Geq64F", argLength: 2},
- // 1-input ops
- {name: "Not", argLength: 1}, // !arg0, boolean
+ // boolean ops
+ {name: "AndB", argLength: 2}, // arg0 && arg1 (not shortcircuited)
+ {name: "OrB", argLength: 2}, // arg0 || arg1 (not shortcircuited)
+ {name: "EqB", argLength: 2}, // arg0 == arg1
+ {name: "NeqB", argLength: 2}, // arg0 != arg1
+ {name: "Not", argLength: 1}, // !arg0, boolean
+ // 1-input ops
{name: "Neg8", argLength: 1}, // -arg0
{name: "Neg16", argLength: 1},
{name: "Neg32", argLength: 1},
diff --git a/src/cmd/compile/internal/ssa/gen/main.go b/src/cmd/compile/internal/ssa/gen/main.go
index db3c43d3a3..2aec4a324b 100644
--- a/src/cmd/compile/internal/ssa/gen/main.go
+++ b/src/cmd/compile/internal/ssa/gen/main.go
@@ -39,7 +39,7 @@ type opData struct {
rematerializeable bool
argLength int32 // number of arguments, if -1, then this operation has a variable number of arguments
commutative bool // this operation is commutative (e.g. addition)
- resultInArg0 bool // prefer v and v.Args[0] to be allocated to the same register
+ resultInArg0 bool // v and v.Args[0] must be allocated to the same register
}
type blockData struct {
@@ -155,6 +155,12 @@ func genOp() {
}
if v.resultInArg0 {
fmt.Fprintln(w, "resultInArg0: true,")
+ if v.reg.inputs[0] != v.reg.outputs[0] {
+ log.Fatalf("input[0] and output registers must be equal for %s", v.name)
+ }
+ if v.commutative && v.reg.inputs[1] != v.reg.outputs[0] {
+ log.Fatalf("input[1] and output registers must be equal for %s", v.name)
+ }
}
if a.name == "generic" {
fmt.Fprintln(w, "generic:true,")
diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go
index b40f480f3e..5f7d1cf984 100644
--- a/src/cmd/compile/internal/ssa/gen/rulegen.go
+++ b/src/cmd/compile/internal/ssa/gen/rulegen.go
@@ -52,12 +52,12 @@ var (
)
type Rule struct {
- rule string
- lineno int
+ rule string
+ loc string // file name & line number
}
func (r Rule) String() string {
- return fmt.Sprintf("rule %q at line %d", r.rule, r.lineno)
+ return fmt.Sprintf("rule %q at %s", r.rule, r.loc)
}
// parse returns the matching part of the rule, additional conditions, and the result.
@@ -91,6 +91,7 @@ func genRules(arch arch) {
scanner := bufio.NewScanner(text)
rule := ""
var lineno int
+ var ruleLineno int // line number of "->"
for scanner.Scan() {
lineno++
line := scanner.Text()
@@ -107,6 +108,9 @@ func genRules(arch arch) {
if !strings.Contains(rule, "->") {
continue
}
+ if ruleLineno == 0 {
+ ruleLineno = lineno
+ }
if strings.HasSuffix(rule, "->") {
continue
}
@@ -117,18 +121,20 @@ func genRules(arch arch) {
if op[len(op)-1] == ')' {
op = op[:len(op)-1] // rule has only opcode, e.g. (ConstNil) -> ...
}
+ loc := fmt.Sprintf("%s.rules:%d", arch.name, ruleLineno)
if isBlock(op, arch) {
- blockrules[op] = append(blockrules[op], Rule{rule: rule, lineno: lineno})
+ blockrules[op] = append(blockrules[op], Rule{rule: rule, loc: loc})
} else {
- oprules[op] = append(oprules[op], Rule{rule: rule, lineno: lineno})
+ oprules[op] = append(oprules[op], Rule{rule: rule, loc: loc})
}
rule = ""
+ ruleLineno = 0
}
if err := scanner.Err(); err != nil {
log.Fatalf("scanner failed: %v\n", err)
}
if unbalanced(rule) {
- log.Fatalf("unbalanced rule at line %d: %v\n", lineno, rule)
+ log.Fatalf("%s.rules:%d: unbalanced rule: %v\n", arch.name, lineno, rule)
}
// Order all the ops.
@@ -174,15 +180,15 @@ func genRules(arch arch) {
fmt.Fprintf(w, "// result: %s\n", result)
fmt.Fprintf(w, "for {\n")
- genMatch(w, arch, match)
+ genMatch(w, arch, match, rule.loc)
if cond != "" {
fmt.Fprintf(w, "if !(%s) {\nbreak\n}\n", cond)
}
- genResult(w, arch, result)
+ genResult(w, arch, result, rule.loc)
if *genLog {
- fmt.Fprintf(w, "fmt.Println(\"rewrite %s.rules:%d\")\n", arch.name, rule.lineno)
+ fmt.Fprintf(w, "fmt.Println(\"rewrite %s\")\n", rule.loc)
}
fmt.Fprintf(w, "return true\n")
@@ -217,7 +223,7 @@ func genRules(arch arch) {
if s[1] != "nil" {
fmt.Fprintf(w, "v := b.Control\n")
if strings.Contains(s[1], "(") {
- genMatch0(w, arch, s[1], "v", map[string]struct{}{}, false)
+ genMatch0(w, arch, s[1], "v", map[string]struct{}{}, false, rule.loc)
} else {
fmt.Fprintf(w, "%s := b.Control\n", s[1])
}
@@ -266,7 +272,7 @@ func genRules(arch arch) {
if t[1] == "nil" {
fmt.Fprintf(w, "b.SetControl(nil)\n")
} else {
- fmt.Fprintf(w, "b.SetControl(%s)\n", genResult0(w, arch, t[1], new(int), false, false))
+ fmt.Fprintf(w, "b.SetControl(%s)\n", genResult0(w, arch, t[1], new(int), false, false, rule.loc))
}
if len(newsuccs) < len(succs) {
fmt.Fprintf(w, "b.Succs = b.Succs[:%d]\n", len(newsuccs))
@@ -289,7 +295,7 @@ func genRules(arch arch) {
}
if *genLog {
- fmt.Fprintf(w, "fmt.Println(\"rewrite %s.rules:%d\")\n", arch.name, rule.lineno)
+ fmt.Fprintf(w, "fmt.Println(\"rewrite %s\")\n", rule.loc)
}
fmt.Fprintf(w, "return true\n")
@@ -315,11 +321,11 @@ func genRules(arch arch) {
}
}
-func genMatch(w io.Writer, arch arch, match string) {
- genMatch0(w, arch, match, "v", map[string]struct{}{}, true)
+func genMatch(w io.Writer, arch arch, match string, loc string) {
+ genMatch0(w, arch, match, "v", map[string]struct{}{}, true, loc)
}
-func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, top bool) {
+func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, top bool, loc string) {
if match[0] != '(' || match[len(match)-1] != ')' {
panic("non-compound expr in genMatch0: " + match)
}
@@ -328,6 +334,24 @@ func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, t
// contained in () or {}.
s := split(match[1 : len(match)-1]) // remove parens, then split
+ // Find op record
+ var op opData
+ for _, x := range genericOps {
+ if x.name == s[0] {
+ op = x
+ break
+ }
+ }
+ for _, x := range arch.ops {
+ if x.name == s[0] {
+ op = x
+ break
+ }
+ }
+ if op.name == "" {
+ log.Fatalf("%s: unknown op %s", loc, s[0])
+ }
+
// check op
if !top {
fmt.Fprintf(w, "if %s.Op != %s {\nbreak\n}\n", v, opName(s[0], arch))
@@ -354,6 +378,11 @@ func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, t
}
} else if a[0] == '[' {
// auxint restriction
+ switch op.aux {
+ case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "SymInt32":
+ default:
+ log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
+ }
x := a[1 : len(a)-1] // remove []
if !isVariable(x) {
// code
@@ -368,7 +397,12 @@ func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, t
}
}
} else if a[0] == '{' {
- // auxint restriction
+ // aux restriction
+ switch op.aux {
+ case "String", "Sym", "SymOff", "SymValAndOff", "SymInt32":
+ default:
+ log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
+ }
x := a[1 : len(a)-1] // remove {}
if !isVariable(x) {
// code
@@ -412,30 +446,18 @@ func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, t
argname = fmt.Sprintf("%s_%d", v, argnum)
}
fmt.Fprintf(w, "%s := %s.Args[%d]\n", argname, v, argnum)
- genMatch0(w, arch, a, argname, m, false)
+ genMatch0(w, arch, a, argname, m, false, loc)
argnum++
}
}
-
- variableLength := false
- for _, op := range genericOps {
- if op.name == s[0] && op.argLength == -1 {
- variableLength = true
- break
- }
- }
- for _, op := range arch.ops {
- if op.name == s[0] && op.argLength == -1 {
- variableLength = true
- break
- }
- }
- if variableLength {
+ if op.argLength == -1 {
fmt.Fprintf(w, "if len(%s.Args) != %d {\nbreak\n}\n", v, argnum)
+ } else if int(op.argLength) != argnum {
+ log.Fatalf("%s: op %s should have %d args, has %d", loc, op.name, op.argLength, argnum)
}
}
-func genResult(w io.Writer, arch arch, result string) {
+func genResult(w io.Writer, arch arch, result string, loc string) {
move := false
if result[0] == '@' {
// parse @block directive
@@ -444,9 +466,9 @@ func genResult(w io.Writer, arch arch, result string) {
result = s[1]
move = true
}
- genResult0(w, arch, result, new(int), true, move)
+ genResult0(w, arch, result, new(int), true, move, loc)
}
-func genResult0(w io.Writer, arch arch, result string, alloc *int, top, move bool) string {
+func genResult0(w io.Writer, arch arch, result string, alloc *int, top, move bool, loc string) string {
// TODO: when generating a constant result, use f.constVal to avoid
// introducing copies just to clean them up again.
if result[0] != '(' {
@@ -464,6 +486,24 @@ func genResult0(w io.Writer, arch arch, result string, alloc *int, top, move boo
s := split(result[1 : len(result)-1]) // remove parens, then split
+ // Find op record
+ var op opData
+ for _, x := range genericOps {
+ if x.name == s[0] {
+ op = x
+ break
+ }
+ }
+ for _, x := range arch.ops {
+ if x.name == s[0] {
+ op = x
+ break
+ }
+ }
+ if op.name == "" {
+ log.Fatalf("%s: unknown op %s", loc, s[0])
+ }
+
// Find the type of the variable.
var opType string
var typeOverride bool
@@ -512,23 +552,38 @@ func genResult0(w io.Writer, arch arch, result string, alloc *int, top, move boo
fmt.Fprintf(w, "v.AddArg(%s)\n", v)
}
}
+ argnum := 0
for _, a := range s[1:] {
if a[0] == '<' {
// type restriction, handled above
} else if a[0] == '[' {
// auxint restriction
+ switch op.aux {
+ case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "SymInt32":
+ default:
+ log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
+ }
x := a[1 : len(a)-1] // remove []
fmt.Fprintf(w, "%s.AuxInt = %s\n", v, x)
} else if a[0] == '{' {
// aux restriction
+ switch op.aux {
+ case "String", "Sym", "SymOff", "SymValAndOff", "SymInt32":
+ default:
+ log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
+ }
x := a[1 : len(a)-1] // remove {}
fmt.Fprintf(w, "%s.Aux = %s\n", v, x)
} else {
// regular argument (sexpr or variable)
- x := genResult0(w, arch, a, alloc, false, move)
+ x := genResult0(w, arch, a, alloc, false, move, loc)
fmt.Fprintf(w, "%s.AddArg(%s)\n", v, x)
+ argnum++
}
}
+ if op.argLength != -1 && int(op.argLength) != argnum {
+ log.Fatalf("%s: op %s should have %d args, has %d", loc, op.name, op.argLength, argnum)
+ }
return v
}
diff --git a/src/cmd/compile/internal/ssa/id.go b/src/cmd/compile/internal/ssa/id.go
index 367e687abf..725279e9fd 100644
--- a/src/cmd/compile/internal/ssa/id.go
+++ b/src/cmd/compile/internal/ssa/id.go
@@ -11,7 +11,7 @@ type idAlloc struct {
last ID
}
-// get allocates an ID and returns it.
+// get allocates an ID and returns it. IDs are always > 0.
func (a *idAlloc) get() ID {
x := a.last
x++
diff --git a/src/cmd/compile/internal/ssa/likelyadjust.go b/src/cmd/compile/internal/ssa/likelyadjust.go
index 76251bdd14..2f52c4c6e6 100644
--- a/src/cmd/compile/internal/ssa/likelyadjust.go
+++ b/src/cmd/compile/internal/ssa/likelyadjust.go
@@ -11,11 +11,24 @@ import (
type loop struct {
header *Block // The header node of this (reducible) loop
outer *loop // loop containing this loop
- // Next two fields not currently used, but cheap to maintain,
- // and aid in computation of inner-ness and list of blocks.
- nBlocks int32 // Number of blocks in this loop but not within inner loops
- isInner bool // True if never discovered to contain a loop
- containsCall bool // if any block in this loop or any loop it contains is a BlockCall or BlockDefer
+
+ // By default, children exits, and depth are not initialized.
+ children []*loop // loops nested directly within this loop. Initialized by assembleChildren().
+ exits []*Block // exits records blocks reached by exits from this loop. Initialized by findExits().
+
+ // Loops aren't that common, so rather than force regalloc to keep
+ // a map or slice for its data, just put it here.
+ spills []*Value
+ scratch int32
+
+ // Next three fields used by regalloc and/or
+ // aid in computation of inner-ness and list of blocks.
+ nBlocks int32 // Number of blocks in this loop but not within inner loops
+ depth int16 // Nesting depth of the loop; 1 is outermost. Initialized by calculateDepths().
+ isInner bool // True if never discovered to contain a loop
+
+ // register allocation uses this.
+ containsCall bool // if any block in this loop or any loop it contains is a BlockCall or BlockDefer
}
// outerinner records that outer contains inner
@@ -48,6 +61,9 @@ type loopnest struct {
po []*Block
sdom sparseTree
loops []*loop
+
+ // Record which of the lazily initialized fields have actually been initialized.
+ initializedChildren, initializedDepth, initializedExits bool
}
func min8(a, b int8) int8 {
@@ -295,6 +311,35 @@ func loopnestfor(f *Func) *loopnest {
innermost.nBlocks++
}
}
+
+ ln := &loopnest{f: f, b2l: b2l, po: po, sdom: sdom, loops: loops}
+
+ // Curious about the loopiness? "-d=ssa/likelyadjust/stats"
+ if f.pass.stats > 0 && len(loops) > 0 {
+ ln.assembleChildren()
+ ln.calculateDepths()
+ ln.findExits()
+
+ // Note stats for non-innermost loops are slightly flawed because
+ // they don't account for inner loop exits that span multiple levels.
+
+ for _, l := range loops {
+ x := len(l.exits)
+ cf := 0
+ if !l.containsCall {
+ cf = 1
+ }
+ inner := 0
+ if l.isInner {
+ inner++
+ }
+
+ f.logStat("loopstats:",
+ l.depth, "depth", x, "exits",
+ inner, "is_inner", cf, "is_callfree", l.nBlocks, "n_blocks")
+ }
+ }
+
if f.pass.debug > 1 && len(loops) > 0 {
fmt.Printf("Loops in %s:\n", f.Name)
for _, l := range loops {
@@ -314,5 +359,90 @@ func loopnestfor(f *Func) *loopnest {
}
fmt.Print("\n")
}
- return &loopnest{f, b2l, po, sdom, loops}
+ return ln
+}
+
+// assembleChildren initializes the children field of each
+// loop in the nest. Loop A is a child of loop B if A is
+// directly nested within B (based on the reducible-loops
+// detection above)
+func (ln *loopnest) assembleChildren() {
+ if ln.initializedChildren {
+ return
+ }
+ for _, l := range ln.loops {
+ if l.outer != nil {
+ l.outer.children = append(l.outer.children, l)
+ }
+ }
+ ln.initializedChildren = true
+}
+
+// calculateDepths uses the children field of loops
+// to determine the nesting depth (outer=1) of each
+// loop. This is helpful for finding exit edges.
+func (ln *loopnest) calculateDepths() {
+ if ln.initializedDepth {
+ return
+ }
+ ln.assembleChildren()
+ for _, l := range ln.loops {
+ if l.outer == nil {
+ l.setDepth(1)
+ }
+ }
+ ln.initializedDepth = true
+}
+
+// findExits uses loop depth information to find the
+// exits from a loop.
+func (ln *loopnest) findExits() {
+ if ln.initializedExits {
+ return
+ }
+ ln.calculateDepths()
+ b2l := ln.b2l
+ for _, b := range ln.po {
+ l := b2l[b.ID]
+ if l != nil && len(b.Succs) == 2 {
+ sl := b2l[b.Succs[0].ID]
+ if recordIfExit(l, sl, b.Succs[0]) {
+ continue
+ }
+ sl = b2l[b.Succs[1].ID]
+ if recordIfExit(l, sl, b.Succs[1]) {
+ continue
+ }
+ }
+ }
+ ln.initializedExits = true
+}
+
+// recordIfExit checks sl (the loop containing b) to see if it
+// is outside of loop l, and if so, records b as an exit block
+// from l and returns true.
+func recordIfExit(l, sl *loop, b *Block) bool {
+ if sl != l {
+ if sl == nil || sl.depth <= l.depth {
+ l.exits = append(l.exits, b)
+ return true
+ }
+ // sl is not nil, and is deeper than l
+ // it's possible for this to be a goto into an irreducible loop made from gotos.
+ for sl.depth > l.depth {
+ sl = sl.outer
+ }
+ if sl != l {
+ l.exits = append(l.exits, b)
+ return true
+ }
+ }
+ return false
+}
+
+func (l *loop) setDepth(d int16) {
+ l.depth = d
+ for _, c := range l.children {
+ c.setDepth(d + 1)
+ }
}
diff --git a/src/cmd/compile/internal/ssa/loopbce.go b/src/cmd/compile/internal/ssa/loopbce.go
index 17486ac49f..9bd2d3f0de 100644
--- a/src/cmd/compile/internal/ssa/loopbce.go
+++ b/src/cmd/compile/internal/ssa/loopbce.go
@@ -31,7 +31,7 @@ type indVar struct {
//
//
// TODO: handle 32 bit operations
-func findIndVar(f *Func, sdom sparseTree) []indVar {
+func findIndVar(f *Func) []indVar {
var iv []indVar
nextb:
@@ -110,7 +110,7 @@ nextb:
// Second condition: b.Succs[entry] dominates nxt so that
// nxt is computed when inc < max, meaning nxt <= max.
- if !sdom.isAncestorEq(b.Succs[entry], nxt.Block) {
+ if !f.sdom.isAncestorEq(b.Succs[entry], nxt.Block) {
// inc+ind can only be reached through the branch that enters the loop.
continue
}
@@ -160,20 +160,18 @@ nextb:
// loopbce performs loop based bounds check elimination.
func loopbce(f *Func) {
- idom := dominators(f)
- sdom := newSparseTree(f, idom)
- ivList := findIndVar(f, sdom)
+ ivList := findIndVar(f)
m := make(map[*Value]indVar)
for _, iv := range ivList {
m[iv.ind] = iv
}
- removeBoundsChecks(f, sdom, m)
+ removeBoundsChecks(f, m)
}
// removesBoundsChecks remove IsInBounds and IsSliceInBounds based on the induction variables.
-func removeBoundsChecks(f *Func, sdom sparseTree, m map[*Value]indVar) {
+func removeBoundsChecks(f *Func, m map[*Value]indVar) {
for _, b := range f.Blocks {
if b.Kind != BlockIf {
continue
@@ -202,7 +200,7 @@ func removeBoundsChecks(f *Func, sdom sparseTree, m map[*Value]indVar) {
goto skip1
}
- if iv, has := m[ind]; has && sdom.isAncestorEq(iv.entry, b) && isNonNegative(iv.min) {
+ if iv, has := m[ind]; has && f.sdom.isAncestorEq(iv.entry, b) && isNonNegative(iv.min) {
if v.Args[1] == iv.max {
if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "Found redundant %s", v.Op)
@@ -229,7 +227,7 @@ func removeBoundsChecks(f *Func, sdom sparseTree, m map[*Value]indVar) {
goto skip2
}
- if iv, has := m[ind]; has && sdom.isAncestorEq(iv.entry, b) && isNonNegative(iv.min) {
+ if iv, has := m[ind]; has && f.sdom.isAncestorEq(iv.entry, b) && isNonNegative(iv.min) {
if v.Args[1].Op == OpSliceCap && iv.max.Op == OpSliceLen && v.Args[1].Args[0] == iv.max.Args[0] {
if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "Found redundant %s (len promoted to cap)", v.Op)
@@ -240,6 +238,37 @@ func removeBoundsChecks(f *Func, sdom sparseTree, m map[*Value]indVar) {
}
skip2:
+ // Simplify
+ // (IsInBounds (Add64 ind) (Const64 [c])) where 0 <= min <= ind < max <= (Const64 [c])
+ // (IsSliceInBounds ind (Const64 [c])) where 0 <= min <= ind < max <= (Const64 [c])
+ if v.Op == OpIsInBounds || v.Op == OpIsSliceInBounds {
+ ind, add := dropAdd64(v.Args[0])
+ if ind.Op != OpPhi {
+ goto skip3
+ }
+
+ // ind + add >= 0 <-> min + add >= 0 <-> min >= -add
+ if iv, has := m[ind]; has && f.sdom.isAncestorEq(iv.entry, b) && isGreaterOrEqualThan(iv.min, -add) {
+ if !v.Args[1].isGenericIntConst() || !iv.max.isGenericIntConst() {
+ goto skip3
+ }
+
+ limit := v.Args[1].AuxInt
+ if v.Op == OpIsSliceInBounds {
+ // If limit++ overflows signed integer then 0 <= max && max <= limit will be false.
+ limit++
+ }
+
+ if max := iv.max.AuxInt + add; 0 <= max && max <= limit { // handle overflow
+ if f.pass.debug > 0 {
+ f.Config.Warnl(b.Line, "Found redundant (%s ind %d), ind < %d", v.Op, v.Args[1].AuxInt, iv.max.AuxInt+add)
+ }
+ goto simplify
+ }
+ }
+ }
+ skip3:
+
continue
simplify:
@@ -258,3 +287,13 @@ func dropAdd64(v *Value) (*Value, int64) {
}
return v, 0
}
+
+func isGreaterOrEqualThan(v *Value, c int64) bool {
+ if c == 0 {
+ return isNonNegative(v)
+ }
+ if v.isGenericIntConst() && v.AuxInt >= c {
+ return true
+ }
+ return false
+}
diff --git a/src/cmd/compile/internal/ssa/nilcheck.go b/src/cmd/compile/internal/ssa/nilcheck.go
index 881e3b2eff..62eb0c8ea6 100644
--- a/src/cmd/compile/internal/ssa/nilcheck.go
+++ b/src/cmd/compile/internal/ssa/nilcheck.go
@@ -4,14 +4,12 @@
package ssa
-// TODO: return value from newobject/newarray is non-nil.
-
// nilcheckelim eliminates unnecessary nil checks.
func nilcheckelim(f *Func) {
// A nil check is redundant if the same nil check was successful in a
// dominating block. The efficacy of this pass depends heavily on the
// efficacy of the cse pass.
- idom := dominators(f)
+ idom := f.idom
domTree := make([][]*Block, f.NumBlocks())
// Create a block ID -> [dominees] mapping
diff --git a/src/cmd/compile/internal/ssa/nilcheck_test.go b/src/cmd/compile/internal/ssa/nilcheck_test.go
index d1f38b6951..af6cbe864a 100644
--- a/src/cmd/compile/internal/ssa/nilcheck_test.go
+++ b/src/cmd/compile/internal/ssa/nilcheck_test.go
@@ -49,6 +49,7 @@ func benchmarkNilCheckDeep(b *testing.B, depth int) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
+ domTree(fun.f)
nilcheckelim(fun.f)
}
}
@@ -83,6 +84,7 @@ func TestNilcheckSimple(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
+ domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -120,6 +122,7 @@ func TestNilcheckDomOrder(t *testing.T) {
Goto("exit")))
CheckFunc(fun.f)
+ domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -153,6 +156,7 @@ func TestNilcheckAddr(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
+ domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -187,6 +191,7 @@ func TestNilcheckAddPtr(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
+ domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -231,6 +236,7 @@ func TestNilcheckPhi(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
+ domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -272,6 +278,7 @@ func TestNilcheckKeepRemove(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
+ domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -319,6 +326,7 @@ func TestNilcheckInFalseBranch(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
+ domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -370,6 +378,7 @@ func TestNilcheckUser(t *testing.T) {
CheckFunc(fun.f)
// we need the opt here to rewrite the user nilcheck
opt(fun.f)
+ domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -409,11 +418,12 @@ func TestNilcheckBug(t *testing.T) {
Goto("exit")),
Bloc("exit",
Valu("phi", OpPhi, TypeMem, 0, nil, "mem", "store"),
- Exit("mem")))
+ Exit("phi")))
CheckFunc(fun.f)
// we need the opt here to rewrite the user nilcheck
opt(fun.f)
+ domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go
index d10ea230ff..cadbc7cd7a 100644
--- a/src/cmd/compile/internal/ssa/op.go
+++ b/src/cmd/compile/internal/ssa/op.go
@@ -26,7 +26,7 @@ type opInfo struct {
generic bool // this is a generic (arch-independent) opcode
rematerializeable bool // this op is rematerializeable
commutative bool // this operation is commutative (e.g. addition)
- resultInArg0 bool // prefer v and v.Args[0] to be allocated to the same register
+ resultInArg0 bool // v and v.Args[0] must be allocated to the same register
}
type inputInfo struct {
@@ -49,9 +49,10 @@ const (
auxInt16 // auxInt is a 16-bit integer
auxInt32 // auxInt is a 32-bit integer
auxInt64 // auxInt is a 64-bit integer
+ auxInt128 // auxInt represents a 128-bit integer. Always 0.
auxFloat32 // auxInt is a float32 (encoded with math.Float64bits)
auxFloat64 // auxInt is a float64 (encoded with math.Float64bits)
- auxString // auxInt is a string
+ auxString // aux is a string
auxSym // aux is a symbol
auxSymOff // aux is a symbol, auxInt is an offset
auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
index 5465d7f5ed..9ab9be769c 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -120,28 +120,16 @@ const (
OpAMD64MOVSDstoreidx8
OpAMD64ADDQ
OpAMD64ADDL
- OpAMD64ADDW
- OpAMD64ADDB
OpAMD64ADDQconst
OpAMD64ADDLconst
- OpAMD64ADDWconst
- OpAMD64ADDBconst
OpAMD64SUBQ
OpAMD64SUBL
- OpAMD64SUBW
- OpAMD64SUBB
OpAMD64SUBQconst
OpAMD64SUBLconst
- OpAMD64SUBWconst
- OpAMD64SUBBconst
OpAMD64MULQ
OpAMD64MULL
- OpAMD64MULW
- OpAMD64MULB
OpAMD64MULQconst
OpAMD64MULLconst
- OpAMD64MULWconst
- OpAMD64MULBconst
OpAMD64HMULQ
OpAMD64HMULL
OpAMD64HMULW
@@ -165,28 +153,16 @@ const (
OpAMD64MODWU
OpAMD64ANDQ
OpAMD64ANDL
- OpAMD64ANDW
- OpAMD64ANDB
OpAMD64ANDQconst
OpAMD64ANDLconst
- OpAMD64ANDWconst
- OpAMD64ANDBconst
OpAMD64ORQ
OpAMD64ORL
- OpAMD64ORW
- OpAMD64ORB
OpAMD64ORQconst
OpAMD64ORLconst
- OpAMD64ORWconst
- OpAMD64ORBconst
OpAMD64XORQ
OpAMD64XORL
- OpAMD64XORW
- OpAMD64XORB
OpAMD64XORQconst
OpAMD64XORLconst
- OpAMD64XORWconst
- OpAMD64XORBconst
OpAMD64CMPQ
OpAMD64CMPL
OpAMD64CMPW
@@ -207,12 +183,8 @@ const (
OpAMD64TESTBconst
OpAMD64SHLQ
OpAMD64SHLL
- OpAMD64SHLW
- OpAMD64SHLB
OpAMD64SHLQconst
OpAMD64SHLLconst
- OpAMD64SHLWconst
- OpAMD64SHLBconst
OpAMD64SHRQ
OpAMD64SHRL
OpAMD64SHRW
@@ -235,12 +207,8 @@ const (
OpAMD64ROLBconst
OpAMD64NEGQ
OpAMD64NEGL
- OpAMD64NEGW
- OpAMD64NEGB
OpAMD64NOTQ
OpAMD64NOTL
- OpAMD64NOTW
- OpAMD64NOTB
OpAMD64BSFQ
OpAMD64BSFL
OpAMD64BSFW
@@ -280,8 +248,6 @@ const (
OpAMD64MOVWQZX
OpAMD64MOVLQSX
OpAMD64MOVLQZX
- OpAMD64MOVBconst
- OpAMD64MOVWconst
OpAMD64MOVLconst
OpAMD64MOVQconst
OpAMD64CVTTSD2SL
@@ -537,6 +503,10 @@ const (
OpGeq64U
OpGeq32F
OpGeq64F
+ OpAndB
+ OpOrB
+ OpEqB
+ OpNeqB
OpNot
OpNeg8
OpNeg16
@@ -971,81 +941,13 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "ADDQ",
- argLen: 2,
- commutative: true,
- resultInArg0: true,
- asm: x86.AADDQ,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "ADDL",
- argLen: 2,
- commutative: true,
- resultInArg0: true,
- asm: x86.AADDL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "ADDW",
- argLen: 2,
- commutative: true,
- resultInArg0: true,
- asm: x86.AADDL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "ADDB",
- argLen: 2,
- commutative: true,
- resultInArg0: true,
- asm: x86.AADDL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "ADDQconst",
- auxType: auxInt64,
- argLen: 1,
- resultInArg0: true,
- asm: x86.AADDQ,
+ name: "ADDQ",
+ argLen: 2,
+ commutative: true,
+ asm: x86.AADDQ,
reg: regInfo{
inputs: []inputInfo{
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
@@ -1055,13 +957,13 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "ADDLconst",
- auxType: auxInt32,
- argLen: 1,
- resultInArg0: true,
- asm: x86.AADDL,
+ name: "ADDL",
+ argLen: 2,
+ commutative: true,
+ asm: x86.AADDL,
reg: regInfo{
inputs: []inputInfo{
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
@@ -1071,11 +973,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "ADDWconst",
- auxType: auxInt16,
- argLen: 1,
- resultInArg0: true,
- asm: x86.AADDL,
+ name: "ADDQconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: x86.AADDQ,
reg: regInfo{
inputs: []inputInfo{
{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -1087,11 +988,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "ADDBconst",
- auxType: auxInt8,
- argLen: 1,
- resultInArg0: true,
- asm: x86.AADDL,
+ name: "ADDLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: x86.AADDL,
reg: regInfo{
inputs: []inputInfo{
{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -1109,8 +1009,8 @@ var opcodeTable = [...]opInfo{
asm: x86.ASUBQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1125,40 +1025,8 @@ var opcodeTable = [...]opInfo{
asm: x86.ASUBL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "SUBW",
- argLen: 2,
- resultInArg0: true,
- asm: x86.ASUBL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "SUBB",
- argLen: 2,
- resultInArg0: true,
- asm: x86.ASUBL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1174,7 +1042,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ASUBQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1190,39 +1058,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ASUBL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "SUBWconst",
- auxType: auxInt16,
- argLen: 1,
- resultInArg0: true,
- asm: x86.ASUBL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "SUBBconst",
- auxType: auxInt8,
- argLen: 1,
- resultInArg0: true,
- asm: x86.ASUBL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1238,8 +1074,8 @@ var opcodeTable = [...]opInfo{
asm: x86.AIMULQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1255,42 +1091,8 @@ var opcodeTable = [...]opInfo{
asm: x86.AIMULL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "MULW",
- argLen: 2,
- commutative: true,
- resultInArg0: true,
- asm: x86.AIMULW,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "MULB",
- argLen: 2,
- commutative: true,
- resultInArg0: true,
- asm: x86.AIMULW,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1306,7 +1108,7 @@ var opcodeTable = [...]opInfo{
asm: x86.AIMULQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1322,39 +1124,7 @@ var opcodeTable = [...]opInfo{
asm: x86.AIMULL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "MULWconst",
- auxType: auxInt16,
- argLen: 1,
- resultInArg0: true,
- asm: x86.AIMULW,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "MULBconst",
- auxType: auxInt8,
- argLen: 1,
- resultInArg0: true,
- asm: x86.AIMULW,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1489,8 +1259,8 @@ var opcodeTable = [...]opInfo{
resultInArg0: true,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1686,8 +1456,8 @@ var opcodeTable = [...]opInfo{
asm: x86.AANDQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1703,42 +1473,8 @@ var opcodeTable = [...]opInfo{
asm: x86.AANDL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "ANDW",
- argLen: 2,
- commutative: true,
- resultInArg0: true,
- asm: x86.AANDL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "ANDB",
- argLen: 2,
- commutative: true,
- resultInArg0: true,
- asm: x86.AANDL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1754,7 +1490,7 @@ var opcodeTable = [...]opInfo{
asm: x86.AANDQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1770,39 +1506,7 @@ var opcodeTable = [...]opInfo{
asm: x86.AANDL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "ANDWconst",
- auxType: auxInt16,
- argLen: 1,
- resultInArg0: true,
- asm: x86.AANDL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "ANDBconst",
- auxType: auxInt8,
- argLen: 1,
- resultInArg0: true,
- asm: x86.AANDL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1818,8 +1522,8 @@ var opcodeTable = [...]opInfo{
asm: x86.AORQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1835,42 +1539,8 @@ var opcodeTable = [...]opInfo{
asm: x86.AORL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "ORW",
- argLen: 2,
- commutative: true,
- resultInArg0: true,
- asm: x86.AORL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "ORB",
- argLen: 2,
- commutative: true,
- resultInArg0: true,
- asm: x86.AORL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1886,7 +1556,7 @@ var opcodeTable = [...]opInfo{
asm: x86.AORQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1902,39 +1572,7 @@ var opcodeTable = [...]opInfo{
asm: x86.AORL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "ORWconst",
- auxType: auxInt16,
- argLen: 1,
- resultInArg0: true,
- asm: x86.AORL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "ORBconst",
- auxType: auxInt8,
- argLen: 1,
- resultInArg0: true,
- asm: x86.AORL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1950,8 +1588,8 @@ var opcodeTable = [...]opInfo{
asm: x86.AXORQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -1967,42 +1605,8 @@ var opcodeTable = [...]opInfo{
asm: x86.AXORL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "XORW",
- argLen: 2,
- commutative: true,
- resultInArg0: true,
- asm: x86.AXORL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "XORB",
- argLen: 2,
- commutative: true,
- resultInArg0: true,
- asm: x86.AXORL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2018,7 +1622,7 @@ var opcodeTable = [...]opInfo{
asm: x86.AXORQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2034,39 +1638,7 @@ var opcodeTable = [...]opInfo{
asm: x86.AXORL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "XORWconst",
- auxType: auxInt16,
- argLen: 1,
- resultInArg0: true,
- asm: x86.AXORL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "XORBconst",
- auxType: auxInt8,
- argLen: 1,
- resultInArg0: true,
- asm: x86.AXORL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2334,11 +1906,11 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 2}, // CX
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
- 65517, // AX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
@@ -2350,43 +1922,11 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 2}, // CX
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65517, // AX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "SHLW",
- argLen: 2,
- resultInArg0: true,
- asm: x86.ASHLL,
- reg: regInfo{
- inputs: []inputInfo{
- {1, 2}, // CX
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65517, // AX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "SHLB",
- argLen: 2,
- resultInArg0: true,
- asm: x86.ASHLL,
- reg: regInfo{
- inputs: []inputInfo{
- {1, 2}, // CX
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
- 65517, // AX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
@@ -2398,7 +1938,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ASHLQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2414,39 +1954,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ASHLL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "SHLWconst",
- auxType: auxInt16,
- argLen: 1,
- resultInArg0: true,
- asm: x86.ASHLL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "SHLBconst",
- auxType: auxInt8,
- argLen: 1,
- resultInArg0: true,
- asm: x86.ASHLL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2462,11 +1970,11 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 2}, // CX
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
- 65517, // AX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
@@ -2478,11 +1986,11 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 2}, // CX
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
- 65517, // AX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
@@ -2494,11 +2002,11 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 2}, // CX
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
- 65517, // AX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
@@ -2510,11 +2018,11 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 2}, // CX
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
- 65517, // AX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
@@ -2526,7 +2034,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ASHRQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2542,7 +2050,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ASHRL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2558,7 +2066,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ASHRW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2574,7 +2082,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ASHRB,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2590,11 +2098,11 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 2}, // CX
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
- 65517, // AX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
@@ -2606,11 +2114,11 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 2}, // CX
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
- 65517, // AX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
@@ -2622,11 +2130,11 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 2}, // CX
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
- 65517, // AX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
@@ -2638,11 +2146,11 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 2}, // CX
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
- 65517, // AX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
@@ -2654,7 +2162,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ASARQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2670,7 +2178,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ASARL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2686,7 +2194,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ASARW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2702,7 +2210,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ASARB,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2718,7 +2226,7 @@ var opcodeTable = [...]opInfo{
asm: x86.AROLQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2734,7 +2242,7 @@ var opcodeTable = [...]opInfo{
asm: x86.AROLL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2750,7 +2258,7 @@ var opcodeTable = [...]opInfo{
asm: x86.AROLW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2766,7 +2274,7 @@ var opcodeTable = [...]opInfo{
asm: x86.AROLB,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2781,7 +2289,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ANEGQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2796,37 +2304,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ANEGL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "NEGW",
- argLen: 1,
- resultInArg0: true,
- asm: x86.ANEGL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "NEGB",
- argLen: 1,
- resultInArg0: true,
- asm: x86.ANEGL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2841,7 +2319,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ANOTQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2856,37 +2334,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ANOTL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "NOTW",
- argLen: 1,
- resultInArg0: true,
- asm: x86.ANOTL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "NOTB",
- argLen: 1,
- resultInArg0: true,
- asm: x86.ANOTL,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2900,7 +2348,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ABSFQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2914,7 +2362,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ABSFL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2928,7 +2376,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ABSFW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2942,7 +2390,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ABSRQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2956,7 +2404,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ABSRL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2970,7 +2418,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ABSRW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -2987,7 +2435,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 8589934592}, // FLAGS
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934593, // AX FLAGS
outputs: []regMask{
@@ -3004,7 +2452,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 8589934592}, // FLAGS
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934593, // AX FLAGS
outputs: []regMask{
@@ -3021,7 +2469,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 8589934592}, // FLAGS
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934593, // AX FLAGS
outputs: []regMask{
@@ -3038,7 +2486,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 8589934592}, // FLAGS
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934593, // AX FLAGS
outputs: []regMask{
@@ -3055,7 +2503,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 8589934592}, // FLAGS
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934593, // AX FLAGS
outputs: []regMask{
@@ -3072,7 +2520,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 8589934592}, // FLAGS
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934593, // AX FLAGS
outputs: []regMask{
@@ -3087,7 +2535,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ABSWAPQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -3102,7 +2550,7 @@ var opcodeTable = [...]opInfo{
asm: x86.ABSWAPL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
clobbers: 8589934592, // FLAGS
outputs: []regMask{
@@ -3438,30 +2886,6 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "MOVBconst",
- auxType: auxInt8,
- argLen: 0,
- rematerializeable: true,
- asm: x86.AMOVB,
- reg: regInfo{
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
- name: "MOVWconst",
- auxType: auxInt16,
- argLen: 0,
- rematerializeable: true,
- asm: x86.AMOVW,
- reg: regInfo{
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- },
- },
- {
name: "MOVLconst",
auxType: auxInt32,
argLen: 0,
@@ -4211,6 +3635,7 @@ var opcodeTable = [...]opInfo{
},
{
name: "MOVOconst",
+ auxType: auxInt128,
argLen: 0,
rematerializeable: true,
reg: regInfo{
@@ -4430,9 +3855,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "MOVWload",
- argLen: 2,
- asm: arm.AMOVW,
+ name: "MOVWload",
+ auxType: auxSymOff,
+ argLen: 2,
+ asm: arm.AMOVW,
reg: regInfo{
inputs: []inputInfo{
{0, 31}, // R0 R1 R2 R3 SP
@@ -4443,9 +3869,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "MOVWstore",
- argLen: 3,
- asm: arm.AMOVW,
+ name: "MOVWstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: arm.AMOVW,
reg: regInfo{
inputs: []inputInfo{
{0, 31}, // R0 R1 R2 R3 SP
@@ -4463,7 +3890,7 @@ var opcodeTable = [...]opInfo{
},
{
name: "LessThan",
- argLen: 2,
+ argLen: 1,
reg: regInfo{
inputs: []inputInfo{
{0, 32}, // FLAGS
@@ -5354,6 +4781,26 @@ var opcodeTable = [...]opInfo{
generic: true,
},
{
+ name: "AndB",
+ argLen: 2,
+ generic: true,
+ },
+ {
+ name: "OrB",
+ argLen: 2,
+ generic: true,
+ },
+ {
+ name: "EqB",
+ argLen: 2,
+ generic: true,
+ },
+ {
+ name: "NeqB",
+ argLen: 2,
+ generic: true,
+ },
+ {
name: "Not",
argLen: 1,
generic: true,
diff --git a/src/cmd/compile/internal/ssa/phielim.go b/src/cmd/compile/internal/ssa/phielim.go
index ce3b5a199a..77013c6481 100644
--- a/src/cmd/compile/internal/ssa/phielim.go
+++ b/src/cmd/compile/internal/ssa/phielim.go
@@ -40,11 +40,7 @@ func phielimValue(v *Value) bool {
// are not v itself, then the phi must remain.
// Otherwise, we can replace it with a copy.
var w *Value
- for i, x := range v.Args {
- if b := v.Block.Preds[i]; b.Kind == BlockFirst && b.Succs[1] == v.Block {
- // This branch is never taken so we can just eliminate it.
- continue
- }
+ for _, x := range v.Args {
if x == v {
continue
}
diff --git a/src/cmd/compile/internal/ssa/phiopt.go b/src/cmd/compile/internal/ssa/phiopt.go
index 2d0a45733a..3b6728ca86 100644
--- a/src/cmd/compile/internal/ssa/phiopt.go
+++ b/src/cmd/compile/internal/ssa/phiopt.go
@@ -26,6 +26,7 @@ package ssa
func phiopt(f *Func) {
for _, b := range f.Blocks {
if len(b.Preds) != 2 || len(b.Values) == 0 {
+ // TODO: handle more than 2 predecessors, e.g. a || b || c.
continue
}
@@ -45,44 +46,67 @@ func phiopt(f *Func) {
}
// b0 is the if block giving the boolean value.
- var reverse bool
+ // reverse is the predecessor from which the truth value comes.
+ var reverse int
if b0.Succs[0] == pb0 && b0.Succs[1] == pb1 {
- reverse = false
+ reverse = 0
} else if b0.Succs[0] == pb1 && b0.Succs[1] == pb0 {
- reverse = true
+ reverse = 1
} else {
b.Fatalf("invalid predecessors\n")
}
for _, v := range b.Values {
- if v.Op != OpPhi || !v.Type.IsBoolean() || v.Args[0].Op != OpConstBool || v.Args[1].Op != OpConstBool {
+ if v.Op != OpPhi || !v.Type.IsBoolean() {
continue
}
- ok, isCopy := false, false
- if v.Args[0].AuxInt == 1 && v.Args[1].AuxInt == 0 {
- ok, isCopy = true, !reverse
- } else if v.Args[0].AuxInt == 0 && v.Args[1].AuxInt == 1 {
- ok, isCopy = true, reverse
+ // Replaces
+ // if a { x = true } else { x = false } with x = a
+ // and
+ // if a { x = false } else { x = true } with x = !a
+ if v.Args[0].Op == OpConstBool && v.Args[1].Op == OpConstBool {
+ if v.Args[reverse].AuxInt != v.Args[1-reverse].AuxInt {
+ ops := [2]Op{OpNot, OpCopy}
+ v.reset(ops[v.Args[reverse].AuxInt])
+ v.AddArg(b0.Control)
+ if f.pass.debug > 0 {
+ f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
+ }
+ continue
+ }
}
- // (Phi (ConstBool [x]) (ConstBool [x])) is already handled by opt / phielim.
-
- if ok && isCopy {
- if f.pass.debug > 0 {
- f.Config.Warnl(b.Line, "converted OpPhi to OpCopy")
+ // Replaces
+ // if a { x = true } else { x = value } with x = a || value.
+ // Requires that value dominates x, meaning that regardless of a,
+ // value is always computed. This guarantees that the side effects
+ // of value are not seen if a is false.
+ if v.Args[reverse].Op == OpConstBool && v.Args[reverse].AuxInt == 1 {
+ if tmp := v.Args[1-reverse]; f.sdom.isAncestorEq(tmp.Block, b) {
+ v.reset(OpOrB)
+ v.SetArgs2(b0.Control, tmp)
+ if f.pass.debug > 0 {
+ f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
+ }
+ continue
}
- v.reset(OpCopy)
- v.AddArg(b0.Control)
- continue
}
- if ok && !isCopy {
- if f.pass.debug > 0 {
- f.Config.Warnl(b.Line, "converted OpPhi to OpNot")
+
+ // Replaces
+ // if a { x = value } else { x = false } with x = a && value.
+ // Requires that value dominates x, meaning that regardless of a,
+ // value is always computed. This guarantees that the side effects
+ // of value are not seen if a is false.
+ if v.Args[1-reverse].Op == OpConstBool && v.Args[1-reverse].AuxInt == 0 {
+ if tmp := v.Args[reverse]; f.sdom.isAncestorEq(tmp.Block, b) {
+ v.reset(OpAndB)
+ v.SetArgs2(b0.Control, tmp)
+ if f.pass.debug > 0 {
+ f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
+ }
+ continue
}
- v.reset(OpNot)
- v.AddArg(b0.Control)
- continue
}
}
}
diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go
index a12a996263..f4a10b508a 100644
--- a/src/cmd/compile/internal/ssa/prove.go
+++ b/src/cmd/compile/internal/ssa/prove.go
@@ -445,9 +445,6 @@ var (
// else branch of the first comparison is executed, we already know that i < len(a).
// The code for the second panic can be removed.
func prove(f *Func) {
- idom := dominators(f)
- sdom := newSparseTree(f, idom)
-
// current node state
type walkState int
const (
@@ -471,8 +468,8 @@ func prove(f *Func) {
for len(work) > 0 {
node := work[len(work)-1]
work = work[:len(work)-1]
- parent := idom[node.block.ID]
- branch := getBranch(sdom, parent, node.block)
+ parent := f.idom[node.block.ID]
+ branch := getBranch(f.sdom, parent, node.block)
switch node.state {
case descend:
@@ -491,7 +488,7 @@ func prove(f *Func) {
block: node.block,
state: simplify,
})
- for s := sdom.Child(node.block); s != nil; s = sdom.Sibling(s) {
+ for s := f.sdom.Child(node.block); s != nil; s = f.sdom.Sibling(s) {
work = append(work, bp{
block: s,
state: descend,
diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go
index 22b9d12c19..65c25dfc5a 100644
--- a/src/cmd/compile/internal/ssa/regalloc.go
+++ b/src/cmd/compile/internal/ssa/regalloc.go
@@ -91,6 +91,18 @@
// will have no use (so don't run deadcode after regalloc!).
// TODO: maybe we should introduce these extra phis?
+// Additional not-quite-SSA output occurs when spills are sunk out
+// of loops to the targets of exit edges from the loop. Before sinking,
+// there is one spill site (one StoreReg) targeting stack slot X, after
+// sinking there may be multiple spill sites targeting stack slot X,
+// with no phi functions at any join points reachable by the multiple
+// spill sites. In addition, uses of the spill from copies of the original
+// will not name the copy in their reference; instead they will name
+// the original, though both will have the same spill location. The
+// first sunk spill will be the original, but moved, to an exit block,
+// thus ensuring that there is a definition somewhere corresponding to
+// the original spill's uses.
+
package ssa
import (
@@ -100,7 +112,8 @@ import (
)
const (
- logSpills = iota
+ moveSpills = iota
+ logSpills
regDebug
stackDebug
)
@@ -176,10 +189,9 @@ type valState struct {
uses *use // list of uses in this block
spill *Value // spilled copy of the Value
spillUsed bool
- needReg bool // cached value of !v.Type.IsMemory() && !v.Type.IsVoid() && !.v.Type.IsFlags()
- rematerializeable bool // cached value of v.rematerializeable()
- desired register // register we want value to be in, if any
- avoid regMask // registers to avoid if we can
+ spillUsedShuffle bool // true if used in shuffling, after ordinary uses
+ needReg bool // cached value of !v.Type.IsMemory() && !v.Type.IsVoid() && !.v.Type.IsFlags()
+ rematerializeable bool // cached value of v.rematerializeable()
}
type regState struct {
@@ -191,10 +203,11 @@ type regState struct {
type regAllocState struct {
f *Func
- registers []Register
- numRegs register
- SPReg register
- SBReg register
+ registers []Register
+ numRegs register
+ SPReg register
+ SBReg register
+ allocatable regMask
// for each block, its primary predecessor.
// A predecessor of b is primary if it is the closest
@@ -206,6 +219,11 @@ type regAllocState struct {
// which are live at the end of b, together with a count of how many instructions
// forward to the next use.
live [][]liveInfo
+ // desired register assignments at the end of each block.
+ // Note that this is a static map computed before allocation occurs. Dynamic
+ // register desires (from partially completed allocations) will trump
+ // this information.
+ desired []desiredState
// current state of each (preregalloc) Value
values []valState
@@ -243,6 +261,15 @@ type regAllocState struct {
loopnest *loopnest
}
+type spillToSink struct {
+ spill *Value // Spill instruction to move (a StoreReg)
+ dests int32 // Bitmask indicating exit blocks from loop in which spill/val is defined. 1<<i set means val is live into loop.exitBlocks[i]
+}
+
+func (sts *spillToSink) spilledValue() *Value {
+ return sts.spill.Args[0]
+}
+
type endReg struct {
r register
v *Value // pre-regalloc value held in this register (TODO: can we use ID here?)
@@ -310,6 +337,7 @@ func (s *regAllocState) assignReg(r register, v *Value, c *Value) {
// If there is no unused register, a Value will be kicked out of
// a register to make room.
func (s *regAllocState) allocReg(v *Value, mask regMask) register {
+ mask &= s.allocatable
mask &^= s.nospill
if mask == 0 {
s.f.Fatalf("no register available")
@@ -317,20 +345,7 @@ func (s *regAllocState) allocReg(v *Value, mask regMask) register {
// Pick an unused register if one is available.
if mask&^s.used != 0 {
- mask &^= s.used
-
- // Use desired register if we can.
- d := s.values[v.ID].desired
- if d != noRegister && mask>>d&1 != 0 {
- mask = regMask(1) << d
- }
-
- // Avoid avoidable registers if we can.
- if mask&^s.values[v.ID].avoid != 0 {
- mask &^= s.values[v.ID].avoid
- }
-
- return pickReg(mask)
+ return pickReg(mask &^ s.used)
}
// Pick a value to spill. Spill the value with the
@@ -340,10 +355,6 @@ func (s *regAllocState) allocReg(v *Value, mask regMask) register {
// TODO: if a single value is in multiple registers, spill one of them
// before spilling a value in just a single register.
- // SP and SB are allocated specially. No regular value should
- // be allocated to them.
- mask &^= 1<<s.SPReg | 1<<s.SBReg
-
// Find a register to spill. We spill the register containing the value
// whose next use is as far in the future as possible.
// https://en.wikipedia.org/wiki/Page_replacement_algorithm#The_theoretically_optimal_page_replacement_algorithm
@@ -389,14 +400,6 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
return s.regs[r].c
}
- if v.Op != OpSP {
- mask &^= 1 << s.SPReg // dont' spill SP
- }
- if v.Op != OpSB {
- mask &^= 1 << s.SBReg // don't spill SB
- }
- mask &^= s.reserved()
-
// Allocate a register.
r := s.allocReg(v, mask)
@@ -417,7 +420,7 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
// Load v from its spill location.
case vi.spill != nil:
if s.f.pass.debug > logSpills {
- s.f.Config.Warnl(vi.spill.Line, "load spill")
+ s.f.Config.Warnl(vi.spill.Line, "load spill for %v from %v", v, vi.spill)
}
c = s.curBlock.NewValue1(line, OpLoadReg, v.Type, vi.spill)
vi.spillUsed = true
@@ -434,6 +437,7 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
}
func (s *regAllocState) init(f *Func) {
+ s.f = f
s.registers = f.Config.registers
s.numRegs = register(len(s.registers))
if s.numRegs > noRegister || s.numRegs > register(unsafe.Sizeof(regMask(0))*8) {
@@ -448,7 +452,17 @@ func (s *regAllocState) init(f *Func) {
}
}
- s.f = f
+ // Figure out which registers we're allowed to use.
+ s.allocatable = regMask(1)<<s.numRegs - 1
+ s.allocatable &^= 1 << s.SPReg
+ s.allocatable &^= 1 << s.SBReg
+ if obj.Framepointer_enabled != 0 {
+ s.allocatable &^= 1 << 5 // BP
+ }
+ if s.f.Config.ctxt.Flag_dynlink {
+ s.allocatable &^= 1 << 15 // R15
+ }
+
s.regs = make([]regState, s.numRegs)
s.values = make([]valState, f.NumValues())
s.orig = make([]*Value, f.NumValues())
@@ -457,7 +471,6 @@ func (s *regAllocState) init(f *Func) {
if !v.Type.IsMemory() && !v.Type.IsVoid() && !v.Type.IsFlags() {
s.values[v.ID].needReg = true
s.values[v.ID].rematerializeable = v.rematerializeable()
- s.values[v.ID].desired = noRegister
s.orig[v.ID] = v
}
}
@@ -527,6 +540,18 @@ func (s *regAllocState) advanceUses(v *Value) {
}
}
+// liveAfterCurrentInstruction reports whether v is live after
+// the current instruction is completed. v must be used by the
+// current instruction.
+func (s *regAllocState) liveAfterCurrentInstruction(v *Value) bool {
+ u := s.values[v.ID].uses
+ d := u.dist
+ for u != nil && u.dist == d {
+ u = u.next
+ }
+ return u != nil && u.dist > d
+}
+
// Sets the state of the registers to that encoded in regs.
func (s *regAllocState) setState(regs []endReg) {
s.freeRegs(s.used)
@@ -541,9 +566,25 @@ func (s *regAllocState) compatRegs(t Type) regMask {
if t.IsFloat() || t == TypeInt128 {
m = 0xffff << 16 // X0-X15
} else {
- m = 0xffef << 0 // AX-R15, except SP
+ m = 0xffff << 0 // AX-R15
+ }
+ return m & s.allocatable
+}
+
+// loopForBlock returns the loop containing block b,
+// provided that the loop is "interesting" for purposes
+// of improving register allocation (= is inner, and does
+// not contain a call)
+func (s *regAllocState) loopForBlock(b *Block) *loop {
+ loop := s.loopnest.b2l[b.ID]
+
+ // Minor for-the-time-being optimization: nothing happens
+ // unless a loop is both inner and call-free, therefore
+ // don't bother with other loops.
+ if loop != nil && (loop.containsCall || !loop.isInner) {
+ loop = nil
}
- return m &^ s.reserved()
+ return loop
}
func (s *regAllocState) regalloc(f *Func) {
@@ -554,12 +595,46 @@ func (s *regAllocState) regalloc(f *Func) {
var phiRegs []register
var args []*Value
+ // statistics
+ var nSpills int // # of spills remaining
+ var nSpillsInner int // # of spills remaining in inner loops
+ var nSpillsSunk int // # of sunk spills remaining
+ var nSpillsChanged int // # of sunk spills lost because of register use change
+ var nSpillsSunkUnused int // # of spills not sunk because they were removed completely
+ var nSpillsNotSunkLateUse int // # of spills not sunk because of very late use (in shuffle)
+
+ // Data structure used for computing desired registers.
+ var desired desiredState
+
+ // Desired registers for inputs & outputs for each instruction in the block.
+ type dentry struct {
+ out [4]register // desired output registers
+ in [3][4]register // desired input registers (for inputs 0,1, and 2)
+ }
+ var dinfo []dentry
+
if f.Entry != f.Blocks[0] {
f.Fatalf("entry block must be first")
}
+ // Get loop nest so that spills in inner loops can be
+ // tracked. When the last block of a loop is processed,
+ // attempt to move spills out of the loop.
+ s.loopnest.findExits()
+
+ // Spills are moved from one block's slice of values to another's.
+ // This confuses register allocation if it occurs before it is
+ // complete, so candidates are recorded, then rechecked and
+ // moved after all allocation (register and stack) is complete.
+ // Because movement is only within a stack slot's lifetime, it
+ // is safe to do this.
+ var toSink []spillToSink
+ // Will be used to figure out live inputs to exit blocks of inner loops.
+ entryCandidates := newSparseMap(f.NumValues())
+
for _, b := range f.Blocks {
s.curBlock = b
+ loop := s.loopForBlock(b)
// Initialize liveSet and uses fields for this block.
// Walk backwards through the block doing liveness analysis.
@@ -739,6 +814,11 @@ func (s *regAllocState) regalloc(f *Func) {
s.setOrig(spill, v)
s.values[v.ID].spill = spill
s.values[v.ID].spillUsed = false
+ if loop != nil {
+ loop.spills = append(loop.spills, v)
+ nSpillsInner++
+ }
+ nSpills++
}
// Save the starting state for use by merge edges.
@@ -765,26 +845,27 @@ func (s *regAllocState) regalloc(f *Func) {
}
}
- // Compute preferred registers for each value using a backwards pass.
+ // Allocate space to record the desired registers for each value.
+ dinfo = dinfo[:0]
+ for i := 0; i < len(oldSched); i++ {
+ dinfo = append(dinfo, dentry{})
+ }
+
+ // Load static desired register info at the end of the block.
+ desired.copy(&s.desired[b.ID])
+
+ // Check actual assigned registers at the start of the next block(s).
+ // Dynamically assigned registers will trump the static
+ // desired registers computed during liveness analysis.
// Note that we do this phase after startRegs is set above, so that
// we get the right behavior for a block which branches to itself.
for _, succ := range b.Succs {
- // TODO: prioritize likely successor.
+ // TODO: prioritize likely successor?
for _, x := range s.startRegs[succ.ID] {
- v := s.orig[x.vid]
- s.values[v.ID].desired = x.r
- }
- // Process phi ops in succ
- i := -1
- for j, p := range succ.Preds {
- if p == b {
- i = j
- break
- }
- }
- if i == -1 {
- s.f.Fatalf("can't find predecssor %s of %s\n", b, succ)
+ desired.add(x.vid, x.r)
}
+ // Process phi ops in succ.
+ pidx := predIdx(succ, b)
for _, v := range succ.Values {
if v.Op != OpPhi {
break
@@ -792,47 +873,44 @@ func (s *regAllocState) regalloc(f *Func) {
if !s.values[v.ID].needReg {
continue
}
- r, ok := s.f.getHome(v.ID).(*Register)
+ rp, ok := s.f.getHome(v.ID).(*Register)
if !ok {
continue
}
- a := s.orig[v.Args[i].ID]
- s.values[a.ID].desired = register(r.Num)
+ desired.add(v.Args[pidx].ID, register(rp.Num))
}
}
-
- // Set avoid fields to help desired register availability.
- liveSet.clear()
- for _, e := range s.live[b.ID] {
- liveSet.add(e.ID)
- }
- if v := b.Control; v != nil && s.values[v.ID].needReg {
- liveSet.add(v.ID)
- }
+ // Walk values backwards computing desired register info.
+ // See computeLive for more comments.
for i := len(oldSched) - 1; i >= 0; i-- {
v := oldSched[i]
- liveSet.remove(v.ID)
-
- r := s.values[v.ID].desired
- if r != noRegister {
- m := regMask(1) << r
- // All live values should avoid this register so
- // it will be available at this point.
- for _, w := range liveSet.contents() {
- s.values[w].avoid |= m
+ prefs := desired.remove(v.ID)
+ desired.clobber(opcodeTable[v.Op].reg.clobbers)
+ for _, j := range opcodeTable[v.Op].reg.inputs {
+ if countRegs(j.regs) != 1 {
+ continue
}
+ desired.clobber(j.regs)
+ desired.add(v.Args[j.idx].ID, pickReg(j.regs))
}
-
- for _, a := range v.Args {
- if !s.values[a.ID].needReg {
- continue
+ if opcodeTable[v.Op].resultInArg0 {
+ if opcodeTable[v.Op].commutative {
+ desired.addList(v.Args[1].ID, prefs)
}
- liveSet.add(a.ID)
+ desired.addList(v.Args[0].ID, prefs)
+ }
+ // Save desired registers for this value.
+ dinfo[i].out = prefs
+ for j, a := range v.Args {
+ if j >= len(dinfo[i].in) {
+ break
+ }
+ dinfo[i].in[j] = desired.get(a.ID)
}
}
// Process all the non-phi values.
- for _, v := range oldSched {
+ for idx, v := range oldSched {
if s.f.pass.debug > regDebug {
fmt.Printf(" processing %s\n", v.LongString())
}
@@ -880,15 +958,132 @@ func (s *regAllocState) regalloc(f *Func) {
continue
}
+ if s.f.pass.debug > regDebug {
+ fmt.Printf("value %s\n", v.LongString())
+ fmt.Printf(" out:")
+ for _, r := range dinfo[idx].out {
+ if r != noRegister {
+ fmt.Printf(" %s", s.registers[r].Name())
+ }
+ }
+ fmt.Println()
+ for i := 0; i < len(v.Args) && i < 3; i++ {
+ fmt.Printf(" in%d:", i)
+ for _, r := range dinfo[idx].in[i] {
+ if r != noRegister {
+ fmt.Printf(" %s", s.registers[r].Name())
+ }
+ }
+ fmt.Println()
+ }
+ }
+
// Move arguments to registers. Process in an ordering defined
// by the register specification (most constrained first).
args = append(args[:0], v.Args...)
for _, i := range regspec.inputs {
- if i.regs == flagRegMask {
+ mask := i.regs
+ if mask == flagRegMask {
// TODO: remove flag input from regspec.inputs.
continue
}
- args[i.idx] = s.allocValToReg(v.Args[i.idx], i.regs, true, v.Line)
+ if mask&s.values[args[i.idx].ID].regs == 0 {
+ // Need a new register for the input.
+ mask &= s.allocatable
+ mask &^= s.nospill
+ // Used desired register if available.
+ if i.idx < 3 {
+ for _, r := range dinfo[idx].in[i.idx] {
+ if r != noRegister && (mask&^s.used)>>r&1 != 0 {
+ // Desired register is allowed and unused.
+ mask = regMask(1) << r
+ break
+ }
+ }
+ }
+ // Avoid registers we're saving for other values.
+ if mask&^desired.avoid != 0 {
+ mask &^= desired.avoid
+ }
+ }
+ args[i.idx] = s.allocValToReg(args[i.idx], mask, true, v.Line)
+ }
+
+ // If the output clobbers the input register, make sure we have
+ // at least two copies of the input register so we don't
+ // have to reload the value from the spill location.
+ if opcodeTable[v.Op].resultInArg0 {
+ var m regMask
+ if !s.liveAfterCurrentInstruction(v.Args[0]) {
+ // arg0 is dead. We can clobber its register.
+ goto ok
+ }
+ if countRegs(s.values[v.Args[0].ID].regs) >= 2 {
+ // we have at least 2 copies of arg0. We can afford to clobber one.
+ goto ok
+ }
+ if opcodeTable[v.Op].commutative {
+ if !s.liveAfterCurrentInstruction(v.Args[1]) {
+ args[0], args[1] = args[1], args[0]
+ goto ok
+ }
+ if countRegs(s.values[v.Args[1].ID].regs) >= 2 {
+ args[0], args[1] = args[1], args[0]
+ goto ok
+ }
+ }
+
+ // We can't overwrite arg0 (or arg1, if commutative). So we
+ // need to make a copy of an input so we have a register we can modify.
+
+ // Possible new registers to copy into.
+ m = s.compatRegs(v.Args[0].Type) &^ s.used
+ if m == 0 {
+ // No free registers. In this case we'll just clobber
+ // an input and future uses of that input must use a restore.
+ // TODO(khr): We should really do this like allocReg does it,
+ // spilling the value with the most distant next use.
+ goto ok
+ }
+
+ // Try to move an input to the desired output.
+ for _, r := range dinfo[idx].out {
+ if r != noRegister && m>>r&1 != 0 {
+ m = regMask(1) << r
+ args[0] = s.allocValToReg(v.Args[0], m, true, v.Line)
+ // Note: we update args[0] so the instruction will
+ // use the register copy we just made.
+ goto ok
+ }
+ }
+ // Try to copy input to its desired location & use its old
+ // location as the result register.
+ for _, r := range dinfo[idx].in[0] {
+ if r != noRegister && m>>r&1 != 0 {
+ m = regMask(1) << r
+ s.allocValToReg(v.Args[0], m, true, v.Line)
+ // Note: no update to args[0] so the instruction will
+ // use the original copy.
+ goto ok
+ }
+ }
+ if opcodeTable[v.Op].commutative {
+ for _, r := range dinfo[idx].in[1] {
+ if r != noRegister && m>>r&1 != 0 {
+ m = regMask(1) << r
+ s.allocValToReg(v.Args[1], m, true, v.Line)
+ args[0], args[1] = args[1], args[0]
+ goto ok
+ }
+ }
+ }
+ // Avoid future fixed uses if we can.
+ if m&^desired.avoid != 0 {
+ m &^= desired.avoid
+ }
+ // Save input 0 to a new register so we can clobber it.
+ s.allocValToReg(v.Args[0], m, true, v.Line)
+ ok:
}
// Now that all args are in regs, we're ready to issue the value itself.
@@ -903,24 +1098,44 @@ func (s *regAllocState) regalloc(f *Func) {
// Pick register for output.
if s.values[v.ID].needReg {
- mask := regspec.outputs[0] &^ s.reserved()
- if mask>>33&1 != 0 {
- s.f.Fatalf("bad mask %s\n", v.LongString())
- }
+ mask := regspec.outputs[0] & s.allocatable
if opcodeTable[v.Op].resultInArg0 {
- r := register(s.f.getHome(args[0].ID).(*Register).Num)
- if (mask&^s.used)>>r&1 != 0 {
+ if !opcodeTable[v.Op].commutative {
+ // Output must use the same register as input 0.
+ r := register(s.f.getHome(args[0].ID).(*Register).Num)
mask = regMask(1) << r
- }
- if opcodeTable[v.Op].commutative {
- r := register(s.f.getHome(args[1].ID).(*Register).Num)
- if (mask&^s.used)>>r&1 != 0 {
- mask = regMask(1) << r
+ } else {
+ // Output must use the same register as input 0 or 1.
+ r0 := register(s.f.getHome(args[0].ID).(*Register).Num)
+ r1 := register(s.f.getHome(args[1].ID).(*Register).Num)
+ // Check r0 and r1 for desired output register.
+ found := false
+ for _, r := range dinfo[idx].out {
+ if (r == r0 || r == r1) && (mask&^s.used)>>r&1 != 0 {
+ mask = regMask(1) << r
+ found = true
+ if r == r1 {
+ args[0], args[1] = args[1], args[0]
+ }
+ break
+ }
+ }
+ if !found {
+ // Neither are desired, pick r0.
+ mask = regMask(1) << r0
}
}
- // TODO: enforce resultInArg0 always, instead of treating it
- // as a hint. Then we don't need the special cases adding
- // moves all throughout ssa.go:genValue.
+ }
+ for _, r := range dinfo[idx].out {
+ if r != noRegister && (mask&^s.used)>>r&1 != 0 {
+ // Desired register is allowed and unused.
+ mask = regMask(1) << r
+ break
+ }
+ }
+ // Avoid registers we're saving for other values.
+ if mask&^desired.avoid != 0 {
+ mask &^= desired.avoid
}
r := s.allocReg(v, mask)
s.assignReg(r, v, v)
@@ -947,6 +1162,11 @@ func (s *regAllocState) regalloc(f *Func) {
s.setOrig(spill, v)
s.values[v.ID].spill = spill
s.values[v.ID].spillUsed = false
+ if loop != nil {
+ loop.spills = append(loop.spills, v)
+ nSpillsInner++
+ }
+ nSpills++
}
}
@@ -993,6 +1213,9 @@ func (s *regAllocState) regalloc(f *Func) {
}
v := s.orig[vid]
m := s.compatRegs(v.Type) &^ s.used
+ if m&^desired.avoid != 0 {
+ m &^= desired.avoid
+ }
if m != 0 {
s.allocValToReg(v, m, false, b.Line)
}
@@ -1056,6 +1279,69 @@ func (s *regAllocState) regalloc(f *Func) {
s.values[e.ID].spillUsed = true
}
+ // Keep track of values that are spilled in the loop, but whose spill
+ // is not used in the loop. It may be possible to move ("sink") the
+ // spill out of the loop into one or more exit blocks.
+ if loop != nil {
+ loop.scratch++ // increment count of blocks in this loop that have been processed
+ if loop.scratch == loop.nBlocks { // just processed last block of loop, if it is an inner loop.
+ // This check is redundant with code at the top of the loop.
+ // This is definitive; the one at the top of the loop is an optimization.
+ if loop.isInner && // Common case, easier, most likely to be profitable
+ !loop.containsCall && // Calls force spills, also lead to puzzling spill info.
+ len(loop.exits) <= 32 { // Almost no inner loops have more than 32 exits,
+ // and this allows use of a bitvector and a sparseMap.
+
+ // TODO: exit calculation is messed up for non-inner loops
+ // because of multilevel exits that are not part of the "exit"
+ // count.
+
+ // Compute the set of spill-movement candidates live at entry to exit blocks.
+ // isLoopSpillCandidate filters for
+ // (1) defined in appropriate loop
+ // (2) needs a register
+ // (3) spill not already used (in the loop)
+ // Condition (3) === "in a register at all loop exits"
+
+ entryCandidates.clear()
+
+ for whichExit, ss := range loop.exits {
+ // Start with live at end.
+ for _, li := range s.live[ss.ID] {
+ if s.isLoopSpillCandidate(loop, s.orig[li.ID]) {
+ entryCandidates.setBit(li.ID, uint(whichExit))
+ }
+ }
+ // Control can also be live.
+ if ss.Control != nil && s.isLoopSpillCandidate(loop, ss.Control) {
+ entryCandidates.setBit(ss.Control.ID, uint(whichExit))
+ }
+ // Walk backwards, filling in locally live values, removing those defined.
+ for i := len(ss.Values) - 1; i >= 0; i-- {
+ v := ss.Values[i]
+ entryCandidates.remove(v.ID) // Cannot be an issue, only keeps the sets smaller.
+ for _, a := range v.Args {
+ if s.isLoopSpillCandidate(loop, a) {
+ entryCandidates.setBit(a.ID, uint(whichExit))
+ }
+ }
+ }
+ }
+
+ for _, e := range loop.spills {
+ whichblocks := entryCandidates.get(e.ID)
+ oldSpill := s.values[e.ID].spill
+ if whichblocks != 0 && whichblocks != -1 { // -1 = not in map.
+ toSink = append(toSink, spillToSink{spill: oldSpill, dests: whichblocks})
+ }
+ }
+
+ } // loop is inner etc
+ loop.scratch = 0 // Don't leave a mess, just in case.
+ loop.spills = nil
+ } // if scratch == nBlocks
+ } // if loop is not nil
+
// Clear any final uses.
// All that is left should be the pseudo-uses added for values which
// are live at the end of b.
@@ -1078,7 +1364,7 @@ func (s *regAllocState) regalloc(f *Func) {
vi := s.values[i]
if vi.spillUsed {
if s.f.pass.debug > logSpills {
- s.f.Config.Warnl(vi.spill.Line, "spilled value")
+ s.f.Config.Warnl(vi.spill.Line, "spilled value at %v remains", vi.spill)
}
continue
}
@@ -1087,9 +1373,16 @@ func (s *regAllocState) regalloc(f *Func) {
// Constants, SP, SB, ...
continue
}
+ loop := s.loopForBlock(spill.Block)
+ if loop != nil {
+ nSpillsInner--
+ }
+
spill.Args[0].Uses--
f.freeValue(spill)
+ nSpills--
}
+
for _, b := range f.Blocks {
i := 0
for _, v := range b.Values {
@@ -1104,12 +1397,161 @@ func (s *regAllocState) regalloc(f *Func) {
// Not important now because this is the last phase that manipulates Values
}
+ // Must clear these out before any potential recycling, though that's
+ // not currently implemented.
+ for i, ts := range toSink {
+ vsp := ts.spill
+ if vsp.Op == OpInvalid { // This spill was completely eliminated
+ toSink[i].spill = nil
+ }
+ }
+
// Anything that didn't get a register gets a stack location here.
// (StoreReg, stack-based phis, inputs, ...)
stacklive := stackalloc(s.f, s.spillLive)
// Fix up all merge edges.
s.shuffle(stacklive)
+
+ // Insert moved spills (that have not been marked invalid above)
+ // at start of appropriate block and remove the originals from their
+ // location within loops. Notice that this can break SSA form;
+ // if a spill is sunk to multiple exits, there will be no phi for that
+ // spill at a join point downstream of those two exits, though the
+ // two spills will target the same stack slot. Notice also that this
+ // takes place after stack allocation, so the stack allocator does
+ // not need to process these malformed flow graphs.
+sinking:
+ for _, ts := range toSink {
+ vsp := ts.spill
+ if vsp == nil { // This spill was completely eliminated
+ nSpillsSunkUnused++
+ continue sinking
+ }
+ e := ts.spilledValue()
+ if s.values[e.ID].spillUsedShuffle {
+ nSpillsNotSunkLateUse++
+ continue sinking
+ }
+
+ // move spills to a better (outside of loop) block.
+ // This would be costly if it occurred very often, but it doesn't.
+ b := vsp.Block
+ loop := s.loopnest.b2l[b.ID]
+ dests := ts.dests
+
+ // Pre-check to be sure that spilled value is still in expected register on all exits where live.
+ check_val_still_in_reg:
+ for i := uint(0); i < 32 && dests != 0; i++ {
+
+ if dests&(1<<i) == 0 {
+ continue
+ }
+ dests ^= 1 << i
+ d := loop.exits[i]
+ if len(d.Preds) > 1 {
+ panic("Should be impossible given critical edges removed")
+ }
+ p := d.Preds[0] // block in loop exiting to d.
+
+ endregs := s.endRegs[p.ID]
+ for _, regrec := range endregs {
+ if regrec.v == e && regrec.r != noRegister && regrec.c == e { // TODO: regrec.c != e implies different spill possible.
+ continue check_val_still_in_reg
+ }
+ }
+ // If here, the register assignment was lost down at least one exit and it can't be sunk
+ if s.f.pass.debug > moveSpills {
+ s.f.Config.Warnl(e.Line, "lost register assignment for spill %v in %v at exit %v to %v",
+ vsp, b, p, d)
+ }
+ nSpillsChanged++
+ continue sinking
+ }
+
+ nSpillsSunk++
+ nSpillsInner--
+ // don't update nSpills, since spill is only moved, and if it is duplicated, the spills-on-a-path is not increased.
+
+ dests = ts.dests
+
+ // remove vsp from b.Values
+ i := 0
+ for _, w := range b.Values {
+ if vsp == w {
+ continue
+ }
+ b.Values[i] = w
+ i++
+ }
+ b.Values = b.Values[:i]
+
+ first := true
+ for i := uint(0); i < 32 && dests != 0; i++ {
+
+ if dests&(1<<i) == 0 {
+ continue
+ }
+
+ dests ^= 1 << i
+
+ d := loop.exits[i]
+ vspnew := vsp // reuse original for first sunk spill, saves tracking down and renaming uses
+ if !first { // any sunk spills after first must make a copy
+ vspnew = d.NewValue1(e.Line, OpStoreReg, e.Type, e)
+ f.setHome(vspnew, f.getHome(vsp.ID)) // copy stack home
+ if s.f.pass.debug > moveSpills {
+ s.f.Config.Warnl(e.Line, "copied spill %v in %v for %v to %v in %v",
+ vsp, b, e, vspnew, d)
+ }
+ } else {
+ first = false
+ vspnew.Block = d
+ d.Values = append(d.Values, vspnew)
+ if s.f.pass.debug > moveSpills {
+ s.f.Config.Warnl(e.Line, "moved spill %v in %v for %v to %v in %v",
+ vsp, b, e, vspnew, d)
+ }
+ }
+
+ // shuffle vspnew to the beginning of its block
+ copy(d.Values[1:], d.Values[0:len(d.Values)-1])
+ d.Values[0] = vspnew
+
+ }
+ }
+
+ if f.pass.stats > 0 {
+ f.logStat("spills_info",
+ nSpills, "spills", nSpillsInner, "inner_spills_remaining", nSpillsSunk, "inner_spills_sunk", nSpillsSunkUnused, "inner_spills_unused", nSpillsNotSunkLateUse, "inner_spills_shuffled", nSpillsChanged, "inner_spills_changed")
+ }
+}
+
+// isLoopSpillCandidate indicates whether the spill for v satisfies preliminary
+// spill-sinking conditions just after the last block of loop has been processed.
+// In particular:
+// v needs a register.
+// v's spill is not (YET) used.
+// v's definition is within loop.
+// The spill may be used in the future, either by an outright use
+// in the code, or by shuffling code inserted after stack allocation.
+// Outright uses cause sinking; shuffling (within the loop) inhibits it.
+func (s *regAllocState) isLoopSpillCandidate(loop *loop, v *Value) bool {
+ return s.values[v.ID].needReg && !s.values[v.ID].spillUsed && s.loopnest.b2l[v.Block.ID] == loop
+}
+
+// lateSpillUse notes a late (after stack allocation) use of the spill of value with ID vid.
+// This will inhibit spill sinking.
+func (s *regAllocState) lateSpillUse(vid ID) {
+ // TODO investigate why this is necessary.
+ // It appears that an outside-the-loop use of
+ // an otherwise sinkable spill makes the spill
+ // a candidate for shuffling, when it would not
+ // otherwise have been the case (spillUsed was not
+ // true when isLoopSpillCandidate was called, yet
+ // it was shuffled). Such shuffling cuts the amount
+ // of spill sinking by more than half (in make.bash)
+ s.values[vid].spillUsedShuffle = true
}
// shuffle fixes up all the merge edges (those going into blocks of indegree > 1).
@@ -1284,6 +1726,7 @@ func (e *edgeState) process() {
if _, isReg := loc.(*Register); isReg {
c = e.p.NewValue1(c.Line, OpCopy, c.Type, c)
} else {
+ e.s.lateSpillUse(vid)
c = e.p.NewValue1(c.Line, OpLoadReg, c.Type, c)
}
e.set(r, vid, c, false)
@@ -1372,6 +1815,7 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value) bool {
}
} else {
if dstReg {
+ e.s.lateSpillUse(vid)
x = e.p.NewValue1(c.Line, OpLoadReg, c.Type, c)
} else {
// mem->mem. Use temp register.
@@ -1389,6 +1833,7 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value) bool {
e.erase(loc)
r := e.findRegFor(c.Type)
+ e.s.lateSpillUse(vid)
t := e.p.NewValue1(c.Line, OpLoadReg, c.Type, c)
e.set(r, vid, t, false)
x = e.p.NewValue1(c.Line, OpStoreReg, loc.(LocalSlot).Type, t)
@@ -1554,24 +1999,36 @@ func (v *Value) rematerializeable() bool {
}
type liveInfo struct {
- ID ID // ID of variable
+ ID ID // ID of value
dist int32 // # of instructions before next use
}
+// dblock contains information about desired & avoid registers at the end of a block.
+type dblock struct {
+ prefers []desiredStateEntry
+ avoid regMask
+}
+
// computeLive computes a map from block ID to a list of value IDs live at the end
// of that block. Together with the value ID is a count of how many instructions
-// to the next use of that value. The resulting map is stored at s.live.
+// to the next use of that value. The resulting map is stored in s.live.
+// computeLive also computes the desired register information at the end of each block.
+// This desired register information is stored in s.desired.
// TODO: this could be quadratic if lots of variables are live across lots of
// basic blocks. Figure out a way to make this function (or, more precisely, the user
// of this function) require only linear size & time.
func (s *regAllocState) computeLive() {
f := s.f
s.live = make([][]liveInfo, f.NumBlocks())
+ s.desired = make([]desiredState, f.NumBlocks())
var phis []*Value
live := newSparseMap(f.NumValues())
t := newSparseMap(f.NumValues())
+ // Keep track of which value we want in each register.
+ var desired desiredState
+
// Instead of iterating over f.Blocks, iterate over their postordering.
// Liveness information flows backward, so starting at the end
// increases the probability that we will stabilize quickly.
@@ -1594,7 +2051,7 @@ func (s *regAllocState) computeLive() {
d := int32(len(b.Values))
if b.Kind == BlockCall || b.Kind == BlockDefer {
// Because we keep no values in registers across a call,
- // make every use past a call very far away.
+ // make every use past a call appear very far away.
d += unlikelyDistance
}
for _, e := range s.live[b.ID] {
@@ -1623,6 +2080,35 @@ func (s *regAllocState) computeLive() {
}
}
}
+ // Propagate desired registers backwards.
+ desired.copy(&s.desired[b.ID])
+ for i := len(b.Values) - 1; i >= 0; i-- {
+ v := b.Values[i]
+ prefs := desired.remove(v.ID)
+ if v.Op == OpPhi {
+ // TODO: if v is a phi, save desired register for phi inputs.
+ // For now, we just drop it and don't propagate
+ // desired registers back though phi nodes.
+ continue
+ }
+ // Cancel desired registers if they get clobbered.
+ desired.clobber(opcodeTable[v.Op].reg.clobbers)
+ // Update desired registers if there are any fixed register inputs.
+ for _, j := range opcodeTable[v.Op].reg.inputs {
+ if countRegs(j.regs) != 1 {
+ continue
+ }
+ desired.clobber(j.regs)
+ desired.add(v.Args[j.idx].ID, pickReg(j.regs))
+ }
+ // Set desired register of input 0 if this is a 2-operand instruction.
+ if opcodeTable[v.Op].resultInArg0 {
+ if opcodeTable[v.Op].commutative {
+ desired.addList(v.Args[1].ID, prefs)
+ }
+ desired.addList(v.Args[0].ID, prefs)
+ }
+ }
// For each predecessor of b, expand its list of live-at-end values.
// invariant: live contains the values live at the start of b (excluding phi inputs)
@@ -1642,6 +2128,9 @@ func (s *regAllocState) computeLive() {
}
}
+ // Update any desired registers at the end of p.
+ s.desired[p.ID].merge(&desired)
+
// Start t off with the previously known live values at the end of p.
t.clear()
for _, e := range s.live[p.ID] {
@@ -1662,7 +2151,7 @@ func (s *regAllocState) computeLive() {
// simultaneously happening at the start of the block).
for _, v := range phis {
id := v.Args[i].ID
- if s.values[id].needReg && !t.contains(id) || delta < t.get(id) {
+ if s.values[id].needReg && (!t.contains(id) || delta < t.get(id)) {
update = true
t.set(id, delta)
}
@@ -1694,20 +2183,152 @@ func (s *regAllocState) computeLive() {
fmt.Printf(" %s:", b)
for _, x := range s.live[b.ID] {
fmt.Printf(" v%d", x.ID)
+ for _, e := range s.desired[b.ID].entries {
+ if e.ID != x.ID {
+ continue
+ }
+ fmt.Printf("[")
+ first := true
+ for _, r := range e.regs {
+ if r == noRegister {
+ continue
+ }
+ if !first {
+ fmt.Printf(",")
+ }
+ fmt.Print(s.registers[r].Name())
+ first = false
+ }
+ fmt.Printf("]")
+ }
}
+ fmt.Printf(" avoid=%x", int64(s.desired[b.ID].avoid))
fmt.Println()
}
}
}
-// reserved returns a mask of reserved registers.
-func (s *regAllocState) reserved() regMask {
- var m regMask
- if obj.Framepointer_enabled != 0 {
- m |= 1 << 5 // BP
+// A desiredState represents desired register assignments.
+type desiredState struct {
+ // Desired assignments will be small, so we just use a list
+ // of valueID+registers entries.
+ entries []desiredStateEntry
+ // Registers that other values want to be in. This value will
+ // contain at least the union of the regs fields of entries, but
+ // may contain additional entries for values that were once in
+ // this data structure but are no longer.
+ avoid regMask
+}
+type desiredStateEntry struct {
+ // (pre-regalloc) value
+ ID ID
+ // Registers it would like to be in, in priority order.
+ // Unused slots are filled with noRegister.
+ regs [4]register
+}
+
+func (d *desiredState) clear() {
+ d.entries = d.entries[:0]
+ d.avoid = 0
+}
+
+// get returns a list of desired registers for value vid.
+func (d *desiredState) get(vid ID) [4]register {
+ for _, e := range d.entries {
+ if e.ID == vid {
+ return e.regs
+ }
}
- if s.f.Config.ctxt.Flag_dynlink {
- m |= 1 << 15 // R15
+ return [4]register{noRegister, noRegister, noRegister, noRegister}
+}
+
+// add records that we'd like value vid to be in register r.
+func (d *desiredState) add(vid ID, r register) {
+ d.avoid |= regMask(1) << r
+ for i := range d.entries {
+ e := &d.entries[i]
+ if e.ID != vid {
+ continue
+ }
+ if e.regs[0] == r {
+ // Already known and highest priority
+ return
+ }
+ for j := 1; j < len(e.regs); j++ {
+ if e.regs[j] == r {
+ // Move from lower priority to top priority
+ copy(e.regs[1:], e.regs[:j])
+ e.regs[0] = r
+ return
+ }
+ }
+ copy(e.regs[1:], e.regs[:])
+ e.regs[0] = r
+ return
+ }
+ d.entries = append(d.entries, desiredStateEntry{vid, [4]register{r, noRegister, noRegister, noRegister}})
+}
+
+func (d *desiredState) addList(vid ID, regs [4]register) {
+ // regs is in priority order, so iterate in reverse order.
+ for i := len(regs) - 1; i >= 0; i-- {
+ r := regs[i]
+ if r != noRegister {
+ d.add(vid, r)
+ }
+ }
+}
+
+// clobber erases any desired registers in the set m.
+func (d *desiredState) clobber(m regMask) {
+ for i := 0; i < len(d.entries); {
+ e := &d.entries[i]
+ j := 0
+ for _, r := range e.regs {
+ if r != noRegister && m>>r&1 == 0 {
+ e.regs[j] = r
+ j++
+ }
+ }
+ if j == 0 {
+ // No more desired registers for this value.
+ d.entries[i] = d.entries[len(d.entries)-1]
+ d.entries = d.entries[:len(d.entries)-1]
+ continue
+ }
+ for ; j < len(e.regs); j++ {
+ e.regs[j] = noRegister
+ }
+ i++
+ }
+ d.avoid &^= m
+}
+
+// copy copies a desired state from another desiredState x.
+func (d *desiredState) copy(x *desiredState) {
+ d.entries = append(d.entries[:0], x.entries...)
+ d.avoid = x.avoid
+}
+
+// remove removes the desired registers for vid and returns them.
+func (d *desiredState) remove(vid ID) [4]register {
+ for i := range d.entries {
+ if d.entries[i].ID == vid {
+ regs := d.entries[i].regs
+ d.entries[i] = d.entries[len(d.entries)-1]
+ d.entries = d.entries[:len(d.entries)-1]
+ return regs
+ }
+ }
+ return [4]register{noRegister, noRegister, noRegister, noRegister}
+}
+
+// merge merges another desired state x into d.
+func (d *desiredState) merge(x *desiredState) {
+ d.avoid |= x.avoid
+ // There should only be a few desired registers, so
+ // linear insert is ok.
+ for _, e := range x.entries {
+ d.addList(e.ID, e.regs)
}
- return m
}
diff --git a/src/cmd/compile/internal/ssa/regalloc_test.go b/src/cmd/compile/internal/ssa/regalloc_test.go
index 6f3f690f1e..cf8f452d12 100644
--- a/src/cmd/compile/internal/ssa/regalloc_test.go
+++ b/src/cmd/compile/internal/ssa/regalloc_test.go
@@ -11,8 +11,8 @@ func TestLiveControlOps(t *testing.T) {
f := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, nil),
- Valu("x", OpAMD64MOVBconst, TypeInt8, 1, nil),
- Valu("y", OpAMD64MOVBconst, TypeInt8, 2, nil),
+ Valu("x", OpAMD64MOVLconst, TypeInt8, 1, nil),
+ Valu("y", OpAMD64MOVLconst, TypeInt8, 2, nil),
Valu("a", OpAMD64TESTB, TypeFlags, 0, nil, "x", "y"),
Valu("b", OpAMD64TESTB, TypeFlags, 0, nil, "y", "x"),
Eq("a", "if", "exit"),
diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
index e0cb7f517b..e9b408a86c 100644
--- a/src/cmd/compile/internal/ssa/rewrite.go
+++ b/src/cmd/compile/internal/ssa/rewrite.go
@@ -40,9 +40,44 @@ func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool)
}
curb = nil
for _, v := range b.Values {
- change = copyelimValue(v) || change
change = phielimValue(v) || change
+ // Eliminate copy inputs.
+ // If any copy input becomes unused, mark it
+ // as invalid and discard its argument. Repeat
+ // recursively on the discarded argument.
+ // This phase helps remove phantom "dead copy" uses
+ // of a value so that a x.Uses==1 rule condition
+ // fires reliably.
+ for i, a := range v.Args {
+ if a.Op != OpCopy {
+ continue
+ }
+ x := a.Args[0]
+ // Rewriting can generate OpCopy loops.
+ // They are harmless (see removePredecessor),
+ // but take care to stop if we find a cycle.
+ slow := x // advances every other iteration
+ var advance bool
+ for x.Op == OpCopy {
+ x = x.Args[0]
+ if slow == x {
+ break
+ }
+ if advance {
+ slow = slow.Args[0]
+ }
+ advance = !advance
+ }
+ v.SetArg(i, x)
+ change = true
+ for a.Uses == 0 {
+ b := a.Args[0]
+ a.reset(OpInvalid)
+ a = b
+ }
+ }
+
// apply rewrite function
curv = v
if rv(v, config) {
@@ -52,7 +87,28 @@ func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool)
}
}
if !change {
- return
+ break
+ }
+ }
+ // remove clobbered values
+ for _, b := range f.Blocks {
+ j := 0
+ for i, v := range b.Values {
+ if v.Op == OpInvalid {
+ f.freeValue(v)
+ continue
+ }
+ if i != j {
+ b.Values[j] = v
+ }
+ j++
+ }
+ if j != len(b.Values) {
+ tail := b.Values[j:]
+ for j := range tail {
+ tail[j] = nil
+ }
+ b.Values = b.Values[:j]
}
}
}
@@ -311,3 +367,13 @@ found:
}
return nil // too far away
}
+
+// clobber invalidates v. Returns true.
+// clobber is used by rewrite rules to:
+// A) make sure v is really dead and never used again.
+// B) decrement use counts of v's args.
+func clobber(v *Value) bool {
+ v.reset(OpInvalid)
+ // Note: leave v.Block intact. The Block field is used after clobber.
+ return true
+}
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
index 11c2de391c..c26aeb0bd0 100644
--- a/src/cmd/compile/internal/ssa/rewriteAMD64.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -8,10 +8,6 @@ import "math"
var _ = math.MinInt8 // in case not otherwise used
func rewriteValueAMD64(v *Value, config *Config) bool {
switch v.Op {
- case OpAMD64ADDB:
- return rewriteValueAMD64_OpAMD64ADDB(v, config)
- case OpAMD64ADDBconst:
- return rewriteValueAMD64_OpAMD64ADDBconst(v, config)
case OpAMD64ADDL:
return rewriteValueAMD64_OpAMD64ADDL(v, config)
case OpAMD64ADDLconst:
@@ -20,14 +16,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpAMD64ADDQ(v, config)
case OpAMD64ADDQconst:
return rewriteValueAMD64_OpAMD64ADDQconst(v, config)
- case OpAMD64ADDW:
- return rewriteValueAMD64_OpAMD64ADDW(v, config)
- case OpAMD64ADDWconst:
- return rewriteValueAMD64_OpAMD64ADDWconst(v, config)
- case OpAMD64ANDB:
- return rewriteValueAMD64_OpAMD64ANDB(v, config)
- case OpAMD64ANDBconst:
- return rewriteValueAMD64_OpAMD64ANDBconst(v, config)
case OpAMD64ANDL:
return rewriteValueAMD64_OpAMD64ANDL(v, config)
case OpAMD64ANDLconst:
@@ -36,10 +24,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpAMD64ANDQ(v, config)
case OpAMD64ANDQconst:
return rewriteValueAMD64_OpAMD64ANDQconst(v, config)
- case OpAMD64ANDW:
- return rewriteValueAMD64_OpAMD64ANDW(v, config)
- case OpAMD64ANDWconst:
- return rewriteValueAMD64_OpAMD64ANDWconst(v, config)
case OpAdd16:
return rewriteValueAMD64_OpAdd16(v, config)
case OpAdd32:
@@ -64,6 +48,8 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpAnd64(v, config)
case OpAnd8:
return rewriteValueAMD64_OpAnd8(v, config)
+ case OpAndB:
+ return rewriteValueAMD64_OpAndB(v, config)
case OpAvg64u:
return rewriteValueAMD64_OpAvg64u(v, config)
case OpBswap32:
@@ -180,6 +166,8 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpEq64F(v, config)
case OpEq8:
return rewriteValueAMD64_OpEq8(v, config)
+ case OpEqB:
+ return rewriteValueAMD64_OpEqB(v, config)
case OpEqPtr:
return rewriteValueAMD64_OpEqPtr(v, config)
case OpGeq16:
@@ -458,10 +446,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpAMD64MOVWstoreidx1(v, config)
case OpAMD64MOVWstoreidx2:
return rewriteValueAMD64_OpAMD64MOVWstoreidx2(v, config)
- case OpAMD64MULB:
- return rewriteValueAMD64_OpAMD64MULB(v, config)
- case OpAMD64MULBconst:
- return rewriteValueAMD64_OpAMD64MULBconst(v, config)
case OpAMD64MULL:
return rewriteValueAMD64_OpAMD64MULL(v, config)
case OpAMD64MULLconst:
@@ -470,10 +454,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpAMD64MULQ(v, config)
case OpAMD64MULQconst:
return rewriteValueAMD64_OpAMD64MULQconst(v, config)
- case OpAMD64MULW:
- return rewriteValueAMD64_OpAMD64MULW(v, config)
- case OpAMD64MULWconst:
- return rewriteValueAMD64_OpAMD64MULWconst(v, config)
case OpMod16:
return rewriteValueAMD64_OpMod16(v, config)
case OpMod16u:
@@ -504,22 +484,14 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpMul64F(v, config)
case OpMul8:
return rewriteValueAMD64_OpMul8(v, config)
- case OpAMD64NEGB:
- return rewriteValueAMD64_OpAMD64NEGB(v, config)
case OpAMD64NEGL:
return rewriteValueAMD64_OpAMD64NEGL(v, config)
case OpAMD64NEGQ:
return rewriteValueAMD64_OpAMD64NEGQ(v, config)
- case OpAMD64NEGW:
- return rewriteValueAMD64_OpAMD64NEGW(v, config)
- case OpAMD64NOTB:
- return rewriteValueAMD64_OpAMD64NOTB(v, config)
case OpAMD64NOTL:
return rewriteValueAMD64_OpAMD64NOTL(v, config)
case OpAMD64NOTQ:
return rewriteValueAMD64_OpAMD64NOTQ(v, config)
- case OpAMD64NOTW:
- return rewriteValueAMD64_OpAMD64NOTW(v, config)
case OpNeg16:
return rewriteValueAMD64_OpNeg16(v, config)
case OpNeg32:
@@ -544,16 +516,14 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpNeq64F(v, config)
case OpNeq8:
return rewriteValueAMD64_OpNeq8(v, config)
+ case OpNeqB:
+ return rewriteValueAMD64_OpNeqB(v, config)
case OpNeqPtr:
return rewriteValueAMD64_OpNeqPtr(v, config)
case OpNilCheck:
return rewriteValueAMD64_OpNilCheck(v, config)
case OpNot:
return rewriteValueAMD64_OpNot(v, config)
- case OpAMD64ORB:
- return rewriteValueAMD64_OpAMD64ORB(v, config)
- case OpAMD64ORBconst:
- return rewriteValueAMD64_OpAMD64ORBconst(v, config)
case OpAMD64ORL:
return rewriteValueAMD64_OpAMD64ORL(v, config)
case OpAMD64ORLconst:
@@ -562,10 +532,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpAMD64ORQ(v, config)
case OpAMD64ORQconst:
return rewriteValueAMD64_OpAMD64ORQconst(v, config)
- case OpAMD64ORW:
- return rewriteValueAMD64_OpAMD64ORW(v, config)
- case OpAMD64ORWconst:
- return rewriteValueAMD64_OpAMD64ORWconst(v, config)
case OpOffPtr:
return rewriteValueAMD64_OpOffPtr(v, config)
case OpOr16:
@@ -576,6 +542,8 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpOr64(v, config)
case OpOr8:
return rewriteValueAMD64_OpOr8(v, config)
+ case OpOrB:
+ return rewriteValueAMD64_OpOrB(v, config)
case OpRsh16Ux16:
return rewriteValueAMD64_OpRsh16Ux16(v, config)
case OpRsh16Ux32:
@@ -680,14 +648,10 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpAMD64SETLE(v, config)
case OpAMD64SETNE:
return rewriteValueAMD64_OpAMD64SETNE(v, config)
- case OpAMD64SHLB:
- return rewriteValueAMD64_OpAMD64SHLB(v, config)
case OpAMD64SHLL:
return rewriteValueAMD64_OpAMD64SHLL(v, config)
case OpAMD64SHLQ:
return rewriteValueAMD64_OpAMD64SHLQ(v, config)
- case OpAMD64SHLW:
- return rewriteValueAMD64_OpAMD64SHLW(v, config)
case OpAMD64SHRB:
return rewriteValueAMD64_OpAMD64SHRB(v, config)
case OpAMD64SHRL:
@@ -696,10 +660,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpAMD64SHRQ(v, config)
case OpAMD64SHRW:
return rewriteValueAMD64_OpAMD64SHRW(v, config)
- case OpAMD64SUBB:
- return rewriteValueAMD64_OpAMD64SUBB(v, config)
- case OpAMD64SUBBconst:
- return rewriteValueAMD64_OpAMD64SUBBconst(v, config)
case OpAMD64SUBL:
return rewriteValueAMD64_OpAMD64SUBL(v, config)
case OpAMD64SUBLconst:
@@ -708,10 +668,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpAMD64SUBQ(v, config)
case OpAMD64SUBQconst:
return rewriteValueAMD64_OpAMD64SUBQconst(v, config)
- case OpAMD64SUBW:
- return rewriteValueAMD64_OpAMD64SUBW(v, config)
- case OpAMD64SUBWconst:
- return rewriteValueAMD64_OpAMD64SUBWconst(v, config)
case OpSignExt16to32:
return rewriteValueAMD64_OpSignExt16to32(v, config)
case OpSignExt16to64:
@@ -756,10 +712,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpTrunc64to32(v, config)
case OpTrunc64to8:
return rewriteValueAMD64_OpTrunc64to8(v, config)
- case OpAMD64XORB:
- return rewriteValueAMD64_OpAMD64XORB(v, config)
- case OpAMD64XORBconst:
- return rewriteValueAMD64_OpAMD64XORBconst(v, config)
case OpAMD64XORL:
return rewriteValueAMD64_OpAMD64XORL(v, config)
case OpAMD64XORLconst:
@@ -768,10 +720,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpAMD64XORQ(v, config)
case OpAMD64XORQconst:
return rewriteValueAMD64_OpAMD64XORQconst(v, config)
- case OpAMD64XORW:
- return rewriteValueAMD64_OpAMD64XORW(v, config)
- case OpAMD64XORWconst:
- return rewriteValueAMD64_OpAMD64XORWconst(v, config)
case OpXor16:
return rewriteValueAMD64_OpXor16(v, config)
case OpXor32:
@@ -797,105 +745,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAMD64ADDB(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ADDB x (MOVBconst [c]))
- // cond:
- // result: (ADDBconst [c] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64ADDBconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ADDB (MOVBconst [c]) x)
- // cond:
- // result: (ADDBconst [c] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64ADDBconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ADDB x (NEGB y))
- // cond:
- // result: (SUBB x y)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64NEGB {
- break
- }
- y := v_1.Args[0]
- v.reset(OpAMD64SUBB)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64ADDBconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ADDBconst [c] x)
- // cond: int8(c)==0
- // result: x
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(int8(c) == 0) {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (ADDBconst [c] (MOVBconst [d]))
- // cond:
- // result: (MOVBconst [int64(int8(c+d))])
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
- break
- }
- d := v_0.AuxInt
- v.reset(OpAMD64MOVBconst)
- v.AuxInt = int64(int8(c + d))
- return true
- }
- // match: (ADDBconst [c] (ADDBconst [d] x))
- // cond:
- // result: (ADDBconst [int64(int8(c+d))] x)
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDBconst {
- break
- }
- d := v_0.AuxInt
- x := v_0.Args[0]
- v.reset(OpAMD64ADDBconst)
- v.AuxInt = int64(int8(c + d))
- v.AddArg(x)
- return true
- }
- return false
-}
func rewriteValueAMD64_OpAMD64ADDL(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -1418,244 +1267,6 @@ func rewriteValueAMD64_OpAMD64ADDQconst(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAMD64ADDW(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ADDW x (MOVWconst [c]))
- // cond:
- // result: (ADDWconst [c] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64ADDWconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ADDW (MOVWconst [c]) x)
- // cond:
- // result: (ADDWconst [c] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64ADDWconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ADDW x (NEGW y))
- // cond:
- // result: (SUBW x y)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64NEGW {
- break
- }
- y := v_1.Args[0]
- v.reset(OpAMD64SUBW)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64ADDWconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ADDWconst [c] x)
- // cond: int16(c)==0
- // result: x
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(int16(c) == 0) {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (ADDWconst [c] (MOVWconst [d]))
- // cond:
- // result: (MOVWconst [int64(int16(c+d))])
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
- break
- }
- d := v_0.AuxInt
- v.reset(OpAMD64MOVWconst)
- v.AuxInt = int64(int16(c + d))
- return true
- }
- // match: (ADDWconst [c] (ADDWconst [d] x))
- // cond:
- // result: (ADDWconst [int64(int16(c+d))] x)
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDWconst {
- break
- }
- d := v_0.AuxInt
- x := v_0.Args[0]
- v.reset(OpAMD64ADDWconst)
- v.AuxInt = int64(int16(c + d))
- v.AddArg(x)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64ANDB(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ANDB x (MOVLconst [c]))
- // cond:
- // result: (ANDBconst [c] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64ANDBconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ANDB (MOVLconst [c]) x)
- // cond:
- // result: (ANDBconst [c] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64ANDBconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ANDB x (MOVBconst [c]))
- // cond:
- // result: (ANDBconst [c] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64ANDBconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ANDB (MOVBconst [c]) x)
- // cond:
- // result: (ANDBconst [c] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64ANDBconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ANDB x x)
- // cond:
- // result: x
- for {
- x := v.Args[0]
- if x != v.Args[1] {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64ANDBconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ANDBconst [c] (ANDBconst [d] x))
- // cond:
- // result: (ANDBconst [c & d] x)
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDBconst {
- break
- }
- d := v_0.AuxInt
- x := v_0.Args[0]
- v.reset(OpAMD64ANDBconst)
- v.AuxInt = c & d
- v.AddArg(x)
- return true
- }
- // match: (ANDBconst [c] _)
- // cond: int8(c)==0
- // result: (MOVBconst [0])
- for {
- c := v.AuxInt
- if !(int8(c) == 0) {
- break
- }
- v.reset(OpAMD64MOVBconst)
- v.AuxInt = 0
- return true
- }
- // match: (ANDBconst [c] x)
- // cond: int8(c)==-1
- // result: x
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(int8(c) == -1) {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (ANDBconst [c] (MOVBconst [d]))
- // cond:
- // result: (MOVBconst [c&d])
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
- break
- }
- d := v_0.AuxInt
- v.reset(OpAMD64MOVBconst)
- v.AuxInt = c & d
- return true
- }
- return false
-}
func rewriteValueAMD64_OpAMD64ANDL(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -1838,180 +1449,77 @@ func rewriteValueAMD64_OpAMD64ANDQconst(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- // match: (ANDQconst [0] _)
- // cond:
- // result: (MOVQconst [0])
- for {
- if v.AuxInt != 0 {
- break
- }
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = 0
- return true
- }
- // match: (ANDQconst [-1] x)
+ // match: (ANDQconst [0xFF] x)
// cond:
- // result: x
+ // result: (MOVBQZX x)
for {
- if v.AuxInt != -1 {
+ if v.AuxInt != 0xFF {
break
}
x := v.Args[0]
- v.reset(OpCopy)
- v.Type = x.Type
+ v.reset(OpAMD64MOVBQZX)
v.AddArg(x)
return true
}
- // match: (ANDQconst [c] (MOVQconst [d]))
+ // match: (ANDQconst [0xFFFF] x)
// cond:
- // result: (MOVQconst [c&d])
+ // result: (MOVWQZX x)
for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVQconst {
+ if v.AuxInt != 0xFFFF {
break
}
- d := v_0.AuxInt
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = c & d
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64ANDW(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ANDW x (MOVLconst [c]))
- // cond:
- // result: (ANDWconst [c] x)
- for {
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64ANDWconst)
- v.AuxInt = c
+ v.reset(OpAMD64MOVWQZX)
v.AddArg(x)
return true
}
- // match: (ANDW (MOVLconst [c]) x)
+ // match: (ANDQconst [0xFFFFFFFF] x)
// cond:
- // result: (ANDWconst [c] x)
+ // result: (MOVLQZX x)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ if v.AuxInt != 0xFFFFFFFF {
break
}
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64ANDWconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ANDW x (MOVWconst [c]))
- // cond:
- // result: (ANDWconst [c] x)
- for {
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64ANDWconst)
- v.AuxInt = c
+ v.reset(OpAMD64MOVLQZX)
v.AddArg(x)
return true
}
- // match: (ANDW (MOVWconst [c]) x)
+ // match: (ANDQconst [0] _)
// cond:
- // result: (ANDWconst [c] x)
+ // result: (MOVQconst [0])
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
+ if v.AuxInt != 0 {
break
}
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64ANDWconst)
- v.AuxInt = c
- v.AddArg(x)
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = 0
return true
}
- // match: (ANDW x x)
+ // match: (ANDQconst [-1] x)
// cond:
// result: x
for {
- x := v.Args[0]
- if x != v.Args[1] {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64ANDWconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ANDWconst [c] (ANDWconst [d] x))
- // cond:
- // result: (ANDWconst [c & d] x)
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDWconst {
- break
- }
- d := v_0.AuxInt
- x := v_0.Args[0]
- v.reset(OpAMD64ANDWconst)
- v.AuxInt = c & d
- v.AddArg(x)
- return true
- }
- // match: (ANDWconst [c] _)
- // cond: int16(c)==0
- // result: (MOVWconst [0])
- for {
- c := v.AuxInt
- if !(int16(c) == 0) {
+ if v.AuxInt != -1 {
break
}
- v.reset(OpAMD64MOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (ANDWconst [c] x)
- // cond: int16(c)==-1
- // result: x
- for {
- c := v.AuxInt
x := v.Args[0]
- if !(int16(c) == -1) {
- break
- }
v.reset(OpCopy)
v.Type = x.Type
v.AddArg(x)
return true
}
- // match: (ANDWconst [c] (MOVWconst [d]))
+ // match: (ANDQconst [c] (MOVQconst [d]))
// cond:
- // result: (MOVWconst [c&d])
+ // result: (MOVQconst [c&d])
for {
c := v.AuxInt
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
+ if v_0.Op != OpAMD64MOVQconst {
break
}
d := v_0.AuxInt
- v.reset(OpAMD64MOVWconst)
+ v.reset(OpAMD64MOVQconst)
v.AuxInt = c & d
return true
}
@@ -2022,11 +1530,11 @@ func rewriteValueAMD64_OpAdd16(v *Value, config *Config) bool {
_ = b
// match: (Add16 x y)
// cond:
- // result: (ADDW x y)
+ // result: (ADDL x y)
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ADDW)
+ v.reset(OpAMD64ADDL)
v.AddArg(x)
v.AddArg(y)
return true
@@ -2102,11 +1610,11 @@ func rewriteValueAMD64_OpAdd8(v *Value, config *Config) bool {
_ = b
// match: (Add8 x y)
// cond:
- // result: (ADDB x y)
+ // result: (ADDL x y)
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ADDB)
+ v.reset(OpAMD64ADDL)
v.AddArg(x)
v.AddArg(y)
return true
@@ -2150,11 +1658,11 @@ func rewriteValueAMD64_OpAnd16(v *Value, config *Config) bool {
_ = b
// match: (And16 x y)
// cond:
- // result: (ANDW x y)
+ // result: (ANDL x y)
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDW)
+ v.reset(OpAMD64ANDL)
v.AddArg(x)
v.AddArg(y)
return true
@@ -2198,11 +1706,27 @@ func rewriteValueAMD64_OpAnd8(v *Value, config *Config) bool {
_ = b
// match: (And8 x y)
// cond:
- // result: (ANDB x y)
+ // result: (ANDL x y)
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDB)
+ v.reset(OpAMD64ANDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAndB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AndB x y)
+ // cond:
+ // result: (ANDL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
v.AddArg(x)
v.AddArg(y)
return true
@@ -2529,27 +2053,27 @@ func rewriteValueAMD64_OpAMD64CMOVWEQconst(v *Value, config *Config) bool {
func rewriteValueAMD64_OpAMD64CMPB(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (CMPB x (MOVBconst [c]))
+ // match: (CMPB x (MOVLconst [c]))
// cond:
- // result: (CMPBconst x [c])
+ // result: (CMPBconst x [int64(int8(c))])
for {
x := v.Args[0]
v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
+ if v_1.Op != OpAMD64MOVLconst {
break
}
c := v_1.AuxInt
v.reset(OpAMD64CMPBconst)
v.AddArg(x)
- v.AuxInt = c
+ v.AuxInt = int64(int8(c))
return true
}
- // match: (CMPB (MOVBconst [c]) x)
+ // match: (CMPB (MOVLconst [c]) x)
// cond:
- // result: (InvertFlags (CMPBconst x [c]))
+ // result: (InvertFlags (CMPBconst x [int64(int8(c))]))
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
+ if v_0.Op != OpAMD64MOVLconst {
break
}
c := v_0.AuxInt
@@ -2557,7 +2081,7 @@ func rewriteValueAMD64_OpAMD64CMPB(v *Value, config *Config) bool {
v.reset(OpAMD64InvertFlags)
v0 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
v0.AddArg(x)
- v0.AuxInt = c
+ v0.AuxInt = int64(int8(c))
v.AddArg(v0)
return true
}
@@ -2566,12 +2090,12 @@ func rewriteValueAMD64_OpAMD64CMPB(v *Value, config *Config) bool {
func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (CMPBconst (MOVBconst [x]) [y])
+ // match: (CMPBconst (MOVLconst [x]) [y])
// cond: int8(x)==int8(y)
// result: (FlagEQ)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
+ if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
@@ -2582,12 +2106,12 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
v.reset(OpAMD64FlagEQ)
return true
}
- // match: (CMPBconst (MOVBconst [x]) [y])
+ // match: (CMPBconst (MOVLconst [x]) [y])
// cond: int8(x)<int8(y) && uint8(x)<uint8(y)
// result: (FlagLT_ULT)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
+ if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
@@ -2598,12 +2122,12 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
v.reset(OpAMD64FlagLT_ULT)
return true
}
- // match: (CMPBconst (MOVBconst [x]) [y])
+ // match: (CMPBconst (MOVLconst [x]) [y])
// cond: int8(x)<int8(y) && uint8(x)>uint8(y)
// result: (FlagLT_UGT)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
+ if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
@@ -2614,12 +2138,12 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
v.reset(OpAMD64FlagLT_UGT)
return true
}
- // match: (CMPBconst (MOVBconst [x]) [y])
+ // match: (CMPBconst (MOVLconst [x]) [y])
// cond: int8(x)>int8(y) && uint8(x)<uint8(y)
// result: (FlagGT_ULT)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
+ if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
@@ -2630,12 +2154,12 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
v.reset(OpAMD64FlagGT_ULT)
return true
}
- // match: (CMPBconst (MOVBconst [x]) [y])
+ // match: (CMPBconst (MOVLconst [x]) [y])
// cond: int8(x)>int8(y) && uint8(x)>uint8(y)
// result: (FlagGT_UGT)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
+ if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
@@ -2646,12 +2170,12 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
v.reset(OpAMD64FlagGT_UGT)
return true
}
- // match: (CMPBconst (ANDBconst _ [m]) [n])
+ // match: (CMPBconst (ANDLconst _ [m]) [n])
// cond: 0 <= int8(m) && int8(m) < int8(n)
// result: (FlagLT_ULT)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDBconst {
+ if v_0.Op != OpAMD64ANDLconst {
break
}
m := v_0.AuxInt
@@ -2662,12 +2186,12 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
v.reset(OpAMD64FlagLT_ULT)
return true
}
- // match: (CMPBconst (ANDB x y) [0])
+ // match: (CMPBconst (ANDL x y) [0])
// cond:
// result: (TESTB x y)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDB {
+ if v_0.Op != OpAMD64ANDL {
break
}
x := v_0.Args[0]
@@ -2680,12 +2204,12 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
v.AddArg(y)
return true
}
- // match: (CMPBconst (ANDBconst [c] x) [0])
+ // match: (CMPBconst (ANDLconst [c] x) [0])
// cond:
- // result: (TESTBconst [c] x)
+ // result: (TESTBconst [int64(int8(c))] x)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDBconst {
+ if v_0.Op != OpAMD64ANDLconst {
break
}
c := v_0.AuxInt
@@ -2694,7 +2218,7 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
break
}
v.reset(OpAMD64TESTBconst)
- v.AuxInt = c
+ v.AuxInt = int64(int8(c))
v.AddArg(x)
return true
}
@@ -2833,6 +2357,22 @@ func rewriteValueAMD64_OpAMD64CMPLconst(v *Value, config *Config) bool {
v.reset(OpAMD64FlagGT_UGT)
return true
}
+ // match: (CMPLconst (SHRLconst _ [c]) [n])
+ // cond: 0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n)
+ // result: (FlagLT_ULT)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64SHRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ n := v.AuxInt
+ if !(0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n)) {
+ break
+ }
+ v.reset(OpAMD64FlagLT_ULT)
+ return true
+ }
// match: (CMPLconst (ANDLconst _ [m]) [n])
// cond: 0 <= int32(m) && int32(m) < int32(n)
// result: (FlagLT_ULT)
@@ -3026,6 +2566,67 @@ func rewriteValueAMD64_OpAMD64CMPQconst(v *Value, config *Config) bool {
v.reset(OpAMD64FlagGT_UGT)
return true
}
+ // match: (CMPQconst (MOVBQZX _) [c])
+ // cond: 0xFF < c
+ // result: (FlagLT_ULT)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVBQZX {
+ break
+ }
+ c := v.AuxInt
+ if !(0xFF < c) {
+ break
+ }
+ v.reset(OpAMD64FlagLT_ULT)
+ return true
+ }
+ // match: (CMPQconst (MOVWQZX _) [c])
+ // cond: 0xFFFF < c
+ // result: (FlagLT_ULT)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVWQZX {
+ break
+ }
+ c := v.AuxInt
+ if !(0xFFFF < c) {
+ break
+ }
+ v.reset(OpAMD64FlagLT_ULT)
+ return true
+ }
+ // match: (CMPQconst (MOVLQZX _) [c])
+ // cond: 0xFFFFFFFF < c
+ // result: (FlagLT_ULT)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLQZX {
+ break
+ }
+ c := v.AuxInt
+ if !(0xFFFFFFFF < c) {
+ break
+ }
+ v.reset(OpAMD64FlagLT_ULT)
+ return true
+ }
+ // match: (CMPQconst (SHRQconst _ [c]) [n])
+ // cond: 0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n)
+ // result: (FlagLT_ULT)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64SHRQconst {
+ break
+ }
+ c := v_0.AuxInt
+ n := v.AuxInt
+ if !(0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n)) {
+ break
+ }
+ v.reset(OpAMD64FlagLT_ULT)
+ return true
+ }
// match: (CMPQconst (ANDQconst _ [m]) [n])
// cond: 0 <= m && m < n
// result: (FlagLT_ULT)
@@ -3096,27 +2697,27 @@ func rewriteValueAMD64_OpAMD64CMPQconst(v *Value, config *Config) bool {
func rewriteValueAMD64_OpAMD64CMPW(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (CMPW x (MOVWconst [c]))
+ // match: (CMPW x (MOVLconst [c]))
// cond:
- // result: (CMPWconst x [c])
+ // result: (CMPWconst x [int64(int16(c))])
for {
x := v.Args[0]
v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
+ if v_1.Op != OpAMD64MOVLconst {
break
}
c := v_1.AuxInt
v.reset(OpAMD64CMPWconst)
v.AddArg(x)
- v.AuxInt = c
+ v.AuxInt = int64(int16(c))
return true
}
- // match: (CMPW (MOVWconst [c]) x)
+ // match: (CMPW (MOVLconst [c]) x)
// cond:
- // result: (InvertFlags (CMPWconst x [c]))
+ // result: (InvertFlags (CMPWconst x [int64(int16(c))]))
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
+ if v_0.Op != OpAMD64MOVLconst {
break
}
c := v_0.AuxInt
@@ -3124,7 +2725,7 @@ func rewriteValueAMD64_OpAMD64CMPW(v *Value, config *Config) bool {
v.reset(OpAMD64InvertFlags)
v0 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
v0.AddArg(x)
- v0.AuxInt = c
+ v0.AuxInt = int64(int16(c))
v.AddArg(v0)
return true
}
@@ -3133,12 +2734,12 @@ func rewriteValueAMD64_OpAMD64CMPW(v *Value, config *Config) bool {
func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (CMPWconst (MOVWconst [x]) [y])
+ // match: (CMPWconst (MOVLconst [x]) [y])
// cond: int16(x)==int16(y)
// result: (FlagEQ)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
+ if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
@@ -3149,12 +2750,12 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
v.reset(OpAMD64FlagEQ)
return true
}
- // match: (CMPWconst (MOVWconst [x]) [y])
+ // match: (CMPWconst (MOVLconst [x]) [y])
// cond: int16(x)<int16(y) && uint16(x)<uint16(y)
// result: (FlagLT_ULT)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
+ if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
@@ -3165,12 +2766,12 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
v.reset(OpAMD64FlagLT_ULT)
return true
}
- // match: (CMPWconst (MOVWconst [x]) [y])
+ // match: (CMPWconst (MOVLconst [x]) [y])
// cond: int16(x)<int16(y) && uint16(x)>uint16(y)
// result: (FlagLT_UGT)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
+ if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
@@ -3181,12 +2782,12 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
v.reset(OpAMD64FlagLT_UGT)
return true
}
- // match: (CMPWconst (MOVWconst [x]) [y])
+ // match: (CMPWconst (MOVLconst [x]) [y])
// cond: int16(x)>int16(y) && uint16(x)<uint16(y)
// result: (FlagGT_ULT)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
+ if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
@@ -3197,12 +2798,12 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
v.reset(OpAMD64FlagGT_ULT)
return true
}
- // match: (CMPWconst (MOVWconst [x]) [y])
+ // match: (CMPWconst (MOVLconst [x]) [y])
// cond: int16(x)>int16(y) && uint16(x)>uint16(y)
// result: (FlagGT_UGT)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
+ if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
@@ -3213,12 +2814,12 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
v.reset(OpAMD64FlagGT_UGT)
return true
}
- // match: (CMPWconst (ANDWconst _ [m]) [n])
+ // match: (CMPWconst (ANDLconst _ [m]) [n])
// cond: 0 <= int16(m) && int16(m) < int16(n)
// result: (FlagLT_ULT)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDWconst {
+ if v_0.Op != OpAMD64ANDLconst {
break
}
m := v_0.AuxInt
@@ -3229,12 +2830,12 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
v.reset(OpAMD64FlagLT_ULT)
return true
}
- // match: (CMPWconst (ANDW x y) [0])
+ // match: (CMPWconst (ANDL x y) [0])
// cond:
// result: (TESTW x y)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDW {
+ if v_0.Op != OpAMD64ANDL {
break
}
x := v_0.Args[0]
@@ -3247,12 +2848,12 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
v.AddArg(y)
return true
}
- // match: (CMPWconst (ANDWconst [c] x) [0])
+ // match: (CMPWconst (ANDLconst [c] x) [0])
// cond:
- // result: (TESTWconst [c] x)
+ // result: (TESTWconst [int64(int16(c))] x)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDWconst {
+ if v_0.Op != OpAMD64ANDLconst {
break
}
c := v_0.AuxInt
@@ -3261,7 +2862,7 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
break
}
v.reset(OpAMD64TESTWconst)
- v.AuxInt = c
+ v.AuxInt = int64(int16(c))
v.AddArg(x)
return true
}
@@ -3305,10 +2906,10 @@ func rewriteValueAMD64_OpCom16(v *Value, config *Config) bool {
_ = b
// match: (Com16 x)
// cond:
- // result: (NOTW x)
+ // result: (NOTL x)
for {
x := v.Args[0]
- v.reset(OpAMD64NOTW)
+ v.reset(OpAMD64NOTL)
v.AddArg(x)
return true
}
@@ -3347,10 +2948,10 @@ func rewriteValueAMD64_OpCom8(v *Value, config *Config) bool {
_ = b
// match: (Com8 x)
// cond:
- // result: (NOTB x)
+ // result: (NOTL x)
for {
x := v.Args[0]
- v.reset(OpAMD64NOTB)
+ v.reset(OpAMD64NOTL)
v.AddArg(x)
return true
}
@@ -3361,10 +2962,10 @@ func rewriteValueAMD64_OpConst16(v *Value, config *Config) bool {
_ = b
// match: (Const16 [val])
// cond:
- // result: (MOVWconst [val])
+ // result: (MOVLconst [val])
for {
val := v.AuxInt
- v.reset(OpAMD64MOVWconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = val
return true
}
@@ -3431,10 +3032,10 @@ func rewriteValueAMD64_OpConst8(v *Value, config *Config) bool {
_ = b
// match: (Const8 [val])
// cond:
- // result: (MOVBconst [val])
+ // result: (MOVLconst [val])
for {
val := v.AuxInt
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = val
return true
}
@@ -3445,10 +3046,10 @@ func rewriteValueAMD64_OpConstBool(v *Value, config *Config) bool {
_ = b
// match: (ConstBool [b])
// cond:
- // result: (MOVBconst [b])
+ // result: (MOVLconst [b])
for {
b := v.AuxInt
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = b
return true
}
@@ -3983,6 +3584,24 @@ func rewriteValueAMD64_OpEq8(v *Value, config *Config) bool {
}
return false
}
+func rewriteValueAMD64_OpEqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqB x y)
+ // cond:
+ // result: (SETEQ (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETEQ)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
func rewriteValueAMD64_OpEqPtr(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -5842,20 +5461,20 @@ func rewriteValueAMD64_OpLsh16x16(v *Value, config *Config) bool {
_ = b
// match: (Lsh16x16 <t> x y)
// cond:
- // result: (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPWconst y [16])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDW)
- v0 := b.NewValue0(v.Line, OpAMD64SHLW, t)
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
v2.AddArg(y)
- v2.AuxInt = 16
+ v2.AuxInt = 32
v1.AddArg(v2)
v.AddArg(v1)
return true
@@ -5867,20 +5486,20 @@ func rewriteValueAMD64_OpLsh16x32(v *Value, config *Config) bool {
_ = b
// match: (Lsh16x32 <t> x y)
// cond:
- // result: (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDW)
- v0 := b.NewValue0(v.Line, OpAMD64SHLW, t)
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
v2.AddArg(y)
- v2.AuxInt = 16
+ v2.AuxInt = 32
v1.AddArg(v2)
v.AddArg(v1)
return true
@@ -5892,20 +5511,20 @@ func rewriteValueAMD64_OpLsh16x64(v *Value, config *Config) bool {
_ = b
// match: (Lsh16x64 <t> x y)
// cond:
- // result: (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPQconst y [16])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDW)
- v0 := b.NewValue0(v.Line, OpAMD64SHLW, t)
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
v2.AddArg(y)
- v2.AuxInt = 16
+ v2.AuxInt = 32
v1.AddArg(v2)
v.AddArg(v1)
return true
@@ -5917,20 +5536,20 @@ func rewriteValueAMD64_OpLsh16x8(v *Value, config *Config) bool {
_ = b
// match: (Lsh16x8 <t> x y)
// cond:
- // result: (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDW)
- v0 := b.NewValue0(v.Line, OpAMD64SHLW, t)
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
v2.AddArg(y)
- v2.AuxInt = 16
+ v2.AuxInt = 32
v1.AddArg(v2)
v.AddArg(v1)
return true
@@ -6142,20 +5761,20 @@ func rewriteValueAMD64_OpLsh8x16(v *Value, config *Config) bool {
_ = b
// match: (Lsh8x16 <t> x y)
// cond:
- // result: (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDB)
- v0 := b.NewValue0(v.Line, OpAMD64SHLB, t)
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
v2.AddArg(y)
- v2.AuxInt = 8
+ v2.AuxInt = 32
v1.AddArg(v2)
v.AddArg(v1)
return true
@@ -6167,20 +5786,20 @@ func rewriteValueAMD64_OpLsh8x32(v *Value, config *Config) bool {
_ = b
// match: (Lsh8x32 <t> x y)
// cond:
- // result: (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDB)
- v0 := b.NewValue0(v.Line, OpAMD64SHLB, t)
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
v2.AddArg(y)
- v2.AuxInt = 8
+ v2.AuxInt = 32
v1.AddArg(v2)
v.AddArg(v1)
return true
@@ -6192,20 +5811,20 @@ func rewriteValueAMD64_OpLsh8x64(v *Value, config *Config) bool {
_ = b
// match: (Lsh8x64 <t> x y)
// cond:
- // result: (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPQconst y [8])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDB)
- v0 := b.NewValue0(v.Line, OpAMD64SHLB, t)
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
v2.AddArg(y)
- v2.AuxInt = 8
+ v2.AuxInt = 32
v1.AddArg(v2)
v.AddArg(v1)
return true
@@ -6217,20 +5836,20 @@ func rewriteValueAMD64_OpLsh8x8(v *Value, config *Config) bool {
_ = b
// match: (Lsh8x8 <t> x y)
// cond:
- // result: (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDB)
- v0 := b.NewValue0(v.Line, OpAMD64SHLB, t)
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
v2.AddArg(y)
- v2.AuxInt = 8
+ v2.AuxInt = 32
v1.AddArg(v2)
v.AddArg(v1)
return true
@@ -6241,7 +5860,7 @@ func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVBQSX x:(MOVBload [off] {sym} ptr mem))
- // cond: x.Uses == 1
+ // cond: x.Uses == 1 && clobber(x)
// result: @x.Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
for {
x := v.Args[0]
@@ -6252,7 +5871,7 @@ func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
sym := x.Aux
ptr := x.Args[0]
mem := x.Args[1]
- if !(x.Uses == 1) {
+ if !(x.Uses == 1 && clobber(x)) {
break
}
b = x.Block
@@ -6265,12 +5884,12 @@ func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
v0.AddArg(mem)
return true
}
- // match: (MOVBQSX (ANDBconst [c] x))
+ // match: (MOVBQSX (ANDLconst [c] x))
// cond: c & 0x80 == 0
- // result: (ANDQconst [c & 0x7f] x)
+ // result: (ANDLconst [c & 0x7f] x)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDBconst {
+ if v_0.Op != OpAMD64ANDLconst {
break
}
c := v_0.AuxInt
@@ -6278,7 +5897,7 @@ func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
if !(c&0x80 == 0) {
break
}
- v.reset(OpAMD64ANDQconst)
+ v.reset(OpAMD64ANDLconst)
v.AuxInt = c & 0x7f
v.AddArg(x)
return true
@@ -6318,7 +5937,7 @@ func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVBQZX x:(MOVBload [off] {sym} ptr mem))
- // cond: x.Uses == 1
+ // cond: x.Uses == 1 && clobber(x)
// result: @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
for {
x := v.Args[0]
@@ -6329,7 +5948,7 @@ func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
sym := x.Aux
ptr := x.Args[0]
mem := x.Args[1]
- if !(x.Uses == 1) {
+ if !(x.Uses == 1 && clobber(x)) {
break
}
b = x.Block
@@ -6343,7 +5962,7 @@ func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
return true
}
// match: (MOVBQZX x:(MOVBloadidx1 [off] {sym} ptr idx mem))
- // cond: x.Uses == 1
+ // cond: x.Uses == 1 && clobber(x)
// result: @x.Block (MOVBloadidx1 <v.Type> [off] {sym} ptr idx mem)
for {
x := v.Args[0]
@@ -6355,7 +5974,7 @@ func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
ptr := x.Args[0]
idx := x.Args[1]
mem := x.Args[2]
- if !(x.Uses == 1) {
+ if !(x.Uses == 1 && clobber(x)) {
break
}
b = x.Block
@@ -6369,17 +5988,17 @@ func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
v0.AddArg(mem)
return true
}
- // match: (MOVBQZX (ANDBconst [c] x))
+ // match: (MOVBQZX (ANDLconst [c] x))
// cond:
- // result: (ANDQconst [c & 0xff] x)
+ // result: (ANDLconst [c & 0xff] x)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDBconst {
+ if v_0.Op != OpAMD64ANDLconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
- v.reset(OpAMD64ANDQconst)
+ v.reset(OpAMD64ANDLconst)
v.AuxInt = c & 0xff
v.AddArg(x)
return true
@@ -6630,7 +6249,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- // match: (MOVBstore [off] {sym} ptr (MOVBconst [c]) mem)
+ // match: (MOVBstore [off] {sym} ptr (MOVLconst [c]) mem)
// cond: validOff(off)
// result: (MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
for {
@@ -6638,7 +6257,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
+ if v_1.Op != OpAMD64MOVLconst {
break
}
c := v_1.AuxInt
@@ -6733,6 +6352,97 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVBstore [i] {s} p (SHRQconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstore [i-1] {s} p w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ if v_1.AuxInt != 8 {
+ break
+ }
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if w != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [i] {s} p (SHRQconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SHRQconst [j-8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstore [i-1] {s} p w0 mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ j := v_1.AuxInt
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ w0 := x.Args[1]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-8 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w0)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value, config *Config) bool {
@@ -6832,6 +6542,35 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ x := v.Args[1]
+ if x.Op != OpAMD64MOVBstoreconst {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ mem := x.Args[1]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstoreconst)
+ v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xff|ValAndOff(c).Val()<<8, ValAndOff(a).Off())
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVBstoreconstidx1(v *Value, config *Config) bool {
@@ -6881,6 +6620,40 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconstidx1(v *Value, config *Config) bool
v.AddArg(mem)
return true
}
+ // match: (MOVBstoreconstidx1 [c] {s} p i x:(MOVBstoreconstidx1 [a] {s} p i mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVWstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p i mem)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ i := v.Args[1]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVBstoreconstidx1 {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if i != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstoreconstidx1)
+ v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xff|ValAndOff(c).Val()<<8, ValAndOff(a).Off())
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(i)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVBstoreidx1(v *Value, config *Config) bool {
@@ -6934,13 +6707,114 @@ func rewriteValueAMD64_OpAMD64MOVBstoreidx1(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVBstoreidx1 [i] {s} p idx (SHRQconst [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i-1] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
+ break
+ }
+ if v_2.AuxInt != 8 {
+ break
+ }
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ if w != x.Args[2] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstoreidx1)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRQconst [j-8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
+ break
+ }
+ j := v_2.AuxInt
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ w0 := x.Args[2]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-8 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstoreidx1)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w0)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVLQSX(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVLQSX x:(MOVLload [off] {sym} ptr mem))
- // cond: x.Uses == 1
+ // cond: x.Uses == 1 && clobber(x)
// result: @x.Block (MOVLQSXload <v.Type> [off] {sym} ptr mem)
for {
x := v.Args[0]
@@ -6951,7 +6825,7 @@ func rewriteValueAMD64_OpAMD64MOVLQSX(v *Value, config *Config) bool {
sym := x.Aux
ptr := x.Args[0]
mem := x.Args[1]
- if !(x.Uses == 1) {
+ if !(x.Uses == 1 && clobber(x)) {
break
}
b = x.Block
@@ -6966,7 +6840,7 @@ func rewriteValueAMD64_OpAMD64MOVLQSX(v *Value, config *Config) bool {
}
// match: (MOVLQSX (ANDLconst [c] x))
// cond: c & 0x80000000 == 0
- // result: (ANDQconst [c & 0x7fffffff] x)
+ // result: (ANDLconst [c & 0x7fffffff] x)
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64ANDLconst {
@@ -6977,7 +6851,7 @@ func rewriteValueAMD64_OpAMD64MOVLQSX(v *Value, config *Config) bool {
if !(c&0x80000000 == 0) {
break
}
- v.reset(OpAMD64ANDQconst)
+ v.reset(OpAMD64ANDLconst)
v.AuxInt = c & 0x7fffffff
v.AddArg(x)
return true
@@ -7017,7 +6891,7 @@ func rewriteValueAMD64_OpAMD64MOVLQZX(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVLQZX x:(MOVLload [off] {sym} ptr mem))
- // cond: x.Uses == 1
+ // cond: x.Uses == 1 && clobber(x)
// result: @x.Block (MOVLload <v.Type> [off] {sym} ptr mem)
for {
x := v.Args[0]
@@ -7028,7 +6902,7 @@ func rewriteValueAMD64_OpAMD64MOVLQZX(v *Value, config *Config) bool {
sym := x.Aux
ptr := x.Args[0]
mem := x.Args[1]
- if !(x.Uses == 1) {
+ if !(x.Uses == 1 && clobber(x)) {
break
}
b = x.Block
@@ -7042,7 +6916,7 @@ func rewriteValueAMD64_OpAMD64MOVLQZX(v *Value, config *Config) bool {
return true
}
// match: (MOVLQZX x:(MOVLloadidx1 [off] {sym} ptr idx mem))
- // cond: x.Uses == 1
+ // cond: x.Uses == 1 && clobber(x)
// result: @x.Block (MOVLloadidx1 <v.Type> [off] {sym} ptr idx mem)
for {
x := v.Args[0]
@@ -7054,7 +6928,7 @@ func rewriteValueAMD64_OpAMD64MOVLQZX(v *Value, config *Config) bool {
ptr := x.Args[0]
idx := x.Args[1]
mem := x.Args[2]
- if !(x.Uses == 1) {
+ if !(x.Uses == 1 && clobber(x)) {
break
}
b = x.Block
@@ -7069,7 +6943,7 @@ func rewriteValueAMD64_OpAMD64MOVLQZX(v *Value, config *Config) bool {
return true
}
// match: (MOVLQZX x:(MOVLloadidx4 [off] {sym} ptr idx mem))
- // cond: x.Uses == 1
+ // cond: x.Uses == 1 && clobber(x)
// result: @x.Block (MOVLloadidx4 <v.Type> [off] {sym} ptr idx mem)
for {
x := v.Args[0]
@@ -7081,7 +6955,7 @@ func rewriteValueAMD64_OpAMD64MOVLQZX(v *Value, config *Config) bool {
ptr := x.Args[0]
idx := x.Args[1]
mem := x.Args[2]
- if !(x.Uses == 1) {
+ if !(x.Uses == 1 && clobber(x)) {
break
}
b = x.Block
@@ -7096,8 +6970,8 @@ func rewriteValueAMD64_OpAMD64MOVLQZX(v *Value, config *Config) bool {
return true
}
// match: (MOVLQZX (ANDLconst [c] x))
- // cond: c & 0x80000000 == 0
- // result: (ANDQconst [c & 0x7fffffff] x)
+ // cond:
+ // result: (ANDLconst [c] x)
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64ANDLconst {
@@ -7105,11 +6979,8 @@ func rewriteValueAMD64_OpAMD64MOVLQZX(v *Value, config *Config) bool {
}
c := v_0.AuxInt
x := v_0.Args[0]
- if !(c&0x80000000 == 0) {
- break
- }
- v.reset(OpAMD64ANDQconst)
- v.AuxInt = c & 0x7fffffff
+ v.reset(OpAMD64ANDLconst)
+ v.AuxInt = c
v.AddArg(x)
return true
}
@@ -7589,6 +7460,97 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVLstore [i] {s} p (SHRQconst [32] w) x:(MOVLstore [i-4] {s} p w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVQstore [i-4] {s} p w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ if v_1.AuxInt != 32 {
+ break
+ }
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVLstore {
+ break
+ }
+ if x.AuxInt != i-4 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if w != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstore)
+ v.AuxInt = i - 4
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstore [i] {s} p (SHRQconst [j] w) x:(MOVLstore [i-4] {s} p w0:(SHRQconst [j-32] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVQstore [i-4] {s} p w0 mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ j := v_1.AuxInt
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVLstore {
+ break
+ }
+ if x.AuxInt != i-4 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ w0 := x.Args[1]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-32 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstore)
+ v.AuxInt = i - 4
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w0)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value, config *Config) bool {
@@ -7714,6 +7676,38 @@ func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVLstoreconst [c] {s} p x:(MOVLstoreconst [a] {s} p mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 4 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVQstore [ValAndOff(a).Off()] {s} p (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ x := v.Args[1]
+ if x.Op != OpAMD64MOVLstoreconst {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ mem := x.Args[1]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstore)
+ v.AuxInt = ValAndOff(a).Off()
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+ v0.AuxInt = ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVLstoreconstidx1(v *Value, config *Config) bool {
@@ -7787,6 +7781,43 @@ func rewriteValueAMD64_OpAMD64MOVLstoreconstidx1(v *Value, config *Config) bool
v.AddArg(mem)
return true
}
+ // match: (MOVLstoreconstidx1 [c] {s} p i x:(MOVLstoreconstidx1 [a] {s} p i mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 4 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVQstoreidx1 [ValAndOff(a).Off()] {s} p i (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ i := v.Args[1]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVLstoreconstidx1 {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if i != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreidx1)
+ v.AuxInt = ValAndOff(a).Off()
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(i)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+ v0.AuxInt = ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVLstoreconstidx4(v *Value, config *Config) bool {
@@ -7836,6 +7867,46 @@ func rewriteValueAMD64_OpAMD64MOVLstoreconstidx4(v *Value, config *Config) bool
v.AddArg(mem)
return true
}
+ // match: (MOVLstoreconstidx4 [c] {s} p i x:(MOVLstoreconstidx4 [a] {s} p i mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 4 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVQstoreidx1 [ValAndOff(a).Off()] {s} p (SHLQconst <i.Type> [2] i) (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ i := v.Args[1]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVLstoreconstidx4 {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if i != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreidx1)
+ v.AuxInt = ValAndOff(a).Off()
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, i.Type)
+ v0.AuxInt = 2
+ v0.AddArg(i)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+ v1.AuxInt = ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32
+ v.AddArg(v1)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVLstoreidx1(v *Value, config *Config) bool {
@@ -7915,6 +7986,107 @@ func rewriteValueAMD64_OpAMD64MOVLstoreidx1(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVLstoreidx1 [i] {s} p idx (SHRQconst [32] w) x:(MOVLstoreidx1 [i-4] {s} p idx w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVQstoreidx1 [i-4] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
+ break
+ }
+ if v_2.AuxInt != 32 {
+ break
+ }
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVLstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-4 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ if w != x.Args[2] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreidx1)
+ v.AuxInt = i - 4
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVLstoreidx1 [i-4] {s} p idx w0:(SHRQconst [j-32] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVQstoreidx1 [i-4] {s} p idx w0 mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
+ break
+ }
+ j := v_2.AuxInt
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVLstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-4 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ w0 := x.Args[2]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-32 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreidx1)
+ v.AuxInt = i - 4
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w0)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVLstoreidx4(v *Value, config *Config) bool {
@@ -7968,6 +8140,113 @@ func rewriteValueAMD64_OpAMD64MOVLstoreidx4(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVLstoreidx4 [i] {s} p idx (SHRQconst [32] w) x:(MOVLstoreidx4 [i-4] {s} p idx w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVQstoreidx1 [i-4] {s} p (SHLQconst <idx.Type> [2] idx) w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
+ break
+ }
+ if v_2.AuxInt != 32 {
+ break
+ }
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVLstoreidx4 {
+ break
+ }
+ if x.AuxInt != i-4 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ if w != x.Args[2] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreidx1)
+ v.AuxInt = i - 4
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, idx.Type)
+ v0.AuxInt = 2
+ v0.AddArg(idx)
+ v.AddArg(v0)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 [i] {s} p idx (SHRQconst [j] w) x:(MOVLstoreidx4 [i-4] {s} p idx w0:(SHRQconst [j-32] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVQstoreidx1 [i-4] {s} p (SHLQconst <idx.Type> [2] idx) w0 mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
+ break
+ }
+ j := v_2.AuxInt
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVLstoreidx4 {
+ break
+ }
+ if x.AuxInt != i-4 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ w0 := x.Args[2]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-32 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreidx1)
+ v.AuxInt = i - 4
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, idx.Type)
+ v0.AuxInt = 2
+ v0.AddArg(idx)
+ v.AddArg(v0)
+ v.AddArg(w0)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVOload(v *Value, config *Config) bool {
@@ -9835,7 +10114,7 @@ func rewriteValueAMD64_OpAMD64MOVWQSX(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVWQSX x:(MOVWload [off] {sym} ptr mem))
- // cond: x.Uses == 1
+ // cond: x.Uses == 1 && clobber(x)
// result: @x.Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
for {
x := v.Args[0]
@@ -9846,7 +10125,7 @@ func rewriteValueAMD64_OpAMD64MOVWQSX(v *Value, config *Config) bool {
sym := x.Aux
ptr := x.Args[0]
mem := x.Args[1]
- if !(x.Uses == 1) {
+ if !(x.Uses == 1 && clobber(x)) {
break
}
b = x.Block
@@ -9859,12 +10138,12 @@ func rewriteValueAMD64_OpAMD64MOVWQSX(v *Value, config *Config) bool {
v0.AddArg(mem)
return true
}
- // match: (MOVWQSX (ANDWconst [c] x))
+ // match: (MOVWQSX (ANDLconst [c] x))
// cond: c & 0x8000 == 0
- // result: (ANDQconst [c & 0x7fff] x)
+ // result: (ANDLconst [c & 0x7fff] x)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDWconst {
+ if v_0.Op != OpAMD64ANDLconst {
break
}
c := v_0.AuxInt
@@ -9872,7 +10151,7 @@ func rewriteValueAMD64_OpAMD64MOVWQSX(v *Value, config *Config) bool {
if !(c&0x8000 == 0) {
break
}
- v.reset(OpAMD64ANDQconst)
+ v.reset(OpAMD64ANDLconst)
v.AuxInt = c & 0x7fff
v.AddArg(x)
return true
@@ -9912,7 +10191,7 @@ func rewriteValueAMD64_OpAMD64MOVWQZX(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVWQZX x:(MOVWload [off] {sym} ptr mem))
- // cond: x.Uses == 1
+ // cond: x.Uses == 1 && clobber(x)
// result: @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
for {
x := v.Args[0]
@@ -9923,7 +10202,7 @@ func rewriteValueAMD64_OpAMD64MOVWQZX(v *Value, config *Config) bool {
sym := x.Aux
ptr := x.Args[0]
mem := x.Args[1]
- if !(x.Uses == 1) {
+ if !(x.Uses == 1 && clobber(x)) {
break
}
b = x.Block
@@ -9937,7 +10216,7 @@ func rewriteValueAMD64_OpAMD64MOVWQZX(v *Value, config *Config) bool {
return true
}
// match: (MOVWQZX x:(MOVWloadidx1 [off] {sym} ptr idx mem))
- // cond: x.Uses == 1
+ // cond: x.Uses == 1 && clobber(x)
// result: @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem)
for {
x := v.Args[0]
@@ -9949,7 +10228,7 @@ func rewriteValueAMD64_OpAMD64MOVWQZX(v *Value, config *Config) bool {
ptr := x.Args[0]
idx := x.Args[1]
mem := x.Args[2]
- if !(x.Uses == 1) {
+ if !(x.Uses == 1 && clobber(x)) {
break
}
b = x.Block
@@ -9964,7 +10243,7 @@ func rewriteValueAMD64_OpAMD64MOVWQZX(v *Value, config *Config) bool {
return true
}
// match: (MOVWQZX x:(MOVWloadidx2 [off] {sym} ptr idx mem))
- // cond: x.Uses == 1
+ // cond: x.Uses == 1 && clobber(x)
// result: @x.Block (MOVWloadidx2 <v.Type> [off] {sym} ptr idx mem)
for {
x := v.Args[0]
@@ -9976,7 +10255,7 @@ func rewriteValueAMD64_OpAMD64MOVWQZX(v *Value, config *Config) bool {
ptr := x.Args[0]
idx := x.Args[1]
mem := x.Args[2]
- if !(x.Uses == 1) {
+ if !(x.Uses == 1 && clobber(x)) {
break
}
b = x.Block
@@ -9990,17 +10269,17 @@ func rewriteValueAMD64_OpAMD64MOVWQZX(v *Value, config *Config) bool {
v0.AddArg(mem)
return true
}
- // match: (MOVWQZX (ANDWconst [c] x))
+ // match: (MOVWQZX (ANDLconst [c] x))
// cond:
- // result: (ANDQconst [c & 0xffff] x)
+ // result: (ANDLconst [c & 0xffff] x)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDWconst {
+ if v_0.Op != OpAMD64ANDLconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
- v.reset(OpAMD64ANDQconst)
+ v.reset(OpAMD64ANDLconst)
v.AuxInt = c & 0xffff
v.AddArg(x)
return true
@@ -10350,7 +10629,7 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- // match: (MOVWstore [off] {sym} ptr (MOVWconst [c]) mem)
+ // match: (MOVWstore [off] {sym} ptr (MOVLconst [c]) mem)
// cond: validOff(off)
// result: (MOVWstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
for {
@@ -10358,7 +10637,7 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
+ if v_1.Op != OpAMD64MOVLconst {
break
}
c := v_1.AuxInt
@@ -10481,6 +10760,97 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVWstore [i] {s} p (SHRQconst [16] w) x:(MOVWstore [i-2] {s} p w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVLstore [i-2] {s} p w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ if v_1.AuxInt != 16 {
+ break
+ }
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVWstore {
+ break
+ }
+ if x.AuxInt != i-2 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if w != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstore)
+ v.AuxInt = i - 2
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [i] {s} p (SHRQconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRQconst [j-16] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVLstore [i-2] {s} p w0 mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ j := v_1.AuxInt
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVWstore {
+ break
+ }
+ if x.AuxInt != i-2 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ w0 := x.Args[1]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-16 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstore)
+ v.AuxInt = i - 2
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w0)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVWstoreconst(v *Value, config *Config) bool {
@@ -10606,6 +10976,35 @@ func rewriteValueAMD64_OpAMD64MOVWstoreconst(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ x := v.Args[1]
+ if x.Op != OpAMD64MOVWstoreconst {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ mem := x.Args[1]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstoreconst)
+ v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVWstoreconstidx1(v *Value, config *Config) bool {
@@ -10679,6 +11078,40 @@ func rewriteValueAMD64_OpAMD64MOVWstoreconstidx1(v *Value, config *Config) bool
v.AddArg(mem)
return true
}
+ // match: (MOVWstoreconstidx1 [c] {s} p i x:(MOVWstoreconstidx1 [a] {s} p i mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p i mem)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ i := v.Args[1]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVWstoreconstidx1 {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if i != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstoreconstidx1)
+ v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(i)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVWstoreconstidx2(v *Value, config *Config) bool {
@@ -10728,6 +11161,43 @@ func rewriteValueAMD64_OpAMD64MOVWstoreconstidx2(v *Value, config *Config) bool
v.AddArg(mem)
return true
}
+ // match: (MOVWstoreconstidx2 [c] {s} p i x:(MOVWstoreconstidx2 [a] {s} p i mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p (SHLQconst <i.Type> [1] i) mem)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ i := v.Args[1]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVWstoreconstidx2 {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if i != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstoreconstidx1)
+ v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, i.Type)
+ v0.AuxInt = 1
+ v0.AddArg(i)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVWstoreidx1(v *Value, config *Config) bool {
@@ -10807,6 +11277,107 @@ func rewriteValueAMD64_OpAMD64MOVWstoreidx1(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVWstoreidx1 [i] {s} p idx (SHRQconst [16] w) x:(MOVWstoreidx1 [i-2] {s} p idx w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVLstoreidx1 [i-2] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
+ break
+ }
+ if v_2.AuxInt != 16 {
+ break
+ }
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVWstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-2 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ if w != x.Args[2] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstoreidx1)
+ v.AuxInt = i - 2
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVWstoreidx1 [i-2] {s} p idx w0:(SHRQconst [j-16] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVLstoreidx1 [i-2] {s} p idx w0 mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
+ break
+ }
+ j := v_2.AuxInt
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVWstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-2 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ w0 := x.Args[2]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-16 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstoreidx1)
+ v.AuxInt = i - 2
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w0)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVWstoreidx2(v *Value, config *Config) bool {
@@ -10860,58 +11431,111 @@ func rewriteValueAMD64_OpAMD64MOVWstoreidx2(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MULB(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MULB x (MOVBconst [c]))
- // cond:
- // result: (MULBconst [c] x)
+ // match: (MOVWstoreidx2 [i] {s} p idx (SHRQconst [16] w) x:(MOVWstoreidx2 [i-2] {s} p idx w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVLstoreidx1 [i-2] {s} p (SHLQconst <idx.Type> [1] idx) w mem)
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
break
}
- c := v_1.AuxInt
- v.reset(OpAMD64MULBconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (MULB (MOVBconst [c]) x)
- // cond:
- // result: (MULBconst [c] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
+ if v_2.AuxInt != 16 {
break
}
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64MULBconst)
- v.AuxInt = c
- v.AddArg(x)
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVWstoreidx2 {
+ break
+ }
+ if x.AuxInt != i-2 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ if w != x.Args[2] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstoreidx1)
+ v.AuxInt = i - 2
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, idx.Type)
+ v0.AuxInt = 1
+ v0.AddArg(idx)
+ v.AddArg(v0)
+ v.AddArg(w)
+ v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MULBconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MULBconst [c] (MOVBconst [d]))
- // cond:
- // result: (MOVBconst [int64(int8(c*d))])
+ // match: (MOVWstoreidx2 [i] {s} p idx (SHRQconst [j] w) x:(MOVWstoreidx2 [i-2] {s} p idx w0:(SHRQconst [j-16] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVLstoreidx1 [i-2] {s} p (SHLQconst <idx.Type> [1] idx) w0 mem)
for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
break
}
- d := v_0.AuxInt
- v.reset(OpAMD64MOVBconst)
- v.AuxInt = int64(int8(c * d))
+ j := v_2.AuxInt
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVWstoreidx2 {
+ break
+ }
+ if x.AuxInt != i-2 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ w0 := x.Args[2]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-16 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstoreidx1)
+ v.AuxInt = i - 2
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, idx.Type)
+ v0.AuxInt = 1
+ v0.AddArg(idx)
+ v.AddArg(v0)
+ v.AddArg(w0)
+ v.AddArg(mem)
return true
}
return false
@@ -11382,60 +12006,6 @@ func rewriteValueAMD64_OpAMD64MULQconst(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAMD64MULW(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MULW x (MOVWconst [c]))
- // cond:
- // result: (MULWconst [c] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64MULWconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (MULW (MOVWconst [c]) x)
- // cond:
- // result: (MULWconst [c] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64MULWconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64MULWconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MULWconst [c] (MOVWconst [d]))
- // cond:
- // result: (MOVWconst [int64(int16(c*d))])
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
- break
- }
- d := v_0.AuxInt
- v.reset(OpAMD64MOVWconst)
- v.AuxInt = int64(int16(c * d))
- return true
- }
- return false
-}
func rewriteValueAMD64_OpMod16(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -11931,11 +12501,11 @@ func rewriteValueAMD64_OpMul16(v *Value, config *Config) bool {
_ = b
// match: (Mul16 x y)
// cond:
- // result: (MULW x y)
+ // result: (MULL x y)
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64MULW)
+ v.reset(OpAMD64MULL)
v.AddArg(x)
v.AddArg(y)
return true
@@ -12011,35 +12581,17 @@ func rewriteValueAMD64_OpMul8(v *Value, config *Config) bool {
_ = b
// match: (Mul8 x y)
// cond:
- // result: (MULB x y)
+ // result: (MULL x y)
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64MULB)
+ v.reset(OpAMD64MULL)
v.AddArg(x)
v.AddArg(y)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64NEGB(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (NEGB (MOVBconst [c]))
- // cond:
- // result: (MOVBconst [int64(int8(-c))])
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
- break
- }
- c := v_0.AuxInt
- v.reset(OpAMD64MOVBconst)
- v.AuxInt = int64(int8(-c))
- return true
- }
- return false
-}
func rewriteValueAMD64_OpAMD64NEGL(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -12076,42 +12628,6 @@ func rewriteValueAMD64_OpAMD64NEGQ(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAMD64NEGW(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (NEGW (MOVWconst [c]))
- // cond:
- // result: (MOVWconst [int64(int16(-c))])
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
- break
- }
- c := v_0.AuxInt
- v.reset(OpAMD64MOVWconst)
- v.AuxInt = int64(int16(-c))
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64NOTB(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (NOTB (MOVBconst [c]))
- // cond:
- // result: (MOVBconst [^c])
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
- break
- }
- c := v_0.AuxInt
- v.reset(OpAMD64MOVBconst)
- v.AuxInt = ^c
- return true
- }
- return false
-}
func rewriteValueAMD64_OpAMD64NOTL(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -12148,33 +12664,15 @@ func rewriteValueAMD64_OpAMD64NOTQ(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAMD64NOTW(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (NOTW (MOVWconst [c]))
- // cond:
- // result: (MOVWconst [^c])
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
- break
- }
- c := v_0.AuxInt
- v.reset(OpAMD64MOVWconst)
- v.AuxInt = ^c
- return true
- }
- return false
-}
func rewriteValueAMD64_OpNeg16(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (Neg16 x)
// cond:
- // result: (NEGW x)
+ // result: (NEGL x)
for {
x := v.Args[0]
- v.reset(OpAMD64NEGW)
+ v.reset(OpAMD64NEGL)
v.AddArg(x)
return true
}
@@ -12247,10 +12745,10 @@ func rewriteValueAMD64_OpNeg8(v *Value, config *Config) bool {
_ = b
// match: (Neg8 x)
// cond:
- // result: (NEGB x)
+ // result: (NEGL x)
for {
x := v.Args[0]
- v.reset(OpAMD64NEGB)
+ v.reset(OpAMD64NEGL)
v.AddArg(x)
return true
}
@@ -12364,6 +12862,24 @@ func rewriteValueAMD64_OpNeq8(v *Value, config *Config) bool {
}
return false
}
+func rewriteValueAMD64_OpNeqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqB x y)
+ // cond:
+ // result: (SETNE (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETNE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
func rewriteValueAMD64_OpNeqPtr(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -12403,50 +12919,50 @@ func rewriteValueAMD64_OpNot(v *Value, config *Config) bool {
_ = b
// match: (Not x)
// cond:
- // result: (XORBconst [1] x)
+ // result: (XORLconst [1] x)
for {
x := v.Args[0]
- v.reset(OpAMD64XORBconst)
+ v.reset(OpAMD64XORLconst)
v.AuxInt = 1
v.AddArg(x)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64ORB(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (ORB x (MOVBconst [c]))
+ // match: (ORL x (MOVLconst [c]))
// cond:
- // result: (ORBconst [c] x)
+ // result: (ORLconst [c] x)
for {
x := v.Args[0]
v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
+ if v_1.Op != OpAMD64MOVLconst {
break
}
c := v_1.AuxInt
- v.reset(OpAMD64ORBconst)
+ v.reset(OpAMD64ORLconst)
v.AuxInt = c
v.AddArg(x)
return true
}
- // match: (ORB (MOVBconst [c]) x)
+ // match: (ORL (MOVLconst [c]) x)
// cond:
- // result: (ORBconst [c] x)
+ // result: (ORLconst [c] x)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
+ if v_0.Op != OpAMD64MOVLconst {
break
}
c := v_0.AuxInt
x := v.Args[1]
- v.reset(OpAMD64ORBconst)
+ v.reset(OpAMD64ORLconst)
v.AuxInt = c
v.AddArg(x)
return true
}
- // match: (ORB x x)
+ // match: (ORL x x)
// cond:
// result: x
for {
@@ -12459,112 +12975,67 @@ func rewriteValueAMD64_OpAMD64ORB(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64ORBconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ORBconst [c] x)
- // cond: int8(c)==0
- // result: x
+ // match: (ORL x0:(MOVBload [i] {s} p mem) s0:(SHLLconst [8] x1:(MOVBload [i+1] {s} p mem)))
+ // cond: x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)
+ // result: @mergePoint(b,x0,x1) (MOVWload [i] {s} p mem)
for {
- c := v.AuxInt
- x := v.Args[0]
- if !(int8(c) == 0) {
+ x0 := v.Args[0]
+ if x0.Op != OpAMD64MOVBload {
break
}
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (ORBconst [c] _)
- // cond: int8(c)==-1
- // result: (MOVBconst [-1])
- for {
- c := v.AuxInt
- if !(int8(c) == -1) {
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ s0 := v.Args[1]
+ if s0.Op != OpAMD64SHLLconst {
break
}
- v.reset(OpAMD64MOVBconst)
- v.AuxInt = -1
- return true
- }
- // match: (ORBconst [c] (MOVBconst [d]))
- // cond:
- // result: (MOVBconst [c|d])
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
+ if s0.AuxInt != 8 {
break
}
- d := v_0.AuxInt
- v.reset(OpAMD64MOVBconst)
- v.AuxInt = c | d
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ORL x (MOVLconst [c]))
- // cond:
- // result: (ORLconst [c] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
+ x1 := s0.Args[0]
+ if x1.Op != OpAMD64MOVBload {
break
}
- c := v_1.AuxInt
- v.reset(OpAMD64ORLconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ORL (MOVLconst [c]) x)
- // cond:
- // result: (ORLconst [c] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ if x1.AuxInt != i+1 {
break
}
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64ORLconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ORL x x)
- // cond:
- // result: x
- for {
- x := v.Args[0]
- if x != v.Args[1] {
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if mem != x1.Args[1] {
break
}
+ if !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+ break
+ }
+ b = mergePoint(b, x0, x1)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVWload, config.fe.TypeUInt16())
v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
+ v.AddArg(v0)
+ v0.AuxInt = i
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(mem)
return true
}
- // match: (ORL (ORL (ORL x0:(MOVBload [i] {s} p mem) (SHLLconst [8] x1:(MOVBload [i+1] {s} p mem))) (SHLLconst [16] x2:(MOVBload [i+2] {s} p mem))) (SHLLconst [24] x3:(MOVBload [i+3] {s} p mem)))
- // cond: mergePoint(b,x0,x1,x2,x3) != nil
+ // match: (ORL o0:(ORL o1:(ORL x0:(MOVBload [i] {s} p mem) s0:(SHLLconst [8] x1:(MOVBload [i+1] {s} p mem))) s1:(SHLLconst [16] x2:(MOVBload [i+2] {s} p mem))) s2:(SHLLconst [24] x3:(MOVBload [i+3] {s} p mem)))
+ // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && mergePoint(b,x0,x1,x2,x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(s0) && clobber(s1) && clobber(s2) && clobber(o0) && clobber(o1)
// result: @mergePoint(b,x0,x1,x2,x3) (MOVLload [i] {s} p mem)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ORL {
+ o0 := v.Args[0]
+ if o0.Op != OpAMD64ORL {
break
}
- v_0_0 := v_0.Args[0]
- if v_0_0.Op != OpAMD64ORL {
+ o1 := o0.Args[0]
+ if o1.Op != OpAMD64ORL {
break
}
- x0 := v_0_0.Args[0]
+ x0 := o1.Args[0]
if x0.Op != OpAMD64MOVBload {
break
}
@@ -12572,14 +13043,14 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
s := x0.Aux
p := x0.Args[0]
mem := x0.Args[1]
- v_0_0_1 := v_0_0.Args[1]
- if v_0_0_1.Op != OpAMD64SHLLconst {
+ s0 := o1.Args[1]
+ if s0.Op != OpAMD64SHLLconst {
break
}
- if v_0_0_1.AuxInt != 8 {
+ if s0.AuxInt != 8 {
break
}
- x1 := v_0_0_1.Args[0]
+ x1 := s0.Args[0]
if x1.Op != OpAMD64MOVBload {
break
}
@@ -12595,14 +13066,14 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
if mem != x1.Args[1] {
break
}
- v_0_1 := v_0.Args[1]
- if v_0_1.Op != OpAMD64SHLLconst {
+ s1 := o0.Args[1]
+ if s1.Op != OpAMD64SHLLconst {
break
}
- if v_0_1.AuxInt != 16 {
+ if s1.AuxInt != 16 {
break
}
- x2 := v_0_1.Args[0]
+ x2 := s1.Args[0]
if x2.Op != OpAMD64MOVBload {
break
}
@@ -12618,14 +13089,14 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
if mem != x2.Args[1] {
break
}
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLLconst {
+ s2 := v.Args[1]
+ if s2.Op != OpAMD64SHLLconst {
break
}
- if v_1.AuxInt != 24 {
+ if s2.AuxInt != 24 {
break
}
- x3 := v_1.Args[0]
+ x3 := s2.Args[0]
if x3.Op != OpAMD64MOVBload {
break
}
@@ -12641,7 +13112,7 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
if mem != x3.Args[1] {
break
}
- if !(mergePoint(b, x0, x1, x2, x3) != nil) {
+ if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && mergePoint(b, x0, x1, x2, x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(s0) && clobber(s1) && clobber(s2) && clobber(o0) && clobber(o1)) {
break
}
b = mergePoint(b, x0, x1, x2, x3)
@@ -12654,19 +13125,72 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
v0.AddArg(mem)
return true
}
- // match: (ORL (ORL (ORL x0:(MOVBloadidx1 [i] {s} p idx mem) (SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem))) (SHLLconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem))) (SHLLconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem)))
- // cond: mergePoint(b,x0,x1,x2,x3) != nil
+ // match: (ORL x0:(MOVBloadidx1 [i] {s} p idx mem) s0:(SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
+ // cond: x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)
+ // result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i] {s} p idx mem)
+ for {
+ x0 := v.Args[0]
+ if x0.Op != OpAMD64MOVBloadidx1 {
+ break
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ idx := x0.Args[1]
+ mem := x0.Args[2]
+ s0 := v.Args[1]
+ if s0.Op != OpAMD64SHLLconst {
+ break
+ }
+ if s0.AuxInt != 8 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != OpAMD64MOVBloadidx1 {
+ break
+ }
+ if x1.AuxInt != i+1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if idx != x1.Args[1] {
+ break
+ }
+ if mem != x1.Args[2] {
+ break
+ }
+ if !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+ break
+ }
+ b = mergePoint(b, x0, x1)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVWloadidx1, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = i
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(idx)
+ v0.AddArg(mem)
+ return true
+ }
+ // match: (ORL o0:(ORL o1:(ORL x0:(MOVBloadidx1 [i] {s} p idx mem) s0:(SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem))) s1:(SHLLconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem))) s2:(SHLLconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem)))
+ // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && mergePoint(b,x0,x1,x2,x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(s0) && clobber(s1) && clobber(s2) && clobber(o0) && clobber(o1)
// result: @mergePoint(b,x0,x1,x2,x3) (MOVLloadidx1 <v.Type> [i] {s} p idx mem)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ORL {
+ o0 := v.Args[0]
+ if o0.Op != OpAMD64ORL {
break
}
- v_0_0 := v_0.Args[0]
- if v_0_0.Op != OpAMD64ORL {
+ o1 := o0.Args[0]
+ if o1.Op != OpAMD64ORL {
break
}
- x0 := v_0_0.Args[0]
+ x0 := o1.Args[0]
if x0.Op != OpAMD64MOVBloadidx1 {
break
}
@@ -12675,14 +13199,14 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
p := x0.Args[0]
idx := x0.Args[1]
mem := x0.Args[2]
- v_0_0_1 := v_0_0.Args[1]
- if v_0_0_1.Op != OpAMD64SHLLconst {
+ s0 := o1.Args[1]
+ if s0.Op != OpAMD64SHLLconst {
break
}
- if v_0_0_1.AuxInt != 8 {
+ if s0.AuxInt != 8 {
break
}
- x1 := v_0_0_1.Args[0]
+ x1 := s0.Args[0]
if x1.Op != OpAMD64MOVBloadidx1 {
break
}
@@ -12701,14 +13225,14 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
if mem != x1.Args[2] {
break
}
- v_0_1 := v_0.Args[1]
- if v_0_1.Op != OpAMD64SHLLconst {
+ s1 := o0.Args[1]
+ if s1.Op != OpAMD64SHLLconst {
break
}
- if v_0_1.AuxInt != 16 {
+ if s1.AuxInt != 16 {
break
}
- x2 := v_0_1.Args[0]
+ x2 := s1.Args[0]
if x2.Op != OpAMD64MOVBloadidx1 {
break
}
@@ -12727,14 +13251,14 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
if mem != x2.Args[2] {
break
}
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLLconst {
+ s2 := v.Args[1]
+ if s2.Op != OpAMD64SHLLconst {
break
}
- if v_1.AuxInt != 24 {
+ if s2.AuxInt != 24 {
break
}
- x3 := v_1.Args[0]
+ x3 := s2.Args[0]
if x3.Op != OpAMD64MOVBloadidx1 {
break
}
@@ -12753,7 +13277,7 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
if mem != x3.Args[2] {
break
}
- if !(mergePoint(b, x0, x1, x2, x3) != nil) {
+ if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && mergePoint(b, x0, x1, x2, x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(s0) && clobber(s1) && clobber(s2) && clobber(o0) && clobber(o1)) {
break
}
b = mergePoint(b, x0, x1, x2, x3)
@@ -12866,35 +13390,35 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- // match: (ORQ (ORQ (ORQ (ORQ (ORQ (ORQ (ORQ x0:(MOVBload [i] {s} p mem) (SHLQconst [8] x1:(MOVBload [i+1] {s} p mem))) (SHLQconst [16] x2:(MOVBload [i+2] {s} p mem))) (SHLQconst [24] x3:(MOVBload [i+3] {s} p mem))) (SHLQconst [32] x4:(MOVBload [i+4] {s} p mem))) (SHLQconst [40] x5:(MOVBload [i+5] {s} p mem))) (SHLQconst [48] x6:(MOVBload [i+6] {s} p mem))) (SHLQconst [56] x7:(MOVBload [i+7] {s} p mem)))
- // cond: mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
+ // match: (ORQ o0:(ORQ o1:(ORQ o2:(ORQ o3:(ORQ o4:(ORQ o5:(ORQ x0:(MOVBload [i] {s} p mem) s0:(SHLQconst [8] x1:(MOVBload [i+1] {s} p mem))) s1:(SHLQconst [16] x2:(MOVBload [i+2] {s} p mem))) s2:(SHLQconst [24] x3:(MOVBload [i+3] {s} p mem))) s3:(SHLQconst [32] x4:(MOVBload [i+4] {s} p mem))) s4:(SHLQconst [40] x5:(MOVBload [i+5] {s} p mem))) s5:(SHLQconst [48] x6:(MOVBload [i+6] {s} p mem))) s6:(SHLQconst [56] x7:(MOVBload [i+7] {s} p mem)))
+ // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(x5) && clobber(x6) && clobber(x7) && clobber(s0) && clobber(s1) && clobber(s2) && clobber(s3) && clobber(s4) && clobber(s5) && clobber(s6) && clobber(o0) && clobber(o1) && clobber(o2) && clobber(o3) && clobber(o4) && clobber(o5)
// result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVQload [i] {s} p mem)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ORQ {
+ o0 := v.Args[0]
+ if o0.Op != OpAMD64ORQ {
break
}
- v_0_0 := v_0.Args[0]
- if v_0_0.Op != OpAMD64ORQ {
+ o1 := o0.Args[0]
+ if o1.Op != OpAMD64ORQ {
break
}
- v_0_0_0 := v_0_0.Args[0]
- if v_0_0_0.Op != OpAMD64ORQ {
+ o2 := o1.Args[0]
+ if o2.Op != OpAMD64ORQ {
break
}
- v_0_0_0_0 := v_0_0_0.Args[0]
- if v_0_0_0_0.Op != OpAMD64ORQ {
+ o3 := o2.Args[0]
+ if o3.Op != OpAMD64ORQ {
break
}
- v_0_0_0_0_0 := v_0_0_0_0.Args[0]
- if v_0_0_0_0_0.Op != OpAMD64ORQ {
+ o4 := o3.Args[0]
+ if o4.Op != OpAMD64ORQ {
break
}
- v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
- if v_0_0_0_0_0_0.Op != OpAMD64ORQ {
+ o5 := o4.Args[0]
+ if o5.Op != OpAMD64ORQ {
break
}
- x0 := v_0_0_0_0_0_0.Args[0]
+ x0 := o5.Args[0]
if x0.Op != OpAMD64MOVBload {
break
}
@@ -12902,14 +13426,14 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
s := x0.Aux
p := x0.Args[0]
mem := x0.Args[1]
- v_0_0_0_0_0_0_1 := v_0_0_0_0_0_0.Args[1]
- if v_0_0_0_0_0_0_1.Op != OpAMD64SHLQconst {
+ s0 := o5.Args[1]
+ if s0.Op != OpAMD64SHLQconst {
break
}
- if v_0_0_0_0_0_0_1.AuxInt != 8 {
+ if s0.AuxInt != 8 {
break
}
- x1 := v_0_0_0_0_0_0_1.Args[0]
+ x1 := s0.Args[0]
if x1.Op != OpAMD64MOVBload {
break
}
@@ -12925,14 +13449,14 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x1.Args[1] {
break
}
- v_0_0_0_0_0_1 := v_0_0_0_0_0.Args[1]
- if v_0_0_0_0_0_1.Op != OpAMD64SHLQconst {
+ s1 := o4.Args[1]
+ if s1.Op != OpAMD64SHLQconst {
break
}
- if v_0_0_0_0_0_1.AuxInt != 16 {
+ if s1.AuxInt != 16 {
break
}
- x2 := v_0_0_0_0_0_1.Args[0]
+ x2 := s1.Args[0]
if x2.Op != OpAMD64MOVBload {
break
}
@@ -12948,14 +13472,14 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x2.Args[1] {
break
}
- v_0_0_0_0_1 := v_0_0_0_0.Args[1]
- if v_0_0_0_0_1.Op != OpAMD64SHLQconst {
+ s2 := o3.Args[1]
+ if s2.Op != OpAMD64SHLQconst {
break
}
- if v_0_0_0_0_1.AuxInt != 24 {
+ if s2.AuxInt != 24 {
break
}
- x3 := v_0_0_0_0_1.Args[0]
+ x3 := s2.Args[0]
if x3.Op != OpAMD64MOVBload {
break
}
@@ -12971,14 +13495,14 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x3.Args[1] {
break
}
- v_0_0_0_1 := v_0_0_0.Args[1]
- if v_0_0_0_1.Op != OpAMD64SHLQconst {
+ s3 := o2.Args[1]
+ if s3.Op != OpAMD64SHLQconst {
break
}
- if v_0_0_0_1.AuxInt != 32 {
+ if s3.AuxInt != 32 {
break
}
- x4 := v_0_0_0_1.Args[0]
+ x4 := s3.Args[0]
if x4.Op != OpAMD64MOVBload {
break
}
@@ -12994,14 +13518,14 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x4.Args[1] {
break
}
- v_0_0_1 := v_0_0.Args[1]
- if v_0_0_1.Op != OpAMD64SHLQconst {
+ s4 := o1.Args[1]
+ if s4.Op != OpAMD64SHLQconst {
break
}
- if v_0_0_1.AuxInt != 40 {
+ if s4.AuxInt != 40 {
break
}
- x5 := v_0_0_1.Args[0]
+ x5 := s4.Args[0]
if x5.Op != OpAMD64MOVBload {
break
}
@@ -13017,14 +13541,14 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x5.Args[1] {
break
}
- v_0_1 := v_0.Args[1]
- if v_0_1.Op != OpAMD64SHLQconst {
+ s5 := o0.Args[1]
+ if s5.Op != OpAMD64SHLQconst {
break
}
- if v_0_1.AuxInt != 48 {
+ if s5.AuxInt != 48 {
break
}
- x6 := v_0_1.Args[0]
+ x6 := s5.Args[0]
if x6.Op != OpAMD64MOVBload {
break
}
@@ -13040,14 +13564,14 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x6.Args[1] {
break
}
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
+ s6 := v.Args[1]
+ if s6.Op != OpAMD64SHLQconst {
break
}
- if v_1.AuxInt != 56 {
+ if s6.AuxInt != 56 {
break
}
- x7 := v_1.Args[0]
+ x7 := s6.Args[0]
if x7.Op != OpAMD64MOVBload {
break
}
@@ -13063,7 +13587,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x7.Args[1] {
break
}
- if !(mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7) != nil) {
+ if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(x5) && clobber(x6) && clobber(x7) && clobber(s0) && clobber(s1) && clobber(s2) && clobber(s3) && clobber(s4) && clobber(s5) && clobber(s6) && clobber(o0) && clobber(o1) && clobber(o2) && clobber(o3) && clobber(o4) && clobber(o5)) {
break
}
b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
@@ -13076,35 +13600,35 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
v0.AddArg(mem)
return true
}
- // match: (ORQ (ORQ (ORQ (ORQ (ORQ (ORQ (ORQ x0:(MOVBloadidx1 [i] {s} p idx mem) (SHLQconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem))) (SHLQconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem))) (SHLQconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem))) (SHLQconst [32] x4:(MOVBloadidx1 [i+4] {s} p idx mem))) (SHLQconst [40] x5:(MOVBloadidx1 [i+5] {s} p idx mem))) (SHLQconst [48] x6:(MOVBloadidx1 [i+6] {s} p idx mem))) (SHLQconst [56] x7:(MOVBloadidx1 [i+7] {s} p idx mem)))
- // cond: mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
+ // match: (ORQ o0:(ORQ o1:(ORQ o2:(ORQ o3:(ORQ o4:(ORQ o5:(ORQ x0:(MOVBloadidx1 [i] {s} p idx mem) s0:(SHLQconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem))) s1:(SHLQconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem))) s2:(SHLQconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem))) s3:(SHLQconst [32] x4:(MOVBloadidx1 [i+4] {s} p idx mem))) s4:(SHLQconst [40] x5:(MOVBloadidx1 [i+5] {s} p idx mem))) s5:(SHLQconst [48] x6:(MOVBloadidx1 [i+6] {s} p idx mem))) s6:(SHLQconst [56] x7:(MOVBloadidx1 [i+7] {s} p idx mem)))
+ // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(x5) && clobber(x6) && clobber(x7) && clobber(s0) && clobber(s1) && clobber(s2) && clobber(s3) && clobber(s4) && clobber(s5) && clobber(s6) && clobber(o0) && clobber(o1) && clobber(o2) && clobber(o3) && clobber(o4) && clobber(o5)
// result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVQloadidx1 <v.Type> [i] {s} p idx mem)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ORQ {
+ o0 := v.Args[0]
+ if o0.Op != OpAMD64ORQ {
break
}
- v_0_0 := v_0.Args[0]
- if v_0_0.Op != OpAMD64ORQ {
+ o1 := o0.Args[0]
+ if o1.Op != OpAMD64ORQ {
break
}
- v_0_0_0 := v_0_0.Args[0]
- if v_0_0_0.Op != OpAMD64ORQ {
+ o2 := o1.Args[0]
+ if o2.Op != OpAMD64ORQ {
break
}
- v_0_0_0_0 := v_0_0_0.Args[0]
- if v_0_0_0_0.Op != OpAMD64ORQ {
+ o3 := o2.Args[0]
+ if o3.Op != OpAMD64ORQ {
break
}
- v_0_0_0_0_0 := v_0_0_0_0.Args[0]
- if v_0_0_0_0_0.Op != OpAMD64ORQ {
+ o4 := o3.Args[0]
+ if o4.Op != OpAMD64ORQ {
break
}
- v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
- if v_0_0_0_0_0_0.Op != OpAMD64ORQ {
+ o5 := o4.Args[0]
+ if o5.Op != OpAMD64ORQ {
break
}
- x0 := v_0_0_0_0_0_0.Args[0]
+ x0 := o5.Args[0]
if x0.Op != OpAMD64MOVBloadidx1 {
break
}
@@ -13113,14 +13637,14 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
p := x0.Args[0]
idx := x0.Args[1]
mem := x0.Args[2]
- v_0_0_0_0_0_0_1 := v_0_0_0_0_0_0.Args[1]
- if v_0_0_0_0_0_0_1.Op != OpAMD64SHLQconst {
+ s0 := o5.Args[1]
+ if s0.Op != OpAMD64SHLQconst {
break
}
- if v_0_0_0_0_0_0_1.AuxInt != 8 {
+ if s0.AuxInt != 8 {
break
}
- x1 := v_0_0_0_0_0_0_1.Args[0]
+ x1 := s0.Args[0]
if x1.Op != OpAMD64MOVBloadidx1 {
break
}
@@ -13139,14 +13663,14 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x1.Args[2] {
break
}
- v_0_0_0_0_0_1 := v_0_0_0_0_0.Args[1]
- if v_0_0_0_0_0_1.Op != OpAMD64SHLQconst {
+ s1 := o4.Args[1]
+ if s1.Op != OpAMD64SHLQconst {
break
}
- if v_0_0_0_0_0_1.AuxInt != 16 {
+ if s1.AuxInt != 16 {
break
}
- x2 := v_0_0_0_0_0_1.Args[0]
+ x2 := s1.Args[0]
if x2.Op != OpAMD64MOVBloadidx1 {
break
}
@@ -13165,14 +13689,14 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x2.Args[2] {
break
}
- v_0_0_0_0_1 := v_0_0_0_0.Args[1]
- if v_0_0_0_0_1.Op != OpAMD64SHLQconst {
+ s2 := o3.Args[1]
+ if s2.Op != OpAMD64SHLQconst {
break
}
- if v_0_0_0_0_1.AuxInt != 24 {
+ if s2.AuxInt != 24 {
break
}
- x3 := v_0_0_0_0_1.Args[0]
+ x3 := s2.Args[0]
if x3.Op != OpAMD64MOVBloadidx1 {
break
}
@@ -13191,14 +13715,14 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x3.Args[2] {
break
}
- v_0_0_0_1 := v_0_0_0.Args[1]
- if v_0_0_0_1.Op != OpAMD64SHLQconst {
+ s3 := o2.Args[1]
+ if s3.Op != OpAMD64SHLQconst {
break
}
- if v_0_0_0_1.AuxInt != 32 {
+ if s3.AuxInt != 32 {
break
}
- x4 := v_0_0_0_1.Args[0]
+ x4 := s3.Args[0]
if x4.Op != OpAMD64MOVBloadidx1 {
break
}
@@ -13217,14 +13741,14 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x4.Args[2] {
break
}
- v_0_0_1 := v_0_0.Args[1]
- if v_0_0_1.Op != OpAMD64SHLQconst {
+ s4 := o1.Args[1]
+ if s4.Op != OpAMD64SHLQconst {
break
}
- if v_0_0_1.AuxInt != 40 {
+ if s4.AuxInt != 40 {
break
}
- x5 := v_0_0_1.Args[0]
+ x5 := s4.Args[0]
if x5.Op != OpAMD64MOVBloadidx1 {
break
}
@@ -13243,14 +13767,14 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x5.Args[2] {
break
}
- v_0_1 := v_0.Args[1]
- if v_0_1.Op != OpAMD64SHLQconst {
+ s5 := o0.Args[1]
+ if s5.Op != OpAMD64SHLQconst {
break
}
- if v_0_1.AuxInt != 48 {
+ if s5.AuxInt != 48 {
break
}
- x6 := v_0_1.Args[0]
+ x6 := s5.Args[0]
if x6.Op != OpAMD64MOVBloadidx1 {
break
}
@@ -13269,14 +13793,14 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x6.Args[2] {
break
}
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
+ s6 := v.Args[1]
+ if s6.Op != OpAMD64SHLQconst {
break
}
- if v_1.AuxInt != 56 {
+ if s6.AuxInt != 56 {
break
}
- x7 := v_1.Args[0]
+ x7 := s6.Args[0]
if x7.Op != OpAMD64MOVBloadidx1 {
break
}
@@ -13295,7 +13819,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x7.Args[2] {
break
}
- if !(mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7) != nil) {
+ if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(x5) && clobber(x6) && clobber(x7) && clobber(s0) && clobber(s1) && clobber(s2) && clobber(s3) && clobber(s4) && clobber(s5) && clobber(s6) && clobber(o0) && clobber(o1) && clobber(o2) && clobber(o3) && clobber(o4) && clobber(o5)) {
break
}
b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
@@ -13354,200 +13878,6 @@ func rewriteValueAMD64_OpAMD64ORQconst(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAMD64ORW(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ORW x (MOVWconst [c]))
- // cond:
- // result: (ORWconst [c] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64ORWconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ORW (MOVWconst [c]) x)
- // cond:
- // result: (ORWconst [c] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64ORWconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ORW x x)
- // cond:
- // result: x
- for {
- x := v.Args[0]
- if x != v.Args[1] {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (ORW x0:(MOVBload [i] {s} p mem) (SHLWconst [8] x1:(MOVBload [i+1] {s} p mem)))
- // cond: mergePoint(b,x0,x1) != nil
- // result: @mergePoint(b,x0,x1) (MOVWload [i] {s} p mem)
- for {
- x0 := v.Args[0]
- if x0.Op != OpAMD64MOVBload {
- break
- }
- i := x0.AuxInt
- s := x0.Aux
- p := x0.Args[0]
- mem := x0.Args[1]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLWconst {
- break
- }
- if v_1.AuxInt != 8 {
- break
- }
- x1 := v_1.Args[0]
- if x1.Op != OpAMD64MOVBload {
- break
- }
- if x1.AuxInt != i+1 {
- break
- }
- if x1.Aux != s {
- break
- }
- if p != x1.Args[0] {
- break
- }
- if mem != x1.Args[1] {
- break
- }
- if !(mergePoint(b, x0, x1) != nil) {
- break
- }
- b = mergePoint(b, x0, x1)
- v0 := b.NewValue0(v.Line, OpAMD64MOVWload, config.fe.TypeUInt16())
- v.reset(OpCopy)
- v.AddArg(v0)
- v0.AuxInt = i
- v0.Aux = s
- v0.AddArg(p)
- v0.AddArg(mem)
- return true
- }
- // match: (ORW x0:(MOVBloadidx1 [i] {s} p idx mem) (SHLWconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
- // cond: mergePoint(b,x0,x1) != nil
- // result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i] {s} p idx mem)
- for {
- x0 := v.Args[0]
- if x0.Op != OpAMD64MOVBloadidx1 {
- break
- }
- i := x0.AuxInt
- s := x0.Aux
- p := x0.Args[0]
- idx := x0.Args[1]
- mem := x0.Args[2]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLWconst {
- break
- }
- if v_1.AuxInt != 8 {
- break
- }
- x1 := v_1.Args[0]
- if x1.Op != OpAMD64MOVBloadidx1 {
- break
- }
- if x1.AuxInt != i+1 {
- break
- }
- if x1.Aux != s {
- break
- }
- if p != x1.Args[0] {
- break
- }
- if idx != x1.Args[1] {
- break
- }
- if mem != x1.Args[2] {
- break
- }
- if !(mergePoint(b, x0, x1) != nil) {
- break
- }
- b = mergePoint(b, x0, x1)
- v0 := b.NewValue0(v.Line, OpAMD64MOVWloadidx1, v.Type)
- v.reset(OpCopy)
- v.AddArg(v0)
- v0.AuxInt = i
- v0.Aux = s
- v0.AddArg(p)
- v0.AddArg(idx)
- v0.AddArg(mem)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64ORWconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ORWconst [c] x)
- // cond: int16(c)==0
- // result: x
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(int16(c) == 0) {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (ORWconst [c] _)
- // cond: int16(c)==-1
- // result: (MOVWconst [-1])
- for {
- c := v.AuxInt
- if !(int16(c) == -1) {
- break
- }
- v.reset(OpAMD64MOVWconst)
- v.AuxInt = -1
- return true
- }
- // match: (ORWconst [c] (MOVWconst [d]))
- // cond:
- // result: (MOVWconst [c|d])
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
- break
- }
- d := v_0.AuxInt
- v.reset(OpAMD64MOVWconst)
- v.AuxInt = c | d
- return true
- }
- return false
-}
func rewriteValueAMD64_OpOffPtr(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -13585,11 +13915,11 @@ func rewriteValueAMD64_OpOr16(v *Value, config *Config) bool {
_ = b
// match: (Or16 x y)
// cond:
- // result: (ORW x y)
+ // result: (ORL x y)
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ORW)
+ v.reset(OpAMD64ORL)
v.AddArg(x)
v.AddArg(y)
return true
@@ -13633,11 +13963,27 @@ func rewriteValueAMD64_OpOr8(v *Value, config *Config) bool {
_ = b
// match: (Or8 x y)
// cond:
- // result: (ORB x y)
+ // result: (ORL x y)
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ORB)
+ v.reset(OpAMD64ORL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpOrB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OrB x y)
+ // cond:
+ // result: (ORL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ORL)
v.AddArg(x)
v.AddArg(y)
return true
@@ -13649,12 +13995,12 @@ func rewriteValueAMD64_OpRsh16Ux16(v *Value, config *Config) bool {
_ = b
// match: (Rsh16Ux16 <t> x y)
// cond:
- // result: (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPWconst y [16])))
+ // result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPWconst y [16])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDW)
+ v.reset(OpAMD64ANDL)
v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
v0.AddArg(x)
v0.AddArg(y)
@@ -13674,12 +14020,12 @@ func rewriteValueAMD64_OpRsh16Ux32(v *Value, config *Config) bool {
_ = b
// match: (Rsh16Ux32 <t> x y)
// cond:
- // result: (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
+ // result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDW)
+ v.reset(OpAMD64ANDL)
v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
v0.AddArg(x)
v0.AddArg(y)
@@ -13699,12 +14045,12 @@ func rewriteValueAMD64_OpRsh16Ux64(v *Value, config *Config) bool {
_ = b
// match: (Rsh16Ux64 <t> x y)
// cond:
- // result: (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPQconst y [16])))
+ // result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPQconst y [16])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDW)
+ v.reset(OpAMD64ANDL)
v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
v0.AddArg(x)
v0.AddArg(y)
@@ -13724,12 +14070,12 @@ func rewriteValueAMD64_OpRsh16Ux8(v *Value, config *Config) bool {
_ = b
// match: (Rsh16Ux8 <t> x y)
// cond:
- // result: (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
+ // result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDW)
+ v.reset(OpAMD64ANDL)
v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
v0.AddArg(x)
v0.AddArg(y)
@@ -13749,7 +14095,7 @@ func rewriteValueAMD64_OpRsh16x16(v *Value, config *Config) bool {
_ = b
// match: (Rsh16x16 <t> x y)
// cond:
- // result: (SARW <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [16])))))
+ // result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [16])))))
for {
t := v.Type
x := v.Args[0]
@@ -13757,7 +14103,7 @@ func rewriteValueAMD64_OpRsh16x16(v *Value, config *Config) bool {
v.reset(OpAMD64SARW)
v.Type = t
v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORW, y.Type)
+ v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
v0.AddArg(y)
v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
@@ -13833,7 +14179,7 @@ func rewriteValueAMD64_OpRsh16x8(v *Value, config *Config) bool {
_ = b
// match: (Rsh16x8 <t> x y)
// cond:
- // result: (SARW <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [16])))))
+ // result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [16])))))
for {
t := v.Type
x := v.Args[0]
@@ -13841,7 +14187,7 @@ func rewriteValueAMD64_OpRsh16x8(v *Value, config *Config) bool {
v.reset(OpAMD64SARW)
v.Type = t
v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORB, y.Type)
+ v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
v0.AddArg(y)
v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
@@ -13961,7 +14307,7 @@ func rewriteValueAMD64_OpRsh32x16(v *Value, config *Config) bool {
_ = b
// match: (Rsh32x16 <t> x y)
// cond:
- // result: (SARL <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [32])))))
+ // result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [32])))))
for {
t := v.Type
x := v.Args[0]
@@ -13969,7 +14315,7 @@ func rewriteValueAMD64_OpRsh32x16(v *Value, config *Config) bool {
v.reset(OpAMD64SARL)
v.Type = t
v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORW, y.Type)
+ v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
v0.AddArg(y)
v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
@@ -14045,7 +14391,7 @@ func rewriteValueAMD64_OpRsh32x8(v *Value, config *Config) bool {
_ = b
// match: (Rsh32x8 <t> x y)
// cond:
- // result: (SARL <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [32])))))
+ // result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [32])))))
for {
t := v.Type
x := v.Args[0]
@@ -14053,7 +14399,7 @@ func rewriteValueAMD64_OpRsh32x8(v *Value, config *Config) bool {
v.reset(OpAMD64SARL)
v.Type = t
v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORB, y.Type)
+ v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
v0.AddArg(y)
v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
@@ -14173,7 +14519,7 @@ func rewriteValueAMD64_OpRsh64x16(v *Value, config *Config) bool {
_ = b
// match: (Rsh64x16 <t> x y)
// cond:
- // result: (SARQ <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [64])))))
+ // result: (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [64])))))
for {
t := v.Type
x := v.Args[0]
@@ -14181,7 +14527,7 @@ func rewriteValueAMD64_OpRsh64x16(v *Value, config *Config) bool {
v.reset(OpAMD64SARQ)
v.Type = t
v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORW, y.Type)
+ v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
v0.AddArg(y)
v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
@@ -14257,7 +14603,7 @@ func rewriteValueAMD64_OpRsh64x8(v *Value, config *Config) bool {
_ = b
// match: (Rsh64x8 <t> x y)
// cond:
- // result: (SARQ <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [64])))))
+ // result: (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [64])))))
for {
t := v.Type
x := v.Args[0]
@@ -14265,7 +14611,7 @@ func rewriteValueAMD64_OpRsh64x8(v *Value, config *Config) bool {
v.reset(OpAMD64SARQ)
v.Type = t
v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORB, y.Type)
+ v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
v0.AddArg(y)
v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
@@ -14285,12 +14631,12 @@ func rewriteValueAMD64_OpRsh8Ux16(v *Value, config *Config) bool {
_ = b
// match: (Rsh8Ux16 <t> x y)
// cond:
- // result: (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
+ // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDB)
+ v.reset(OpAMD64ANDL)
v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
v0.AddArg(x)
v0.AddArg(y)
@@ -14310,12 +14656,12 @@ func rewriteValueAMD64_OpRsh8Ux32(v *Value, config *Config) bool {
_ = b
// match: (Rsh8Ux32 <t> x y)
// cond:
- // result: (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
+ // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDB)
+ v.reset(OpAMD64ANDL)
v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
v0.AddArg(x)
v0.AddArg(y)
@@ -14335,12 +14681,12 @@ func rewriteValueAMD64_OpRsh8Ux64(v *Value, config *Config) bool {
_ = b
// match: (Rsh8Ux64 <t> x y)
// cond:
- // result: (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPQconst y [8])))
+ // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPQconst y [8])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDB)
+ v.reset(OpAMD64ANDL)
v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
v0.AddArg(x)
v0.AddArg(y)
@@ -14360,12 +14706,12 @@ func rewriteValueAMD64_OpRsh8Ux8(v *Value, config *Config) bool {
_ = b
// match: (Rsh8Ux8 <t> x y)
// cond:
- // result: (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
+ // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDB)
+ v.reset(OpAMD64ANDL)
v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
v0.AddArg(x)
v0.AddArg(y)
@@ -14385,7 +14731,7 @@ func rewriteValueAMD64_OpRsh8x16(v *Value, config *Config) bool {
_ = b
// match: (Rsh8x16 <t> x y)
// cond:
- // result: (SARB <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [8])))))
+ // result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [8])))))
for {
t := v.Type
x := v.Args[0]
@@ -14393,7 +14739,7 @@ func rewriteValueAMD64_OpRsh8x16(v *Value, config *Config) bool {
v.reset(OpAMD64SARB)
v.Type = t
v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORW, y.Type)
+ v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
v0.AddArg(y)
v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
@@ -14469,7 +14815,7 @@ func rewriteValueAMD64_OpRsh8x8(v *Value, config *Config) bool {
_ = b
// match: (Rsh8x8 <t> x y)
// cond:
- // result: (SARB <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [8])))))
+ // result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [8])))))
for {
t := v.Type
x := v.Args[0]
@@ -14477,7 +14823,7 @@ func rewriteValueAMD64_OpRsh8x8(v *Value, config *Config) bool {
v.reset(OpAMD64SARB)
v.Type = t
v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORB, y.Type)
+ v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
v0.AddArg(y)
v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
@@ -14525,54 +14871,6 @@ func rewriteValueAMD64_OpAMD64SARB(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- // match: (SARB x (MOVWconst [c]))
- // cond:
- // result: (SARBconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SARBconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SARB x (MOVBconst [c]))
- // cond:
- // result: (SARBconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SARBconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SARB x (ANDBconst [31] y))
- // cond:
- // result: (SARB x y)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ANDBconst {
- break
- }
- if v_1.AuxInt != 31 {
- break
- }
- y := v_1.Args[0]
- v.reset(OpAMD64SARB)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
return false
}
func rewriteValueAMD64_OpAMD64SARBconst(v *Value, config *Config) bool {
@@ -14627,36 +14925,6 @@ func rewriteValueAMD64_OpAMD64SARL(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- // match: (SARL x (MOVWconst [c]))
- // cond:
- // result: (SARLconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SARLconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SARL x (MOVBconst [c]))
- // cond:
- // result: (SARLconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SARLconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
// match: (SARL x (ANDLconst [31] y))
// cond:
// result: (SARL x y)
@@ -14729,36 +14997,6 @@ func rewriteValueAMD64_OpAMD64SARQ(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- // match: (SARQ x (MOVWconst [c]))
- // cond:
- // result: (SARQconst [c&63] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SARQconst)
- v.AuxInt = c & 63
- v.AddArg(x)
- return true
- }
- // match: (SARQ x (MOVBconst [c]))
- // cond:
- // result: (SARQconst [c&63] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SARQconst)
- v.AuxInt = c & 63
- v.AddArg(x)
- return true
- }
// match: (SARQ x (ANDQconst [63] y))
// cond:
// result: (SARQ x y)
@@ -14831,54 +15069,6 @@ func rewriteValueAMD64_OpAMD64SARW(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- // match: (SARW x (MOVWconst [c]))
- // cond:
- // result: (SARWconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SARWconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SARW x (MOVBconst [c]))
- // cond:
- // result: (SARWconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SARWconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SARW x (ANDWconst [31] y))
- // cond:
- // result: (SARW x y)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ANDWconst {
- break
- }
- if v_1.AuxInt != 31 {
- break
- }
- y := v_1.Args[0]
- v.reset(OpAMD64SARW)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
return false
}
func rewriteValueAMD64_OpAMD64SARWconst(v *Value, config *Config) bool {
@@ -15048,61 +15238,61 @@ func rewriteValueAMD64_OpAMD64SETA(v *Value, config *Config) bool {
}
// match: (SETA (FlagEQ))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagEQ {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETA (FlagLT_ULT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETA (FlagLT_UGT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETA (FlagGT_ULT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETA (FlagGT_UGT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
@@ -15126,61 +15316,61 @@ func rewriteValueAMD64_OpAMD64SETAE(v *Value, config *Config) bool {
}
// match: (SETAE (FlagEQ))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagEQ {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETAE (FlagLT_ULT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETAE (FlagLT_UGT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETAE (FlagGT_ULT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETAE (FlagGT_UGT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
@@ -15204,61 +15394,61 @@ func rewriteValueAMD64_OpAMD64SETB(v *Value, config *Config) bool {
}
// match: (SETB (FlagEQ))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagEQ {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETB (FlagLT_ULT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETB (FlagLT_UGT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETB (FlagGT_ULT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETB (FlagGT_UGT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
@@ -15282,61 +15472,61 @@ func rewriteValueAMD64_OpAMD64SETBE(v *Value, config *Config) bool {
}
// match: (SETBE (FlagEQ))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagEQ {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETBE (FlagLT_ULT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETBE (FlagLT_UGT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETBE (FlagGT_ULT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETBE (FlagGT_UGT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
@@ -15360,61 +15550,61 @@ func rewriteValueAMD64_OpAMD64SETEQ(v *Value, config *Config) bool {
}
// match: (SETEQ (FlagEQ))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagEQ {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETEQ (FlagLT_ULT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETEQ (FlagLT_UGT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETEQ (FlagGT_ULT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETEQ (FlagGT_UGT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
@@ -15438,61 +15628,61 @@ func rewriteValueAMD64_OpAMD64SETG(v *Value, config *Config) bool {
}
// match: (SETG (FlagEQ))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagEQ {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETG (FlagLT_ULT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETG (FlagLT_UGT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETG (FlagGT_ULT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETG (FlagGT_UGT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
@@ -15516,61 +15706,61 @@ func rewriteValueAMD64_OpAMD64SETGE(v *Value, config *Config) bool {
}
// match: (SETGE (FlagEQ))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagEQ {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETGE (FlagLT_ULT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETGE (FlagLT_UGT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETGE (FlagGT_ULT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETGE (FlagGT_UGT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
@@ -15594,61 +15784,61 @@ func rewriteValueAMD64_OpAMD64SETL(v *Value, config *Config) bool {
}
// match: (SETL (FlagEQ))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagEQ {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETL (FlagLT_ULT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETL (FlagLT_UGT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETL (FlagGT_ULT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETL (FlagGT_UGT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
@@ -15672,61 +15862,61 @@ func rewriteValueAMD64_OpAMD64SETLE(v *Value, config *Config) bool {
}
// match: (SETLE (FlagEQ))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagEQ {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETLE (FlagLT_ULT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETLE (FlagLT_UGT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETLE (FlagGT_ULT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETLE (FlagGT_UGT))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
@@ -15750,149 +15940,66 @@ func rewriteValueAMD64_OpAMD64SETNE(v *Value, config *Config) bool {
}
// match: (SETNE (FlagEQ))
// cond:
- // result: (MOVBconst [0])
+ // result: (MOVLconst [0])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagEQ {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 0
return true
}
// match: (SETNE (FlagLT_ULT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETNE (FlagLT_UGT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagLT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETNE (FlagGT_ULT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_ULT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
// match: (SETNE (FlagGT_UGT))
// cond:
- // result: (MOVBconst [1])
+ // result: (MOVLconst [1])
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64FlagGT_UGT {
break
}
- v.reset(OpAMD64MOVBconst)
+ v.reset(OpAMD64MOVLconst)
v.AuxInt = 1
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64SHLB(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (SHLB x (MOVQconst [c]))
- // cond:
- // result: (SHLBconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLBconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SHLB x (MOVLconst [c]))
- // cond:
- // result: (SHLBconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLBconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SHLB x (MOVWconst [c]))
- // cond:
- // result: (SHLBconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLBconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SHLB x (MOVBconst [c]))
- // cond:
- // result: (SHLBconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLBconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SHLB x (ANDBconst [31] y))
- // cond:
- // result: (SHLB x y)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ANDBconst {
- break
- }
- if v_1.AuxInt != 31 {
- break
- }
- y := v_1.Args[0]
- v.reset(OpAMD64SHLB)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
- return false
-}
func rewriteValueAMD64_OpAMD64SHLL(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -15926,36 +16033,6 @@ func rewriteValueAMD64_OpAMD64SHLL(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- // match: (SHLL x (MOVWconst [c]))
- // cond:
- // result: (SHLLconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLLconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SHLL x (MOVBconst [c]))
- // cond:
- // result: (SHLLconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLLconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
// match: (SHLL x (ANDLconst [31] y))
// cond:
// result: (SHLL x y)
@@ -16009,36 +16086,6 @@ func rewriteValueAMD64_OpAMD64SHLQ(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- // match: (SHLQ x (MOVWconst [c]))
- // cond:
- // result: (SHLQconst [c&63] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLQconst)
- v.AuxInt = c & 63
- v.AddArg(x)
- return true
- }
- // match: (SHLQ x (MOVBconst [c]))
- // cond:
- // result: (SHLQconst [c&63] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLQconst)
- v.AuxInt = c & 63
- v.AddArg(x)
- return true
- }
// match: (SHLQ x (ANDQconst [63] y))
// cond:
// result: (SHLQ x y)
@@ -16059,89 +16106,6 @@ func rewriteValueAMD64_OpAMD64SHLQ(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAMD64SHLW(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (SHLW x (MOVQconst [c]))
- // cond:
- // result: (SHLWconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLWconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SHLW x (MOVLconst [c]))
- // cond:
- // result: (SHLWconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLWconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SHLW x (MOVWconst [c]))
- // cond:
- // result: (SHLWconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLWconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SHLW x (MOVBconst [c]))
- // cond:
- // result: (SHLWconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLWconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SHLW x (ANDWconst [31] y))
- // cond:
- // result: (SHLW x y)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ANDWconst {
- break
- }
- if v_1.AuxInt != 31 {
- break
- }
- y := v_1.Args[0]
- v.reset(OpAMD64SHLW)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
- return false
-}
func rewriteValueAMD64_OpAMD64SHRB(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -16175,54 +16139,6 @@ func rewriteValueAMD64_OpAMD64SHRB(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- // match: (SHRB x (MOVWconst [c]))
- // cond:
- // result: (SHRBconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRBconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SHRB x (MOVBconst [c]))
- // cond:
- // result: (SHRBconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRBconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SHRB x (ANDBconst [31] y))
- // cond:
- // result: (SHRB x y)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ANDBconst {
- break
- }
- if v_1.AuxInt != 31 {
- break
- }
- y := v_1.Args[0]
- v.reset(OpAMD64SHRB)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
return false
}
func rewriteValueAMD64_OpAMD64SHRL(v *Value, config *Config) bool {
@@ -16258,36 +16174,6 @@ func rewriteValueAMD64_OpAMD64SHRL(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- // match: (SHRL x (MOVWconst [c]))
- // cond:
- // result: (SHRLconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRLconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SHRL x (MOVBconst [c]))
- // cond:
- // result: (SHRLconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRLconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
// match: (SHRL x (ANDLconst [31] y))
// cond:
// result: (SHRL x y)
@@ -16341,36 +16227,6 @@ func rewriteValueAMD64_OpAMD64SHRQ(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- // match: (SHRQ x (MOVWconst [c]))
- // cond:
- // result: (SHRQconst [c&63] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRQconst)
- v.AuxInt = c & 63
- v.AddArg(x)
- return true
- }
- // match: (SHRQ x (MOVBconst [c]))
- // cond:
- // result: (SHRQconst [c&63] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRQconst)
- v.AuxInt = c & 63
- v.AddArg(x)
- return true
- }
// match: (SHRQ x (ANDQconst [63] y))
// cond:
// result: (SHRQ x y)
@@ -16424,152 +16280,6 @@ func rewriteValueAMD64_OpAMD64SHRW(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- // match: (SHRW x (MOVWconst [c]))
- // cond:
- // result: (SHRWconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRWconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SHRW x (MOVBconst [c]))
- // cond:
- // result: (SHRWconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRWconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SHRW x (ANDWconst [31] y))
- // cond:
- // result: (SHRW x y)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ANDWconst {
- break
- }
- if v_1.AuxInt != 31 {
- break
- }
- y := v_1.Args[0]
- v.reset(OpAMD64SHRW)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64SUBB(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (SUBB x (MOVBconst [c]))
- // cond:
- // result: (SUBBconst x [c])
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SUBBconst)
- v.AddArg(x)
- v.AuxInt = c
- return true
- }
- // match: (SUBB (MOVBconst [c]) x)
- // cond:
- // result: (NEGB (SUBBconst <v.Type> x [c]))
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64NEGB)
- v0 := b.NewValue0(v.Line, OpAMD64SUBBconst, v.Type)
- v0.AddArg(x)
- v0.AuxInt = c
- v.AddArg(v0)
- return true
- }
- // match: (SUBB x x)
- // cond:
- // result: (MOVBconst [0])
- for {
- x := v.Args[0]
- if x != v.Args[1] {
- break
- }
- v.reset(OpAMD64MOVBconst)
- v.AuxInt = 0
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64SUBBconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (SUBBconst [c] x)
- // cond: int8(c) == 0
- // result: x
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(int8(c) == 0) {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (SUBBconst (MOVBconst [d]) [c])
- // cond:
- // result: (MOVBconst [int64(int8(d-c))])
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
- break
- }
- d := v_0.AuxInt
- c := v.AuxInt
- v.reset(OpAMD64MOVBconst)
- v.AuxInt = int64(int8(d - c))
- return true
- }
- // match: (SUBBconst (SUBBconst x [d]) [c])
- // cond:
- // result: (ADDBconst [int64(int8(-c-d))] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64SUBBconst {
- break
- }
- x := v_0.Args[0]
- d := v_0.AuxInt
- c := v.AuxInt
- v.reset(OpAMD64ADDBconst)
- v.AuxInt = int64(int8(-c - d))
- v.AddArg(x)
- return true
- }
return false
}
func rewriteValueAMD64_OpAMD64SUBL(v *Value, config *Config) bool {
@@ -16638,6 +16348,17 @@ func rewriteValueAMD64_OpAMD64SUBLconst(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
+ // match: (SUBLconst [c] x)
+ // cond:
+ // result: (ADDLconst [int64(int32(-c))] x)
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ v.reset(OpAMD64ADDLconst)
+ v.AuxInt = int64(int32(-c))
+ v.AddArg(x)
+ return true
+ }
// match: (SUBLconst (MOVLconst [d]) [c])
// cond:
// result: (MOVLconst [int64(int32(d-c))])
@@ -16741,6 +16462,20 @@ func rewriteValueAMD64_OpAMD64SUBQconst(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
+ // match: (SUBQconst [c] x)
+ // cond: c != -(1<<31)
+ // result: (ADDQconst [-c] x)
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(c != -(1 << 31)) {
+ break
+ }
+ v.reset(OpAMD64ADDQconst)
+ v.AuxInt = -c
+ v.AddArg(x)
+ return true
+ }
// match: (SUBQconst (MOVQconst [d]) [c])
// cond:
// result: (MOVQconst [d-c])
@@ -16776,104 +16511,6 @@ func rewriteValueAMD64_OpAMD64SUBQconst(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAMD64SUBW(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (SUBW x (MOVWconst [c]))
- // cond:
- // result: (SUBWconst x [c])
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SUBWconst)
- v.AddArg(x)
- v.AuxInt = c
- return true
- }
- // match: (SUBW (MOVWconst [c]) x)
- // cond:
- // result: (NEGW (SUBWconst <v.Type> x [c]))
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64NEGW)
- v0 := b.NewValue0(v.Line, OpAMD64SUBWconst, v.Type)
- v0.AddArg(x)
- v0.AuxInt = c
- v.AddArg(v0)
- return true
- }
- // match: (SUBW x x)
- // cond:
- // result: (MOVWconst [0])
- for {
- x := v.Args[0]
- if x != v.Args[1] {
- break
- }
- v.reset(OpAMD64MOVWconst)
- v.AuxInt = 0
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64SUBWconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (SUBWconst [c] x)
- // cond: int16(c) == 0
- // result: x
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(int16(c) == 0) {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (SUBWconst (MOVWconst [d]) [c])
- // cond:
- // result: (MOVWconst [int64(int16(d-c))])
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
- break
- }
- d := v_0.AuxInt
- c := v.AuxInt
- v.reset(OpAMD64MOVWconst)
- v.AuxInt = int64(int16(d - c))
- return true
- }
- // match: (SUBWconst (SUBWconst x [d]) [c])
- // cond:
- // result: (ADDWconst [int64(int16(-c-d))] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64SUBWconst {
- break
- }
- x := v_0.Args[0]
- d := v_0.AuxInt
- c := v.AuxInt
- v.reset(OpAMD64ADDWconst)
- v.AuxInt = int64(int16(-c - d))
- v.AddArg(x)
- return true
- }
- return false
-}
func rewriteValueAMD64_OpSignExt16to32(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -17102,11 +16739,11 @@ func rewriteValueAMD64_OpSub16(v *Value, config *Config) bool {
_ = b
// match: (Sub16 x y)
// cond:
- // result: (SUBW x y)
+ // result: (SUBL x y)
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64SUBW)
+ v.reset(OpAMD64SUBL)
v.AddArg(x)
v.AddArg(y)
return true
@@ -17182,11 +16819,11 @@ func rewriteValueAMD64_OpSub8(v *Value, config *Config) bool {
_ = b
// match: (Sub8 x y)
// cond:
- // result: (SUBB x y)
+ // result: (SUBL x y)
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64SUBB)
+ v.reset(OpAMD64SUBL)
v.AddArg(x)
v.AddArg(y)
return true
@@ -17299,86 +16936,6 @@ func rewriteValueAMD64_OpTrunc64to8(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAMD64XORB(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (XORB x (MOVBconst [c]))
- // cond:
- // result: (XORBconst [c] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64XORBconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (XORB (MOVBconst [c]) x)
- // cond:
- // result: (XORBconst [c] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64XORBconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (XORB x x)
- // cond:
- // result: (MOVBconst [0])
- for {
- x := v.Args[0]
- if x != v.Args[1] {
- break
- }
- v.reset(OpAMD64MOVBconst)
- v.AuxInt = 0
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64XORBconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (XORBconst [c] x)
- // cond: int8(c)==0
- // result: x
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(int8(c) == 0) {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (XORBconst [c] (MOVBconst [d]))
- // cond:
- // result: (MOVBconst [c^d])
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBconst {
- break
- }
- d := v_0.AuxInt
- v.reset(OpAMD64MOVBconst)
- v.AuxInt = c ^ d
- return true
- }
- return false
-}
func rewriteValueAMD64_OpAMD64XORL(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -17544,96 +17101,16 @@ func rewriteValueAMD64_OpAMD64XORQconst(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAMD64XORW(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (XORW x (MOVWconst [c]))
- // cond:
- // result: (XORWconst [c] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64XORWconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (XORW (MOVWconst [c]) x)
- // cond:
- // result: (XORWconst [c] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64XORWconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (XORW x x)
- // cond:
- // result: (MOVWconst [0])
- for {
- x := v.Args[0]
- if x != v.Args[1] {
- break
- }
- v.reset(OpAMD64MOVWconst)
- v.AuxInt = 0
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64XORWconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (XORWconst [c] x)
- // cond: int16(c)==0
- // result: x
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(int16(c) == 0) {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (XORWconst [c] (MOVWconst [d]))
- // cond:
- // result: (MOVWconst [c^d])
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWconst {
- break
- }
- d := v_0.AuxInt
- v.reset(OpAMD64MOVWconst)
- v.AuxInt = c ^ d
- return true
- }
- return false
-}
func rewriteValueAMD64_OpXor16(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (Xor16 x y)
// cond:
- // result: (XORW x y)
+ // result: (XORL x y)
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64XORW)
+ v.reset(OpAMD64XORL)
v.AddArg(x)
v.AddArg(y)
return true
@@ -17677,11 +17154,11 @@ func rewriteValueAMD64_OpXor8(v *Value, config *Config) bool {
_ = b
// match: (Xor8 x y)
// cond:
- // result: (XORB x y)
+ // result: (XORL x y)
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64XORB)
+ v.reset(OpAMD64XORL)
v.AddArg(x)
v.AddArg(y)
return true
@@ -18849,7 +18326,7 @@ func rewriteBlockAMD64(b *Block) bool {
return true
}
case BlockAMD64NE:
- // match: (NE (TESTB (SETL cmp)) yes no)
+ // match: (NE (TESTB (SETL cmp) (SETL cmp)) yes no)
// cond:
// result: (LT cmp yes no)
for {
@@ -18862,6 +18339,13 @@ func rewriteBlockAMD64(b *Block) bool {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETL {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64LT
@@ -18870,7 +18354,7 @@ func rewriteBlockAMD64(b *Block) bool {
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETLE cmp)) yes no)
+ // match: (NE (TESTB (SETLE cmp) (SETLE cmp)) yes no)
// cond:
// result: (LE cmp yes no)
for {
@@ -18883,6 +18367,13 @@ func rewriteBlockAMD64(b *Block) bool {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETLE {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64LE
@@ -18891,7 +18382,7 @@ func rewriteBlockAMD64(b *Block) bool {
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETG cmp)) yes no)
+ // match: (NE (TESTB (SETG cmp) (SETG cmp)) yes no)
// cond:
// result: (GT cmp yes no)
for {
@@ -18904,6 +18395,13 @@ func rewriteBlockAMD64(b *Block) bool {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETG {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64GT
@@ -18912,7 +18410,7 @@ func rewriteBlockAMD64(b *Block) bool {
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETGE cmp)) yes no)
+ // match: (NE (TESTB (SETGE cmp) (SETGE cmp)) yes no)
// cond:
// result: (GE cmp yes no)
for {
@@ -18925,6 +18423,13 @@ func rewriteBlockAMD64(b *Block) bool {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETGE {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64GE
@@ -18933,7 +18438,7 @@ func rewriteBlockAMD64(b *Block) bool {
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETEQ cmp)) yes no)
+ // match: (NE (TESTB (SETEQ cmp) (SETEQ cmp)) yes no)
// cond:
// result: (EQ cmp yes no)
for {
@@ -18946,6 +18451,13 @@ func rewriteBlockAMD64(b *Block) bool {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETEQ {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64EQ
@@ -18954,7 +18466,7 @@ func rewriteBlockAMD64(b *Block) bool {
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETNE cmp)) yes no)
+ // match: (NE (TESTB (SETNE cmp) (SETNE cmp)) yes no)
// cond:
// result: (NE cmp yes no)
for {
@@ -18967,6 +18479,13 @@ func rewriteBlockAMD64(b *Block) bool {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETNE {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64NE
@@ -18975,7 +18494,7 @@ func rewriteBlockAMD64(b *Block) bool {
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETB cmp)) yes no)
+ // match: (NE (TESTB (SETB cmp) (SETB cmp)) yes no)
// cond:
// result: (ULT cmp yes no)
for {
@@ -18988,6 +18507,13 @@ func rewriteBlockAMD64(b *Block) bool {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETB {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64ULT
@@ -18996,7 +18522,7 @@ func rewriteBlockAMD64(b *Block) bool {
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETBE cmp)) yes no)
+ // match: (NE (TESTB (SETBE cmp) (SETBE cmp)) yes no)
// cond:
// result: (ULE cmp yes no)
for {
@@ -19009,6 +18535,13 @@ func rewriteBlockAMD64(b *Block) bool {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETBE {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64ULE
@@ -19017,7 +18550,7 @@ func rewriteBlockAMD64(b *Block) bool {
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETA cmp)) yes no)
+ // match: (NE (TESTB (SETA cmp) (SETA cmp)) yes no)
// cond:
// result: (UGT cmp yes no)
for {
@@ -19030,6 +18563,13 @@ func rewriteBlockAMD64(b *Block) bool {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETA {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGT
@@ -19038,7 +18578,7 @@ func rewriteBlockAMD64(b *Block) bool {
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETAE cmp)) yes no)
+ // match: (NE (TESTB (SETAE cmp) (SETAE cmp)) yes no)
// cond:
// result: (UGE cmp yes no)
for {
@@ -19051,6 +18591,13 @@ func rewriteBlockAMD64(b *Block) bool {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETAE {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGE
@@ -19059,7 +18606,7 @@ func rewriteBlockAMD64(b *Block) bool {
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETGF cmp)) yes no)
+ // match: (NE (TESTB (SETGF cmp) (SETGF cmp)) yes no)
// cond:
// result: (UGT cmp yes no)
for {
@@ -19072,6 +18619,13 @@ func rewriteBlockAMD64(b *Block) bool {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETGF {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGT
@@ -19080,7 +18634,7 @@ func rewriteBlockAMD64(b *Block) bool {
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETGEF cmp)) yes no)
+ // match: (NE (TESTB (SETGEF cmp) (SETGEF cmp)) yes no)
// cond:
// result: (UGE cmp yes no)
for {
@@ -19093,6 +18647,13 @@ func rewriteBlockAMD64(b *Block) bool {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETGEF {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGE
@@ -19101,7 +18662,7 @@ func rewriteBlockAMD64(b *Block) bool {
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETEQF cmp)) yes no)
+ // match: (NE (TESTB (SETEQF cmp) (SETEQF cmp)) yes no)
// cond:
// result: (EQF cmp yes no)
for {
@@ -19114,6 +18675,13 @@ func rewriteBlockAMD64(b *Block) bool {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETEQF {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64EQF
@@ -19122,7 +18690,7 @@ func rewriteBlockAMD64(b *Block) bool {
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETNEF cmp)) yes no)
+ // match: (NE (TESTB (SETNEF cmp) (SETNEF cmp)) yes no)
// cond:
// result: (NEF cmp yes no)
for {
@@ -19135,6 +18703,13 @@ func rewriteBlockAMD64(b *Block) bool {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETNEF {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64NEF
diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
index 932cb42235..43e87c3bf6 100644
--- a/src/cmd/compile/internal/ssa/rewritegeneric.go
+++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
@@ -66,6 +66,8 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
return rewriteValuegeneric_OpEq64(v, config)
case OpEq8:
return rewriteValuegeneric_OpEq8(v, config)
+ case OpEqB:
+ return rewriteValuegeneric_OpEqB(v, config)
case OpEqInter:
return rewriteValuegeneric_OpEqInter(v, config)
case OpEqPtr:
@@ -218,6 +220,8 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
return rewriteValuegeneric_OpNeq64(v, config)
case OpNeq8:
return rewriteValuegeneric_OpNeq8(v, config)
+ case OpNeqB:
+ return rewriteValuegeneric_OpNeqB(v, config)
case OpNeqInter:
return rewriteValuegeneric_OpNeqInter(v, config)
case OpNeqPtr:
@@ -732,6 +736,78 @@ func rewriteValuegeneric_OpAnd16(v *Value, config *Config) bool {
v.AuxInt = 0
return true
}
+ // match: (And16 x (And16 x y))
+ // cond:
+ // result: (And16 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAnd16 {
+ break
+ }
+ if x != v_1.Args[0] {
+ break
+ }
+ y := v_1.Args[1]
+ v.reset(OpAnd16)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (And16 x (And16 y x))
+ // cond:
+ // result: (And16 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAnd16 {
+ break
+ }
+ y := v_1.Args[0]
+ if x != v_1.Args[1] {
+ break
+ }
+ v.reset(OpAnd16)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (And16 (And16 x y) x)
+ // cond:
+ // result: (And16 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAnd16 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpAnd16)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (And16 (And16 x y) y)
+ // cond:
+ // result: (And16 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAnd16 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if y != v.Args[1] {
+ break
+ }
+ v.reset(OpAnd16)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpAnd32(v *Value, config *Config) bool {
@@ -803,6 +879,78 @@ func rewriteValuegeneric_OpAnd32(v *Value, config *Config) bool {
v.AuxInt = 0
return true
}
+ // match: (And32 x (And32 x y))
+ // cond:
+ // result: (And32 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAnd32 {
+ break
+ }
+ if x != v_1.Args[0] {
+ break
+ }
+ y := v_1.Args[1]
+ v.reset(OpAnd32)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (And32 x (And32 y x))
+ // cond:
+ // result: (And32 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAnd32 {
+ break
+ }
+ y := v_1.Args[0]
+ if x != v_1.Args[1] {
+ break
+ }
+ v.reset(OpAnd32)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (And32 (And32 x y) x)
+ // cond:
+ // result: (And32 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAnd32 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpAnd32)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (And32 (And32 x y) y)
+ // cond:
+ // result: (And32 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAnd32 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if y != v.Args[1] {
+ break
+ }
+ v.reset(OpAnd32)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpAnd64(v *Value, config *Config) bool {
@@ -874,6 +1022,78 @@ func rewriteValuegeneric_OpAnd64(v *Value, config *Config) bool {
v.AuxInt = 0
return true
}
+ // match: (And64 x (And64 x y))
+ // cond:
+ // result: (And64 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAnd64 {
+ break
+ }
+ if x != v_1.Args[0] {
+ break
+ }
+ y := v_1.Args[1]
+ v.reset(OpAnd64)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (And64 x (And64 y x))
+ // cond:
+ // result: (And64 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAnd64 {
+ break
+ }
+ y := v_1.Args[0]
+ if x != v_1.Args[1] {
+ break
+ }
+ v.reset(OpAnd64)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (And64 (And64 x y) x)
+ // cond:
+ // result: (And64 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAnd64 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpAnd64)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (And64 (And64 x y) y)
+ // cond:
+ // result: (And64 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAnd64 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if y != v.Args[1] {
+ break
+ }
+ v.reset(OpAnd64)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
// match: (And64 <t> (Const64 [y]) x)
// cond: nlz(y) + nto(y) == 64 && nto(y) >= 32
// result: (Rsh64Ux64 (Lsh64x64 <t> x (Const64 <t> [nlz(y)])) (Const64 <t> [nlz(y)]))
@@ -997,6 +1217,78 @@ func rewriteValuegeneric_OpAnd8(v *Value, config *Config) bool {
v.AuxInt = 0
return true
}
+ // match: (And8 x (And8 x y))
+ // cond:
+ // result: (And8 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAnd8 {
+ break
+ }
+ if x != v_1.Args[0] {
+ break
+ }
+ y := v_1.Args[1]
+ v.reset(OpAnd8)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (And8 x (And8 y x))
+ // cond:
+ // result: (And8 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAnd8 {
+ break
+ }
+ y := v_1.Args[0]
+ if x != v_1.Args[1] {
+ break
+ }
+ v.reset(OpAnd8)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (And8 (And8 x y) x)
+ // cond:
+ // result: (And8 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAnd8 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpAnd8)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (And8 (And8 x y) y)
+ // cond:
+ // result: (And8 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAnd8 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if y != v.Args[1] {
+ break
+ }
+ v.reset(OpAnd8)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpArg(v *Value, config *Config) bool {
@@ -2060,57 +2352,6 @@ func rewriteValuegeneric_OpEq8(v *Value, config *Config) bool {
v.AuxInt = 1
return true
}
- // match: (Eq8 (ConstBool [c]) (ConstBool [d]))
- // cond:
- // result: (ConstBool [b2i(c == d)])
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpConstBool {
- break
- }
- c := v_0.AuxInt
- v_1 := v.Args[1]
- if v_1.Op != OpConstBool {
- break
- }
- d := v_1.AuxInt
- v.reset(OpConstBool)
- v.AuxInt = b2i(c == d)
- return true
- }
- // match: (Eq8 (ConstBool [0]) x)
- // cond:
- // result: (Not x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpConstBool {
- break
- }
- if v_0.AuxInt != 0 {
- break
- }
- x := v.Args[1]
- v.reset(OpNot)
- v.AddArg(x)
- return true
- }
- // match: (Eq8 (ConstBool [1]) x)
- // cond:
- // result: x
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpConstBool {
- break
- }
- if v_0.AuxInt != 1 {
- break
- }
- x := v.Args[1]
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
// match: (Eq8 (Const8 <t> [c]) (Add8 (Const8 <t> [d]) x))
// cond:
// result: (Eq8 (Const8 <t> [int64(int8(c-d))]) x)
@@ -2162,38 +2403,40 @@ func rewriteValuegeneric_OpEq8(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- // match: (Eq8 x (ConstBool <t> [c]))
- // cond: x.Op != OpConstBool
- // result: (Eq8 (ConstBool <t> [c]) x)
+ // match: (Eq8 (Const8 [c]) (Const8 [d]))
+ // cond:
+ // result: (ConstBool [b2i(c == d)])
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpConstBool {
+ v_0 := v.Args[0]
+ if v_0.Op != OpConst8 {
break
}
- t := v_1.Type
- c := v_1.AuxInt
- if !(x.Op != OpConstBool) {
+ c := v_0.AuxInt
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst8 {
break
}
- v.reset(OpEq8)
- v0 := b.NewValue0(v.Line, OpConstBool, t)
- v0.AuxInt = c
- v.AddArg(v0)
- v.AddArg(x)
+ d := v_1.AuxInt
+ v.reset(OpConstBool)
+ v.AuxInt = b2i(c == d)
return true
}
- // match: (Eq8 (Const8 [c]) (Const8 [d]))
+ return false
+}
+func rewriteValuegeneric_OpEqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqB (ConstBool [c]) (ConstBool [d]))
// cond:
// result: (ConstBool [b2i(c == d)])
for {
v_0 := v.Args[0]
- if v_0.Op != OpConst8 {
+ if v_0.Op != OpConstBool {
break
}
c := v_0.AuxInt
v_1 := v.Args[1]
- if v_1.Op != OpConst8 {
+ if v_1.Op != OpConstBool {
break
}
d := v_1.AuxInt
@@ -2201,6 +2444,39 @@ func rewriteValuegeneric_OpEq8(v *Value, config *Config) bool {
v.AuxInt = b2i(c == d)
return true
}
+ // match: (EqB (ConstBool [0]) x)
+ // cond:
+ // result: (Not x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpConstBool {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpNot)
+ v.AddArg(x)
+ return true
+ }
+ // match: (EqB (ConstBool [1]) x)
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpConstBool {
+ break
+ }
+ if v_0.AuxInt != 1 {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpEqInter(v *Value, config *Config) bool {
@@ -5419,57 +5695,6 @@ func rewriteValuegeneric_OpNeq8(v *Value, config *Config) bool {
v.AuxInt = 0
return true
}
- // match: (Neq8 (ConstBool [c]) (ConstBool [d]))
- // cond:
- // result: (ConstBool [b2i(c != d)])
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpConstBool {
- break
- }
- c := v_0.AuxInt
- v_1 := v.Args[1]
- if v_1.Op != OpConstBool {
- break
- }
- d := v_1.AuxInt
- v.reset(OpConstBool)
- v.AuxInt = b2i(c != d)
- return true
- }
- // match: (Neq8 (ConstBool [0]) x)
- // cond:
- // result: x
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpConstBool {
- break
- }
- if v_0.AuxInt != 0 {
- break
- }
- x := v.Args[1]
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (Neq8 (ConstBool [1]) x)
- // cond:
- // result: (Not x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpConstBool {
- break
- }
- if v_0.AuxInt != 1 {
- break
- }
- x := v.Args[1]
- v.reset(OpNot)
- v.AddArg(x)
- return true
- }
// match: (Neq8 (Const8 <t> [c]) (Add8 (Const8 <t> [d]) x))
// cond:
// result: (Neq8 (Const8 <t> [int64(int8(c-d))]) x)
@@ -5521,38 +5746,40 @@ func rewriteValuegeneric_OpNeq8(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- // match: (Neq8 x (ConstBool <t> [c]))
- // cond: x.Op != OpConstBool
- // result: (Neq8 (ConstBool <t> [c]) x)
+ // match: (Neq8 (Const8 [c]) (Const8 [d]))
+ // cond:
+ // result: (ConstBool [b2i(c != d)])
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpConstBool {
+ v_0 := v.Args[0]
+ if v_0.Op != OpConst8 {
break
}
- t := v_1.Type
- c := v_1.AuxInt
- if !(x.Op != OpConstBool) {
+ c := v_0.AuxInt
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst8 {
break
}
- v.reset(OpNeq8)
- v0 := b.NewValue0(v.Line, OpConstBool, t)
- v0.AuxInt = c
- v.AddArg(v0)
- v.AddArg(x)
+ d := v_1.AuxInt
+ v.reset(OpConstBool)
+ v.AuxInt = b2i(c != d)
return true
}
- // match: (Neq8 (Const8 [c]) (Const8 [d]))
+ return false
+}
+func rewriteValuegeneric_OpNeqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqB (ConstBool [c]) (ConstBool [d]))
// cond:
// result: (ConstBool [b2i(c != d)])
for {
v_0 := v.Args[0]
- if v_0.Op != OpConst8 {
+ if v_0.Op != OpConstBool {
break
}
c := v_0.AuxInt
v_1 := v.Args[1]
- if v_1.Op != OpConst8 {
+ if v_1.Op != OpConstBool {
break
}
d := v_1.AuxInt
@@ -5560,6 +5787,39 @@ func rewriteValuegeneric_OpNeq8(v *Value, config *Config) bool {
v.AuxInt = b2i(c != d)
return true
}
+ // match: (NeqB (ConstBool [0]) x)
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpConstBool {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (NeqB (ConstBool [1]) x)
+ // cond:
+ // result: (Not x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpConstBool {
+ break
+ }
+ if v_0.AuxInt != 1 {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpNot)
+ v.AddArg(x)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpNeqInter(v *Value, config *Config) bool {
@@ -5739,6 +5999,78 @@ func rewriteValuegeneric_OpOr16(v *Value, config *Config) bool {
v.AuxInt = -1
return true
}
+ // match: (Or16 x (Or16 x y))
+ // cond:
+ // result: (Or16 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpOr16 {
+ break
+ }
+ if x != v_1.Args[0] {
+ break
+ }
+ y := v_1.Args[1]
+ v.reset(OpOr16)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Or16 x (Or16 y x))
+ // cond:
+ // result: (Or16 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpOr16 {
+ break
+ }
+ y := v_1.Args[0]
+ if x != v_1.Args[1] {
+ break
+ }
+ v.reset(OpOr16)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Or16 (Or16 x y) x)
+ // cond:
+ // result: (Or16 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpOr16 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpOr16)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Or16 (Or16 x y) y)
+ // cond:
+ // result: (Or16 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpOr16 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if y != v.Args[1] {
+ break
+ }
+ v.reset(OpOr16)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpOr32(v *Value, config *Config) bool {
@@ -5810,6 +6142,78 @@ func rewriteValuegeneric_OpOr32(v *Value, config *Config) bool {
v.AuxInt = -1
return true
}
+ // match: (Or32 x (Or32 x y))
+ // cond:
+ // result: (Or32 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpOr32 {
+ break
+ }
+ if x != v_1.Args[0] {
+ break
+ }
+ y := v_1.Args[1]
+ v.reset(OpOr32)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Or32 x (Or32 y x))
+ // cond:
+ // result: (Or32 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpOr32 {
+ break
+ }
+ y := v_1.Args[0]
+ if x != v_1.Args[1] {
+ break
+ }
+ v.reset(OpOr32)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Or32 (Or32 x y) x)
+ // cond:
+ // result: (Or32 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpOr32 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpOr32)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Or32 (Or32 x y) y)
+ // cond:
+ // result: (Or32 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpOr32 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if y != v.Args[1] {
+ break
+ }
+ v.reset(OpOr32)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpOr64(v *Value, config *Config) bool {
@@ -5881,6 +6285,78 @@ func rewriteValuegeneric_OpOr64(v *Value, config *Config) bool {
v.AuxInt = -1
return true
}
+ // match: (Or64 x (Or64 x y))
+ // cond:
+ // result: (Or64 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpOr64 {
+ break
+ }
+ if x != v_1.Args[0] {
+ break
+ }
+ y := v_1.Args[1]
+ v.reset(OpOr64)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Or64 x (Or64 y x))
+ // cond:
+ // result: (Or64 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpOr64 {
+ break
+ }
+ y := v_1.Args[0]
+ if x != v_1.Args[1] {
+ break
+ }
+ v.reset(OpOr64)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Or64 (Or64 x y) x)
+ // cond:
+ // result: (Or64 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpOr64 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpOr64)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Or64 (Or64 x y) y)
+ // cond:
+ // result: (Or64 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpOr64 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if y != v.Args[1] {
+ break
+ }
+ v.reset(OpOr64)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpOr8(v *Value, config *Config) bool {
@@ -5952,6 +6428,78 @@ func rewriteValuegeneric_OpOr8(v *Value, config *Config) bool {
v.AuxInt = -1
return true
}
+ // match: (Or8 x (Or8 x y))
+ // cond:
+ // result: (Or8 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpOr8 {
+ break
+ }
+ if x != v_1.Args[0] {
+ break
+ }
+ y := v_1.Args[1]
+ v.reset(OpOr8)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Or8 x (Or8 y x))
+ // cond:
+ // result: (Or8 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpOr8 {
+ break
+ }
+ y := v_1.Args[0]
+ if x != v_1.Args[1] {
+ break
+ }
+ v.reset(OpOr8)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Or8 (Or8 x y) x)
+ // cond:
+ // result: (Or8 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpOr8 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpOr8)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Or8 (Or8 x y) y)
+ // cond:
+ // result: (Or8 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpOr8 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if y != v.Args[1] {
+ break
+ }
+ v.reset(OpOr8)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpPhi(v *Value, config *Config) bool {
@@ -6185,7 +6733,7 @@ func rewriteValuegeneric_OpRsh16Ux64(v *Value, config *Config) bool {
_ = b
// match: (Rsh16Ux64 (Const16 [c]) (Const64 [d]))
// cond:
- // result: (Const16 [int64(uint16(c) >> uint64(d))])
+ // result: (Const16 [int64(int16(uint16(c) >> uint64(d)))])
for {
v_0 := v.Args[0]
if v_0.Op != OpConst16 {
@@ -6198,7 +6746,7 @@ func rewriteValuegeneric_OpRsh16Ux64(v *Value, config *Config) bool {
}
d := v_1.AuxInt
v.reset(OpConst16)
- v.AuxInt = int64(uint16(c) >> uint64(d))
+ v.AuxInt = int64(int16(uint16(c) >> uint64(d)))
return true
}
// match: (Rsh16Ux64 (Const16 [0]) _)
@@ -6547,7 +7095,7 @@ func rewriteValuegeneric_OpRsh32Ux64(v *Value, config *Config) bool {
_ = b
// match: (Rsh32Ux64 (Const32 [c]) (Const64 [d]))
// cond:
- // result: (Const32 [int64(uint32(c) >> uint64(d))])
+ // result: (Const32 [int64(int32(uint32(c) >> uint64(d)))])
for {
v_0 := v.Args[0]
if v_0.Op != OpConst32 {
@@ -6560,7 +7108,7 @@ func rewriteValuegeneric_OpRsh32Ux64(v *Value, config *Config) bool {
}
d := v_1.AuxInt
v.reset(OpConst32)
- v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AuxInt = int64(int32(uint32(c) >> uint64(d)))
return true
}
// match: (Rsh32Ux64 (Const32 [0]) _)
@@ -7353,7 +7901,7 @@ func rewriteValuegeneric_OpRsh8Ux64(v *Value, config *Config) bool {
_ = b
// match: (Rsh8Ux64 (Const8 [c]) (Const64 [d]))
// cond:
- // result: (Const8 [int64(uint8(c) >> uint64(d))])
+ // result: (Const8 [int64(int8(uint8(c) >> uint64(d)))])
for {
v_0 := v.Args[0]
if v_0.Op != OpConst8 {
@@ -7366,7 +7914,7 @@ func rewriteValuegeneric_OpRsh8Ux64(v *Value, config *Config) bool {
}
d := v_1.AuxInt
v.reset(OpConst8)
- v.AuxInt = int64(uint8(c) >> uint64(d))
+ v.AuxInt = int64(int8(uint8(c) >> uint64(d)))
return true
}
// match: (Rsh8Ux64 (Const8 [0]) _)
@@ -8941,6 +9489,78 @@ func rewriteValuegeneric_OpXor16(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
+ // match: (Xor16 x (Xor16 x y))
+ // cond:
+ // result: y
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpXor16 {
+ break
+ }
+ if x != v_1.Args[0] {
+ break
+ }
+ y := v_1.Args[1]
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (Xor16 x (Xor16 y x))
+ // cond:
+ // result: y
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpXor16 {
+ break
+ }
+ y := v_1.Args[0]
+ if x != v_1.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (Xor16 (Xor16 x y) x)
+ // cond:
+ // result: y
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpXor16 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (Xor16 (Xor16 x y) y)
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpXor16 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if y != v.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpXor32(v *Value, config *Config) bool {
@@ -8996,6 +9616,78 @@ func rewriteValuegeneric_OpXor32(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
+ // match: (Xor32 x (Xor32 x y))
+ // cond:
+ // result: y
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpXor32 {
+ break
+ }
+ if x != v_1.Args[0] {
+ break
+ }
+ y := v_1.Args[1]
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (Xor32 x (Xor32 y x))
+ // cond:
+ // result: y
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpXor32 {
+ break
+ }
+ y := v_1.Args[0]
+ if x != v_1.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (Xor32 (Xor32 x y) x)
+ // cond:
+ // result: y
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpXor32 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (Xor32 (Xor32 x y) y)
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpXor32 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if y != v.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpXor64(v *Value, config *Config) bool {
@@ -9051,6 +9743,78 @@ func rewriteValuegeneric_OpXor64(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
+ // match: (Xor64 x (Xor64 x y))
+ // cond:
+ // result: y
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpXor64 {
+ break
+ }
+ if x != v_1.Args[0] {
+ break
+ }
+ y := v_1.Args[1]
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (Xor64 x (Xor64 y x))
+ // cond:
+ // result: y
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpXor64 {
+ break
+ }
+ y := v_1.Args[0]
+ if x != v_1.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (Xor64 (Xor64 x y) x)
+ // cond:
+ // result: y
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpXor64 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (Xor64 (Xor64 x y) y)
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpXor64 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if y != v.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpXor8(v *Value, config *Config) bool {
@@ -9106,6 +9870,78 @@ func rewriteValuegeneric_OpXor8(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
+ // match: (Xor8 x (Xor8 x y))
+ // cond:
+ // result: y
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpXor8 {
+ break
+ }
+ if x != v_1.Args[0] {
+ break
+ }
+ y := v_1.Args[1]
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (Xor8 x (Xor8 y x))
+ // cond:
+ // result: y
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpXor8 {
+ break
+ }
+ y := v_1.Args[0]
+ if x != v_1.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (Xor8 (Xor8 x y) x)
+ // cond:
+ // result: y
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpXor8 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (Xor8 (Xor8 x y) y)
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpXor8 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if y != v.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
return false
}
func rewriteBlockgeneric(b *Block) bool {
diff --git a/src/cmd/compile/internal/ssa/sparsemap.go b/src/cmd/compile/internal/ssa/sparsemap.go
index 6c0043b230..0211a70f09 100644
--- a/src/cmd/compile/internal/ssa/sparsemap.go
+++ b/src/cmd/compile/internal/ssa/sparsemap.go
@@ -32,6 +32,8 @@ func (s *sparseMap) contains(k ID) bool {
return i < len(s.dense) && s.dense[i].key == k
}
+// get returns the value for key k, or -1 if k does
+// not appear in the map.
func (s *sparseMap) get(k ID) int32 {
i := s.sparse[k]
if i < len(s.dense) && s.dense[i].key == k {
@@ -50,6 +52,20 @@ func (s *sparseMap) set(k ID, v int32) {
s.sparse[k] = len(s.dense) - 1
}
+// setBit sets the v'th bit of k's value, where 0 <= v < 32
+func (s *sparseMap) setBit(k ID, v uint) {
+ if v >= 32 {
+ panic("bit index too large.")
+ }
+ i := s.sparse[k]
+ if i < len(s.dense) && s.dense[i].key == k {
+ s.dense[i].val |= 1 << v
+ return
+ }
+ s.dense = append(s.dense, sparseEntry{k, 1 << v})
+ s.sparse[k] = len(s.dense) - 1
+}
+
func (s *sparseMap) remove(k ID) {
i := s.sparse[k]
if i < len(s.dense) && s.dense[i].key == k {
diff --git a/src/cmd/compile/internal/ssa/sparsetree.go b/src/cmd/compile/internal/ssa/sparsetree.go
index cae91e7ddb..45c7897496 100644
--- a/src/cmd/compile/internal/ssa/sparsetree.go
+++ b/src/cmd/compile/internal/ssa/sparsetree.go
@@ -116,6 +116,9 @@ func (t sparseTree) Child(x *Block) *Block {
// isAncestorEq reports whether x is an ancestor of or equal to y.
func (t sparseTree) isAncestorEq(x, y *Block) bool {
+ if x == y {
+ return true
+ }
xx := &t[x.ID]
yy := &t[y.ID]
return xx.entry <= yy.entry && yy.exit <= xx.exit
@@ -123,7 +126,16 @@ func (t sparseTree) isAncestorEq(x, y *Block) bool {
// isAncestor reports whether x is a strict ancestor of y.
func (t sparseTree) isAncestor(x, y *Block) bool {
+ if x == y {
+ return false
+ }
xx := &t[x.ID]
yy := &t[y.ID]
return xx.entry < yy.entry && yy.exit < xx.exit
}
+
+// maxdomorder returns a value to allow a maximal dominator first sort. maxdomorder(x) < maxdomorder(y) is true
+// if x may dominate y, and false if x cannot dominate y.
+func (t sparseTree) maxdomorder(x *Block) int32 {
+ return t[x.ID].entry
+}
diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go
index 1de22dc96e..44f4096cb2 100644
--- a/src/cmd/compile/internal/ssa/stackalloc.go
+++ b/src/cmd/compile/internal/ssa/stackalloc.go
@@ -22,6 +22,13 @@ type stackAllocState struct {
names []LocalSlot
slots []int
used []bool
+
+ nArgSlot, // Number of Values sourced to arg slot
+ nNotNeed, // Number of Values not needing a stack slot
+ nNamedSlot, // Number of Values using a named stack slot
+ nReuse, // Number of values reusing a stack slot
+ nAuto, // Number of autos allocated for stack slots.
+ nSelfInterfere int32 // Number of self-interferences
}
func newStackAllocState(f *Func) *stackAllocState {
@@ -54,6 +61,7 @@ func putStackAllocState(s *stackAllocState) {
s.f.Config.stackAllocState = s
s.f = nil
s.live = nil
+ s.nArgSlot, s.nNotNeed, s.nNamedSlot, s.nReuse, s.nAuto, s.nSelfInterfere = 0, 0, 0, 0, 0, 0
}
type stackValState struct {
@@ -75,6 +83,13 @@ func stackalloc(f *Func, spillLive [][]ID) [][]ID {
defer putStackAllocState(s)
s.stackalloc()
+ if f.pass.stats > 0 {
+ f.logStat("stack_alloc_stats",
+ s.nArgSlot, "arg_slots", s.nNotNeed, "slot_not_needed",
+ s.nNamedSlot, "named_slots", s.nAuto, "auto_slots",
+ s.nReuse, "reused_slots", s.nSelfInterfere, "self_interfering")
+ }
+
return s.live
}
@@ -170,9 +185,11 @@ func (s *stackAllocState) stackalloc() {
for _, b := range f.Blocks {
for _, v := range b.Values {
if !s.values[v.ID].needSlot {
+ s.nNotNeed++
continue
}
if v.Op == OpArg {
+ s.nArgSlot++
continue // already picked
}
@@ -184,18 +201,20 @@ func (s *stackAllocState) stackalloc() {
} else {
name = names[v.ID]
}
- if name.N != nil && v.Type.Equal(name.Type) {
+ if name.N != nil && v.Type.Compare(name.Type) == CMPeq {
for _, id := range s.interfere[v.ID] {
h := f.getHome(id)
if h != nil && h.(LocalSlot).N == name.N && h.(LocalSlot).Off == name.Off {
// A variable can interfere with itself.
// It is rare, but but it can happen.
+ s.nSelfInterfere++
goto noname
}
}
if f.pass.debug > stackDebug {
fmt.Printf("stackalloc %s to %s\n", v, name.Name())
}
+ s.nNamedSlot++
f.setHome(v, name)
continue
}
@@ -217,11 +236,13 @@ func (s *stackAllocState) stackalloc() {
var i int
for i = 0; i < len(locs); i++ {
if !used[i] {
+ s.nReuse++
break
}
}
// If there is no unused stack slot, allocate a new one.
if i == len(locs) {
+ s.nAuto++
locs = append(locs, LocalSlot{N: f.Config.fe.Auto(v.Type), Type: v.Type, Off: 0})
locations[v.Type] = locs
}
@@ -351,7 +372,7 @@ func (s *stackAllocState) buildInterferenceGraph() {
if s.values[v.ID].needSlot {
live.remove(v.ID)
for _, id := range live.contents() {
- if s.values[v.ID].typ.Equal(s.values[id].typ) {
+ if s.values[v.ID].typ.Compare(s.values[id].typ) == CMPeq {
s.interfere[v.ID] = append(s.interfere[v.ID], id)
s.interfere[id] = append(s.interfere[id], v.ID)
}
diff --git a/src/cmd/compile/internal/ssa/type.go b/src/cmd/compile/internal/ssa/type.go
index 9643b07556..91a4efe78f 100644
--- a/src/cmd/compile/internal/ssa/type.go
+++ b/src/cmd/compile/internal/ssa/type.go
@@ -31,16 +31,16 @@ type Type interface {
ElemType() Type // given []T or *T or [n]T, return T
PtrTo() Type // given T, return *T
- NumFields() int // # of fields of a struct
- FieldType(i int) Type // type of ith field of the struct
- FieldOff(i int) int64 // offset of ith field of the struct
+ NumFields() int // # of fields of a struct
+ FieldType(i int) Type // type of ith field of the struct
+ FieldOff(i int) int64 // offset of ith field of the struct
+ FieldName(i int) string // name of ith field of the struct
NumElem() int64 // # of elements of an array
String() string
SimpleString() string // a coarser generic description of T, e.g. T's underlying type
- Equal(Type) bool
- Compare(Type) Cmp // compare types, returning one of CMPlt, CMPeq, CMPgt.
+ Compare(Type) Cmp // compare types, returning one of CMPlt, CMPeq, CMPgt.
}
// Special compiler-only types.
@@ -53,30 +53,31 @@ type CompilerType struct {
Int128 bool
}
-func (t *CompilerType) Size() int64 { return t.size } // Size in bytes
-func (t *CompilerType) Alignment() int64 { return 0 }
-func (t *CompilerType) IsBoolean() bool { return false }
-func (t *CompilerType) IsInteger() bool { return false }
-func (t *CompilerType) IsSigned() bool { return false }
-func (t *CompilerType) IsFloat() bool { return false }
-func (t *CompilerType) IsComplex() bool { return false }
-func (t *CompilerType) IsPtrShaped() bool { return false }
-func (t *CompilerType) IsString() bool { return false }
-func (t *CompilerType) IsSlice() bool { return false }
-func (t *CompilerType) IsArray() bool { return false }
-func (t *CompilerType) IsStruct() bool { return false }
-func (t *CompilerType) IsInterface() bool { return false }
-func (t *CompilerType) IsMemory() bool { return t.Memory }
-func (t *CompilerType) IsFlags() bool { return t.Flags }
-func (t *CompilerType) IsVoid() bool { return t.Void }
-func (t *CompilerType) String() string { return t.Name }
-func (t *CompilerType) SimpleString() string { return t.Name }
-func (t *CompilerType) ElemType() Type { panic("not implemented") }
-func (t *CompilerType) PtrTo() Type { panic("not implemented") }
-func (t *CompilerType) NumFields() int { panic("not implemented") }
-func (t *CompilerType) FieldType(i int) Type { panic("not implemented") }
-func (t *CompilerType) FieldOff(i int) int64 { panic("not implemented") }
-func (t *CompilerType) NumElem() int64 { panic("not implemented") }
+func (t *CompilerType) Size() int64 { return t.size } // Size in bytes
+func (t *CompilerType) Alignment() int64 { return 0 }
+func (t *CompilerType) IsBoolean() bool { return false }
+func (t *CompilerType) IsInteger() bool { return false }
+func (t *CompilerType) IsSigned() bool { return false }
+func (t *CompilerType) IsFloat() bool { return false }
+func (t *CompilerType) IsComplex() bool { return false }
+func (t *CompilerType) IsPtrShaped() bool { return false }
+func (t *CompilerType) IsString() bool { return false }
+func (t *CompilerType) IsSlice() bool { return false }
+func (t *CompilerType) IsArray() bool { return false }
+func (t *CompilerType) IsStruct() bool { return false }
+func (t *CompilerType) IsInterface() bool { return false }
+func (t *CompilerType) IsMemory() bool { return t.Memory }
+func (t *CompilerType) IsFlags() bool { return t.Flags }
+func (t *CompilerType) IsVoid() bool { return t.Void }
+func (t *CompilerType) String() string { return t.Name }
+func (t *CompilerType) SimpleString() string { return t.Name }
+func (t *CompilerType) ElemType() Type { panic("not implemented") }
+func (t *CompilerType) PtrTo() Type { panic("not implemented") }
+func (t *CompilerType) NumFields() int { panic("not implemented") }
+func (t *CompilerType) FieldType(i int) Type { panic("not implemented") }
+func (t *CompilerType) FieldOff(i int) int64 { panic("not implemented") }
+func (t *CompilerType) FieldName(i int) string { panic("not implemented") }
+func (t *CompilerType) NumElem() int64 { panic("not implemented") }
// Cmp is a comparison between values a and b.
// -1 if a < b
@@ -115,14 +116,6 @@ func (t *CompilerType) Compare(u Type) Cmp {
return CMPlt
}
-func (t *CompilerType) Equal(u Type) bool {
- x, ok := u.(*CompilerType)
- if !ok {
- return false
- }
- return x == t
-}
-
var (
TypeInvalid = &CompilerType{Name: "invalid"}
TypeMem = &CompilerType{Name: "mem", Memory: true}
diff --git a/src/cmd/compile/internal/ssa/type_test.go b/src/cmd/compile/internal/ssa/type_test.go
index cd80abf03f..3b1a892083 100644
--- a/src/cmd/compile/internal/ssa/type_test.go
+++ b/src/cmd/compile/internal/ssa/type_test.go
@@ -24,30 +24,31 @@ type TypeImpl struct {
Name string
}
-func (t *TypeImpl) Size() int64 { return t.Size_ }
-func (t *TypeImpl) Alignment() int64 { return t.Align }
-func (t *TypeImpl) IsBoolean() bool { return t.Boolean }
-func (t *TypeImpl) IsInteger() bool { return t.Integer }
-func (t *TypeImpl) IsSigned() bool { return t.Signed }
-func (t *TypeImpl) IsFloat() bool { return t.Float }
-func (t *TypeImpl) IsComplex() bool { return t.Complex }
-func (t *TypeImpl) IsPtrShaped() bool { return t.Ptr }
-func (t *TypeImpl) IsString() bool { return t.string }
-func (t *TypeImpl) IsSlice() bool { return t.slice }
-func (t *TypeImpl) IsArray() bool { return t.array }
-func (t *TypeImpl) IsStruct() bool { return t.struct_ }
-func (t *TypeImpl) IsInterface() bool { return t.inter }
-func (t *TypeImpl) IsMemory() bool { return false }
-func (t *TypeImpl) IsFlags() bool { return false }
-func (t *TypeImpl) IsVoid() bool { return false }
-func (t *TypeImpl) String() string { return t.Name }
-func (t *TypeImpl) SimpleString() string { return t.Name }
-func (t *TypeImpl) ElemType() Type { return t.Elem_ }
-func (t *TypeImpl) PtrTo() Type { panic("not implemented") }
-func (t *TypeImpl) NumFields() int { panic("not implemented") }
-func (t *TypeImpl) FieldType(i int) Type { panic("not implemented") }
-func (t *TypeImpl) FieldOff(i int) int64 { panic("not implemented") }
-func (t *TypeImpl) NumElem() int64 { panic("not implemented") }
+func (t *TypeImpl) Size() int64 { return t.Size_ }
+func (t *TypeImpl) Alignment() int64 { return t.Align }
+func (t *TypeImpl) IsBoolean() bool { return t.Boolean }
+func (t *TypeImpl) IsInteger() bool { return t.Integer }
+func (t *TypeImpl) IsSigned() bool { return t.Signed }
+func (t *TypeImpl) IsFloat() bool { return t.Float }
+func (t *TypeImpl) IsComplex() bool { return t.Complex }
+func (t *TypeImpl) IsPtrShaped() bool { return t.Ptr }
+func (t *TypeImpl) IsString() bool { return t.string }
+func (t *TypeImpl) IsSlice() bool { return t.slice }
+func (t *TypeImpl) IsArray() bool { return t.array }
+func (t *TypeImpl) IsStruct() bool { return t.struct_ }
+func (t *TypeImpl) IsInterface() bool { return t.inter }
+func (t *TypeImpl) IsMemory() bool { return false }
+func (t *TypeImpl) IsFlags() bool { return false }
+func (t *TypeImpl) IsVoid() bool { return false }
+func (t *TypeImpl) String() string { return t.Name }
+func (t *TypeImpl) SimpleString() string { return t.Name }
+func (t *TypeImpl) ElemType() Type { return t.Elem_ }
+func (t *TypeImpl) PtrTo() Type { panic("not implemented") }
+func (t *TypeImpl) NumFields() int { panic("not implemented") }
+func (t *TypeImpl) FieldType(i int) Type { panic("not implemented") }
+func (t *TypeImpl) FieldOff(i int) int64 { panic("not implemented") }
+func (t *TypeImpl) FieldName(i int) string { panic("not implemented") }
+func (t *TypeImpl) NumElem() int64 { panic("not implemented") }
func (t *TypeImpl) Equal(u Type) bool {
x, ok := u.(*TypeImpl)
diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go
index fd4eb64db1..6c364ad932 100644
--- a/src/cmd/compile/internal/ssa/value.go
+++ b/src/cmd/compile/internal/ssa/value.go
@@ -185,6 +185,7 @@ func (v *Value) resetArgs() {
}
v.argstorage[0] = nil
v.argstorage[1] = nil
+ v.argstorage[2] = nil
v.Args = v.argstorage[:0]
}
diff --git a/src/cmd/compile/internal/x86/cgen64.go b/src/cmd/compile/internal/x86/cgen64.go
index 61e191f87c..ea52d6951a 100644
--- a/src/cmd/compile/internal/x86/cgen64.go
+++ b/src/cmd/compile/internal/x86/cgen64.go
@@ -19,12 +19,12 @@ func cgen64(n *gc.Node, res *gc.Node) {
if res.Op != gc.OINDREG && res.Op != gc.ONAME {
gc.Dump("n", n)
gc.Dump("res", res)
- gc.Fatalf("cgen64 %v of %v", gc.Oconv(n.Op, 0), gc.Oconv(res.Op, 0))
+ gc.Fatalf("cgen64 %v of %v", n.Op, res.Op)
}
switch n.Op {
default:
- gc.Fatalf("cgen64 %v", gc.Oconv(n.Op, 0))
+ gc.Fatalf("cgen64 %v", n.Op)
case gc.OMINUS:
gc.Cgen(n.Left, res)
@@ -531,7 +531,7 @@ func cmp64(nl *gc.Node, nr *gc.Node, op gc.Op, likely int, to *obj.Prog) {
var br *obj.Prog
switch op {
default:
- gc.Fatalf("cmp64 %v %v", gc.Oconv(op, 0), t)
+ gc.Fatalf("cmp64 %v %v", op, t)
// cmp hi
// jne L
diff --git a/src/cmd/compile/internal/x86/galign.go b/src/cmd/compile/internal/x86/galign.go
index 4ab72b6da7..738d887742 100644
--- a/src/cmd/compile/internal/x86/galign.go
+++ b/src/cmd/compile/internal/x86/galign.go
@@ -13,15 +13,10 @@ import (
)
func betypeinit() {
- gc.Widthptr = 4
- gc.Widthint = 4
- gc.Widthreg = 4
}
func Main() {
- gc.Thearch.Thechar = '8'
- gc.Thearch.Thestring = "386"
- gc.Thearch.Thelinkarch = &x86.Link386
+ gc.Thearch.LinkArch = &x86.Link386
gc.Thearch.REGSP = x86.REGSP
gc.Thearch.REGCTXT = x86.REGCTXT
gc.Thearch.REGCALLX = x86.REG_BX
diff --git a/src/cmd/compile/internal/x86/ggen.go b/src/cmd/compile/internal/x86/ggen.go
index 38c3f8fc0e..21d989c98d 100644
--- a/src/cmd/compile/internal/x86/ggen.go
+++ b/src/cmd/compile/internal/x86/ggen.go
@@ -661,7 +661,7 @@ func cgen_floatsse(n *gc.Node, res *gc.Node) {
switch n.Op {
default:
gc.Dump("cgen_floatsse", n)
- gc.Fatalf("cgen_floatsse %v", gc.Oconv(n.Op, 0))
+ gc.Fatalf("cgen_floatsse %v", n.Op)
return
case gc.OMINUS,
diff --git a/src/cmd/compile/internal/x86/gsubr.go b/src/cmd/compile/internal/x86/gsubr.go
index 91c009116c..569ffd11bd 100644
--- a/src/cmd/compile/internal/x86/gsubr.go
+++ b/src/cmd/compile/internal/x86/gsubr.go
@@ -91,7 +91,7 @@ func optoas(op gc.Op, t *gc.Type) obj.As {
a := obj.AXXX
switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
default:
- gc.Fatalf("optoas: no entry %v-%v", gc.Oconv(op, 0), t)
+ gc.Fatalf("optoas: no entry %v-%v", op, t)
case OADDR_ | gc.TPTR32:
a = x86.ALEAL
@@ -454,7 +454,7 @@ func foptoas(op gc.Op, t *gc.Type, flg int) obj.As {
if !gc.Thearch.Use387 {
switch uint32(op)<<16 | uint32(et) {
default:
- gc.Fatalf("foptoas-sse: no entry %v-%v", gc.Oconv(op, 0), t)
+ gc.Fatalf("foptoas-sse: no entry %v-%v", op, t)
case OCMP_ | gc.TFLOAT32:
a = x86.AUCOMISS
@@ -587,7 +587,7 @@ func foptoas(op gc.Op, t *gc.Type, flg int) obj.As {
return x86.AFCHS
}
- gc.Fatalf("foptoas %v %v %#x", gc.Oconv(op, 0), t, flg)
+ gc.Fatalf("foptoas %v %v %#x", op, t, flg)
return 0
}
diff --git a/src/cmd/compile/internal/x86/reg.go b/src/cmd/compile/internal/x86/reg.go
index 76d90b8e89..d49a1aed9d 100644
--- a/src/cmd/compile/internal/x86/reg.go
+++ b/src/cmd/compile/internal/x86/reg.go
@@ -62,7 +62,7 @@ func regnames(n *int) []string {
}
func excludedregs() uint64 {
- if gc.Ctxt.Flag_shared != 0 {
+ if gc.Ctxt.Flag_shared {
return RtoB(x86.REG_SP) | RtoB(x86.REG_CX)
} else {
return RtoB(x86.REG_SP)
diff --git a/src/cmd/compile/main.go b/src/cmd/compile/main.go
index 49c2fb6263..8b8161efd1 100644
--- a/src/cmd/compile/main.go
+++ b/src/cmd/compile/main.go
@@ -10,6 +10,7 @@ import (
"cmd/compile/internal/arm64"
"cmd/compile/internal/mips64"
"cmd/compile/internal/ppc64"
+ "cmd/compile/internal/s390x"
"cmd/compile/internal/x86"
"cmd/internal/obj"
"fmt"
@@ -38,5 +39,7 @@ func main() {
mips64.Main()
case "ppc64", "ppc64le":
ppc64.Main()
+ case "s390x":
+ s390x.Main()
}
}
diff --git a/src/cmd/dist/buildgo.go b/src/cmd/dist/buildgo.go
index af33ecd66d..2b68fc2224 100644
--- a/src/cmd/dist/buildgo.go
+++ b/src/cmd/dist/buildgo.go
@@ -7,6 +7,7 @@ package main
import (
"bytes"
"fmt"
+ "sort"
)
/*
@@ -48,6 +49,15 @@ func mkzdefaultcc(dir, file string) {
//
// It is invoked to write go/build/zcgo.go.
func mkzcgo(dir, file string) {
+ // sort for deterministic zcgo.go file
+ var list []string
+ for plat, hasCgo := range cgoEnabled {
+ if hasCgo {
+ list = append(list, plat)
+ }
+ }
+ sort.Strings(list)
+
var buf bytes.Buffer
fmt.Fprintf(&buf,
@@ -56,10 +66,8 @@ func mkzcgo(dir, file string) {
"package build\n"+
"\n"+
"var cgoEnabled = map[string]bool{\n")
- for plat, hasCgo := range cgoEnabled {
- if hasCgo {
- fmt.Fprintf(&buf, "\t%q: true,\n", plat)
- }
+ for _, plat := range list {
+ fmt.Fprintf(&buf, "\t%q: true,\n", plat)
}
fmt.Fprintf(&buf, "}")
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index df9d9f3eeb..a535316ca0 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -38,6 +38,8 @@ var bootstrapDirs = []string{
"compile/internal/ppc64",
"compile/internal/ssa",
"compile/internal/x86",
+ "compile/internal/s390x",
+ "internal/bio",
"internal/gcprog",
"internal/obj",
"internal/obj/arm",
@@ -46,6 +48,7 @@ var bootstrapDirs = []string{
"internal/obj/ppc64",
"internal/obj/s390x",
"internal/obj/x86",
+ "internal/sys",
"link",
"link/internal/amd64",
"link/internal/arm",
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index 9a9cf2d7e4..11c22f4fd3 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -725,8 +725,10 @@ func (t *tester) cgoTest(dt *distTest) error {
cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", t.tags(), "-ldflags", "-linkmode=auto")
cmd.Env = env
- if t.gohostos != "dragonfly" {
+ if t.gohostos != "dragonfly" && t.gohostarch != "ppc64le" {
// linkmode=internal fails on dragonfly since errno is a TLS relocation.
+ // linkmode=internal fails on ppc64le because cmd/link doesn't
+ // handle the TOC correctly (issue 15409).
cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", "-linkmode=internal")
cmd.Env = env
}
diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go
index d0983d447d..efd681d514 100644
--- a/src/cmd/doc/pkg.go
+++ b/src/cmd/doc/pkg.go
@@ -268,7 +268,7 @@ func (pkg *Package) packageDoc() {
pkg.newlines(2) // Guarantee blank line before the components.
pkg.valueSummary(pkg.doc.Consts)
pkg.valueSummary(pkg.doc.Vars)
- pkg.funcSummary(pkg.doc.Funcs)
+ pkg.funcSummary(pkg.doc.Funcs, false)
pkg.typeSummary()
pkg.bugs()
}
@@ -308,24 +308,44 @@ func (pkg *Package) valueSummary(values []*doc.Value) {
}
}
-// funcSummary prints a one-line summary for each function.
-func (pkg *Package) funcSummary(funcs []*doc.Func) {
+// funcSummary prints a one-line summary for each function. Constructors
+// are printed by typeSummary, below, and so can be suppressed here.
+func (pkg *Package) funcSummary(funcs []*doc.Func, showConstructors bool) {
+ // First, identify the constructors. Don't bother figuring out if they're exported.
+ var isConstructor map[*doc.Func]bool
+ if !showConstructors {
+ isConstructor = make(map[*doc.Func]bool)
+ for _, typ := range pkg.doc.Types {
+ for _, constructor := range typ.Funcs {
+ isConstructor[constructor] = true
+ }
+ }
+ }
for _, fun := range funcs {
decl := fun.Decl
// Exported functions only. The go/doc package does not include methods here.
if isExported(fun.Name) {
- pkg.oneLineFunc(decl)
+ if !isConstructor[fun] {
+ pkg.oneLineFunc(decl)
+ }
}
}
}
-// typeSummary prints a one-line summary for each type.
+// typeSummary prints a one-line summary for each type, followed by its constructors.
func (pkg *Package) typeSummary() {
for _, typ := range pkg.doc.Types {
for _, spec := range typ.Decl.Specs {
typeSpec := spec.(*ast.TypeSpec) // Must succeed.
if isExported(typeSpec.Name.Name) {
pkg.oneLineTypeDecl(typeSpec)
+ // Now print the constructors.
+ for _, constructor := range typ.Funcs {
+ if isExported(constructor.Name) {
+ pkg.Printf(indent)
+ pkg.oneLineFunc(constructor.Decl)
+ }
+ }
}
}
}
@@ -453,8 +473,8 @@ func (pkg *Package) symbolDoc(symbol string) bool {
}
pkg.valueSummary(typ.Consts)
pkg.valueSummary(typ.Vars)
- pkg.funcSummary(typ.Funcs)
- pkg.funcSummary(typ.Methods)
+ pkg.funcSummary(typ.Funcs, true)
+ pkg.funcSummary(typ.Methods, true)
found = true
}
if !found {
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index 1f5981055c..2b74cb59e3 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -69,6 +69,8 @@ When compiling multiple packages or a single non-main package,
build compiles the packages but discards the resulting object,
serving only as a check that the packages can be built.
+When compiling packages, build ignores files that end in '_test.go'.
+
The -o flag, only allowed when compiling a single package,
forces build to write the resulting executable or object
to the named output file, instead of the default behavior described
@@ -566,6 +568,7 @@ syntax of package template. The default output is equivalent to -f
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?
+ StaleReason string // explanation for Stale==true
Root string // Go root or Go path dir containing this package
// Source files
@@ -1346,7 +1349,10 @@ The following flags are recognized by the 'go test' command and
control the execution of any test:
-bench regexp
- Run benchmarks matching the regular expression.
+ Run (sub)benchmarks matching a regular expression.
+ The given regular expression is split into smaller ones by
+ top-level '/', where each must match the corresponding part of a
+ benchmark's identifier.
By default, no benchmarks run. To run all benchmarks,
use '-bench .' or '-bench=.'.
@@ -1434,8 +1440,10 @@ control the execution of any test:
(see 'go help build').
-run regexp
- Run only those tests and examples matching the regular
- expression.
+ Run only those tests and examples matching the regular expression.
+ For tests the regular expression is split into smaller ones by
+ top-level '/', where each must match the corresponding part of a
+ test's identifier.
-short
Tell long-running tests to shorten their run time.
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index 01b32c30ed..b8c12db196 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -48,6 +48,8 @@ When compiling multiple packages or a single non-main package,
build compiles the packages but discards the resulting object,
serving only as a check that the packages can be built.
+When compiling packages, build ignores files that end in '_test.go'.
+
The -o flag, only allowed when compiling a single package,
forces build to write the resulting executable or object
to the named output file, instead of the default behavior described
@@ -332,6 +334,11 @@ func buildModeInit() {
}
return p
}
+ switch platform {
+ case "darwin/arm":
+ codegenArg = "-shared"
+ default:
+ }
exeSuffix = ".a"
ldBuildmode = "c-archive"
case "c-shared":
@@ -463,6 +470,7 @@ func runBuild(cmd *Command, args []string) {
p := pkgs[0]
p.target = *buildO
p.Stale = true // must build - not up to date
+ p.StaleReason = "build -o flag in use"
a := b.action(modeInstall, depMode, p)
b.do(a)
return
@@ -834,6 +842,7 @@ func goFilesPackage(gofiles []string) *Package {
pkg.Target = pkg.target
pkg.Stale = true
+ pkg.StaleReason = "files named on command line"
computeStale(pkg)
return pkg
@@ -1424,6 +1433,9 @@ func (b *builder) build(a *action) (err error) {
if err != nil {
return err
}
+ if _, ok := buildToolchain.(gccgoToolchain); ok {
+ cgoObjects = append(cgoObjects, filepath.Join(a.objdir, "_cgo_flags"))
+ }
cgoObjects = append(cgoObjects, outObj...)
gofiles = append(gofiles, outGo...)
}
@@ -2599,10 +2611,9 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles
func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
// gccgo needs explicit linking with all package dependencies,
// and all LDFLAGS from cgo dependencies.
- apackagesSeen := make(map[*Package]bool)
+ apackagePathsSeen := make(map[string]bool)
afiles := []string{}
shlibs := []string{}
- xfiles := []string{}
ldflags := b.gccArchArgs()
cgoldflags := []string{}
usesCgo := false
@@ -2610,12 +2621,73 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
objc := len(root.p.MFiles) > 0
fortran := len(root.p.FFiles) > 0
+ readCgoFlags := func(flagsFile string) error {
+ flags, err := ioutil.ReadFile(flagsFile)
+ if err != nil {
+ return err
+ }
+ const ldflagsPrefix = "_CGO_LDFLAGS="
+ for _, line := range strings.Split(string(flags), "\n") {
+ if strings.HasPrefix(line, ldflagsPrefix) {
+ newFlags := strings.Fields(line[len(ldflagsPrefix):])
+ for _, flag := range newFlags {
+ // Every _cgo_flags file has -g and -O2 in _CGO_LDFLAGS
+ // but they don't mean anything to the linker so filter
+ // them out.
+ if flag != "-g" && !strings.HasPrefix(flag, "-O") {
+ cgoldflags = append(cgoldflags, flag)
+ }
+ }
+ }
+ }
+ return nil
+ }
+
+ readAndRemoveCgoFlags := func(archive string) (string, error) {
+ newa, err := ioutil.TempFile(b.work, filepath.Base(archive))
+ if err != nil {
+ return "", err
+ }
+ olda, err := os.Open(archive)
+ if err != nil {
+ return "", err
+ }
+ _, err = io.Copy(newa, olda)
+ if err != nil {
+ return "", err
+ }
+ err = olda.Close()
+ if err != nil {
+ return "", err
+ }
+ err = newa.Close()
+ if err != nil {
+ return "", err
+ }
+
+ newarchive := newa.Name()
+ err = b.run(b.work, root.p.ImportPath, nil, "ar", "x", newarchive, "_cgo_flags")
+ if err != nil {
+ return "", err
+ }
+ err = b.run(".", root.p.ImportPath, nil, "ar", "d", newarchive, "_cgo_flags")
+ if err != nil {
+ return "", err
+ }
+ err = readCgoFlags(filepath.Join(b.work, "_cgo_flags"))
+ if err != nil {
+ return "", err
+ }
+ return newarchive, nil
+ }
+
actionsSeen := make(map[*action]bool)
// Make a pre-order depth-first traversal of the action graph, taking note of
// whether a shared library action has been seen on the way to an action (the
// construction of the graph means that if any path to a node passes through
// a shared library action, they all do).
var walk func(a *action, seenShlib bool)
+ var err error
walk = func(a *action, seenShlib bool) {
if actionsSeen[a] {
return
@@ -2630,21 +2702,18 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
// rather than the 'build' location (which may not exist any
// more). We still need to traverse the dependencies of the
// build action though so saying
- // if apackagesSeen[a.p] { return }
+ // if apackagePathsSeen[a.p.ImportPath] { return }
// doesn't work.
- if !apackagesSeen[a.p] {
- apackagesSeen[a.p] = true
- if a.p.fake && a.p.external {
- // external _tests, if present must come before
- // internal _tests. Store these on a separate list
- // and place them at the head after this loop.
- xfiles = append(xfiles, a.target)
- } else if a.p.fake {
- // move _test files to the top of the link order
- afiles = append([]string{a.target}, afiles...)
- } else {
- afiles = append(afiles, a.target)
+ if !apackagePathsSeen[a.p.ImportPath] {
+ apackagePathsSeen[a.p.ImportPath] = true
+ target := a.target
+ if len(a.p.CgoFiles) > 0 {
+ target, err = readAndRemoveCgoFlags(target)
+ if err != nil {
+ return
+ }
}
+ afiles = append(afiles, target)
}
}
if strings.HasSuffix(a.target, ".so") {
@@ -2653,12 +2722,17 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
}
for _, a1 := range a.deps {
walk(a1, seenShlib)
+ if err != nil {
+ return
+ }
}
}
for _, a1 := range root.deps {
walk(a1, false)
+ if err != nil {
+ return err
+ }
}
- afiles = append(xfiles, afiles...)
for _, a := range allactions {
// Gather CgoLDFLAGS, but not from standard packages.
@@ -2688,6 +2762,14 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
}
}
+ for i, o := range ofiles {
+ if filepath.Base(o) == "_cgo_flags" {
+ readCgoFlags(o)
+ ofiles = append(ofiles[:i], ofiles[i+1:]...)
+ break
+ }
+ }
+
ldflags = append(ldflags, "-Wl,--whole-archive")
ldflags = append(ldflags, afiles...)
ldflags = append(ldflags, "-Wl,--no-whole-archive")
diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go
index 7e0045fb1d..b52991a5fc 100644
--- a/src/cmd/go/get.go
+++ b/src/cmd/go/get.go
@@ -45,7 +45,7 @@ missing packages but does not use it to look for updates to existing packages.
Get also accepts build flags to control the installation. See 'go help build'.
-When checking out a new package, get creates the target directory
+When checking out a new package, get creates the target directory
GOPATH/src/<import-path>. If the GOPATH contains multiple entries,
get uses the first one. See 'go help gopath'.
@@ -346,7 +346,7 @@ func downloadPackage(p *Package) error {
if p.build.SrcRoot != "" {
// Directory exists. Look for checkout along path to src.
- vcs, rootPath, err = vcsForDir(p)
+ vcs, rootPath, err = vcsFromDir(p.Dir, p.build.SrcRoot)
if err != nil {
return err
}
@@ -354,7 +354,7 @@ func downloadPackage(p *Package) error {
// Double-check where it came from.
if *getU && vcs.remoteRepo != nil {
- dir := filepath.Join(p.build.SrcRoot, rootPath)
+ dir := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath))
remote, err := vcs.remoteRepo(vcs, dir)
if err != nil {
return err
@@ -401,7 +401,7 @@ func downloadPackage(p *Package) error {
p.build.SrcRoot = filepath.Join(list[0], "src")
p.build.PkgRoot = filepath.Join(list[0], "pkg")
}
- root := filepath.Join(p.build.SrcRoot, rootPath)
+ root := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath))
// If we've considered this repository already, don't do it again.
if downloadRootCache[root] {
return nil
diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go
index 3e595d187f..fe3d47752c 100644
--- a/src/cmd/go/go_test.go
+++ b/src/cmd/go/go_test.go
@@ -524,32 +524,43 @@ func (tg *testgoData) wantArchive(path string) {
}
}
-// isStale returns whether pkg is stale.
-func (tg *testgoData) isStale(pkg string) bool {
- tg.run("list", "-f", "{{.Stale}}", pkg)
- switch v := strings.TrimSpace(tg.getStdout()); v {
- case "true":
- return true
- case "false":
- return false
- default:
- tg.t.Fatalf("unexpected output checking staleness of package %v: %v", pkg, v)
- panic("unreachable")
+// isStale reports whether pkg is stale, and why
+func (tg *testgoData) isStale(pkg string) (bool, string) {
+ tg.run("list", "-f", "{{.Stale}}:{{.StaleReason}}", pkg)
+ v := strings.TrimSpace(tg.getStdout())
+ f := strings.SplitN(v, ":", 2)
+ if len(f) == 2 {
+ switch f[0] {
+ case "true":
+ return true, f[1]
+ case "false":
+ return false, f[1]
+ }
}
+ tg.t.Fatalf("unexpected output checking staleness of package %v: %v", pkg, v)
+ panic("unreachable")
}
// wantStale fails with msg if pkg is not stale.
-func (tg *testgoData) wantStale(pkg, msg string) {
- if !tg.isStale(pkg) {
+func (tg *testgoData) wantStale(pkg, reason, msg string) {
+ stale, why := tg.isStale(pkg)
+ if !stale {
tg.t.Fatal(msg)
}
+ if reason == "" && why != "" || !strings.Contains(why, reason) {
+ tg.t.Errorf("wrong reason for Stale=true: %q, want %q", why, reason)
+ }
}
// wantNotStale fails with msg if pkg is stale.
-func (tg *testgoData) wantNotStale(pkg, msg string) {
- if tg.isStale(pkg) {
+func (tg *testgoData) wantNotStale(pkg, reason, msg string) {
+ stale, why := tg.isStale(pkg)
+ if stale {
tg.t.Fatal(msg)
}
+ if reason == "" && why != "" || !strings.Contains(why, reason) {
+ tg.t.Errorf("wrong reason for Stale=false: %q, want %q", why, reason)
+ }
}
// cleanup cleans up a test that runs testgo.
@@ -708,7 +719,7 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
tg.tempFile("d1/src/p1/p1.go", `package p1`)
tg.setenv("GOPATH", tg.path("d1"))
tg.run("install", "-a", "p1")
- tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly")
tg.sleep()
// Changing mtime and content of runtime/internal/sys/sys.go
@@ -717,28 +728,28 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
sys := runtime.GOROOT() + "/src/runtime/internal/sys/sys.go"
restore := addNL(sys)
defer restore()
- tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly, after updating runtime/internal/sys/sys.go")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after updating runtime/internal/sys/sys.go")
restore()
- tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly, after restoring runtime/internal/sys/sys.go")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after restoring runtime/internal/sys/sys.go")
// But changing runtime/internal/sys/zversion.go should have an effect:
// that's how we tell when we flip from one release to another.
zversion := runtime.GOROOT() + "/src/runtime/internal/sys/zversion.go"
restore = addNL(zversion)
defer restore()
- tg.wantStale("p1", "./testgo list claims p1 is NOT stale, incorrectly, after changing to new release")
+ tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing to new release")
restore()
- tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly, after changing back to old release")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after changing back to old release")
addNL(zversion)
- tg.wantStale("p1", "./testgo list claims p1 is NOT stale, incorrectly, after changing again to new release")
+ tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing again to new release")
tg.run("install", "p1")
- tg.wantNotStale("p1", "./testgo list claims p1 is stale after building with new release")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with new release")
// Restore to "old" release.
restore()
- tg.wantStale("p1", "./testgo list claims p1 is NOT stale, incorrectly, after changing to old release after new build")
+ tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing to old release after new build")
tg.run("install", "p1")
- tg.wantNotStale("p1", "./testgo list claims p1 is stale after building with old release")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with old release")
// Everything is out of date. Rebuild to leave things in a better state.
tg.run("install", "std")
@@ -821,8 +832,8 @@ func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) {
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", tg.path("d1")+sep+tg.path("d2"))
tg.run("install", "p1")
- tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly")
- tg.wantNotStale("p2", "./testgo list claims p2 is stale, incorrectly")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly")
+ tg.wantNotStale("p2", "", "./testgo list claims p2 is stale, incorrectly")
tg.sleep()
if f, err := os.OpenFile(tg.path("d2/src/p2/p2.go"), os.O_WRONLY|os.O_APPEND, 0); err != nil {
t.Fatal(err)
@@ -831,12 +842,12 @@ func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) {
} else {
tg.must(f.Close())
}
- tg.wantStale("p2", "./testgo list claims p2 is NOT stale, incorrectly")
- tg.wantStale("p1", "./testgo list claims p1 is NOT stale, incorrectly")
+ tg.wantStale("p2", "newer source file", "./testgo list claims p2 is NOT stale, incorrectly")
+ tg.wantStale("p1", "stale dependency", "./testgo list claims p1 is NOT stale, incorrectly")
tg.run("install", "p1")
- tg.wantNotStale("p2", "./testgo list claims p2 is stale after reinstall, incorrectly")
- tg.wantNotStale("p1", "./testgo list claims p1 is stale after reinstall, incorrectly")
+ tg.wantNotStale("p2", "", "./testgo list claims p2 is stale after reinstall, incorrectly")
+ tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after reinstall, incorrectly")
}
func TestGoInstallDetectsRemovedFiles(t *testing.T) {
@@ -850,13 +861,13 @@ func TestGoInstallDetectsRemovedFiles(t *testing.T) {
package mypkg`)
tg.setenv("GOPATH", tg.path("."))
tg.run("install", "mypkg")
- tg.wantNotStale("mypkg", "./testgo list mypkg claims mypkg is stale, incorrectly")
+ tg.wantNotStale("mypkg", "", "./testgo list mypkg claims mypkg is stale, incorrectly")
// z.go was not part of the build; removing it is okay.
tg.must(os.Remove(tg.path("src/mypkg/z.go")))
- tg.wantNotStale("mypkg", "./testgo list mypkg claims mypkg is stale after removing z.go; should not be stale")
+ tg.wantNotStale("mypkg", "", "./testgo list mypkg claims mypkg is stale after removing z.go; should not be stale")
// y.go was part of the package; removing it should be detected.
tg.must(os.Remove(tg.path("src/mypkg/y.go")))
- tg.wantStale("mypkg", "./testgo list mypkg claims mypkg is NOT stale after removing y.go; should be stale")
+ tg.wantStale("mypkg", "build ID mismatch", "./testgo list mypkg claims mypkg is NOT stale after removing y.go; should be stale")
}
func TestWildcardMatchesSyntaxErrorDirs(t *testing.T) {
@@ -919,13 +930,13 @@ func TestGoInstallDetectsRemovedFilesInPackageMain(t *testing.T) {
package main`)
tg.setenv("GOPATH", tg.path("."))
tg.run("install", "mycmd")
- tg.wantNotStale("mycmd", "./testgo list mypkg claims mycmd is stale, incorrectly")
+ tg.wantNotStale("mycmd", "", "./testgo list mypkg claims mycmd is stale, incorrectly")
// z.go was not part of the build; removing it is okay.
tg.must(os.Remove(tg.path("src/mycmd/z.go")))
- tg.wantNotStale("mycmd", "./testgo list mycmd claims mycmd is stale after removing z.go; should not be stale")
+ tg.wantNotStale("mycmd", "", "./testgo list mycmd claims mycmd is stale after removing z.go; should not be stale")
// y.go was part of the package; removing it should be detected.
tg.must(os.Remove(tg.path("src/mycmd/y.go")))
- tg.wantStale("mycmd", "./testgo list mycmd claims mycmd is NOT stale after removing y.go; should be stale")
+ tg.wantStale("mycmd", "build ID mismatch", "./testgo list mycmd claims mycmd is NOT stale after removing y.go; should be stale")
}
func testLocalRun(tg *testgoData, exepath, local, match string) {
@@ -1317,7 +1328,7 @@ func TestPackageMainTestImportsArchiveNotBinary(t *testing.T) {
tg.sleep()
tg.run("test", "main_test")
tg.run("install", "main_test")
- tg.wantNotStale("main_test", "after go install, main listed as stale")
+ tg.wantNotStale("main_test", "", "after go install, main listed as stale")
tg.run("test", "main_test")
}
@@ -1327,9 +1338,9 @@ func TestPackageNotStaleWithTrailingSlash(t *testing.T) {
defer tg.cleanup()
goroot := runtime.GOROOT()
tg.setenv("GOROOT", goroot+"/")
- tg.wantNotStale("runtime", "with trailing slash in GOROOT, runtime listed as stale")
- tg.wantNotStale("os", "with trailing slash in GOROOT, os listed as stale")
- tg.wantNotStale("io", "with trailing slash in GOROOT, io listed as stale")
+ tg.wantNotStale("runtime", "", "with trailing slash in GOROOT, runtime listed as stale")
+ tg.wantNotStale("os", "", "with trailing slash in GOROOT, os listed as stale")
+ tg.wantNotStale("io", "", "with trailing slash in GOROOT, io listed as stale")
}
// With $GOBIN set, binaries get installed to $GOBIN.
@@ -1377,28 +1388,6 @@ func TestInstallToGOBINCommandLinePackage(t *testing.T) {
tg.wantExecutable("testdata/bin1/helloworld"+exeSuffix, "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld")
}
-func TestGodocInstalls(t *testing.T) {
- testenv.MustHaveExternalNetwork(t)
-
- // godoc installs into GOBIN
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
- tg.tempDir("gobin")
- tg.setenv("GOPATH", tg.path("."))
- tg.setenv("GOBIN", tg.path("gobin"))
- tg.run("get", "golang.org/x/tools/cmd/godoc")
- tg.wantExecutable(tg.path("gobin/godoc"), "did not install godoc to $GOBIN")
- tg.unsetenv("GOBIN")
-
- // godoc installs into GOROOT
- goroot := runtime.GOROOT()
- tg.setenv("GOROOT", goroot)
- tg.check(os.RemoveAll(filepath.Join(goroot, "bin", "godoc")))
- tg.run("install", "golang.org/x/tools/cmd/godoc")
- tg.wantExecutable(filepath.Join(goroot, "bin", "godoc"), "did not install godoc to $GOROOT/bin")
-}
-
func TestGoGetNonPkg(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
@@ -1488,7 +1477,7 @@ func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
defer tg.cleanup()
tg.parallel()
tg.run("test", "errors", "errors", "errors", "errors", "errors")
- if strings.Index(strings.TrimSpace(tg.getStdout()), "\n") != -1 {
+ if strings.Contains(strings.TrimSpace(tg.getStdout()), "\n") {
t.Error("go test errors errors errors errors errors tested the same package multiple times")
}
}
@@ -1517,7 +1506,7 @@ func TestGoListCmdOnlyShowsCommands(t *testing.T) {
tg.run("list", "cmd")
out := strings.TrimSpace(tg.getStdout())
for _, line := range strings.Split(out, "\n") {
- if strings.Index(line, "cmd/") == -1 {
+ if !strings.Contains(line, "cmd/") {
t.Error("go list cmd shows non-commands")
break
}
@@ -2320,8 +2309,7 @@ func TestGoVetWithExternalTests(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
- tg.setenv("GOPATH", tg.path("."))
- tg.run("get", "golang.org/x/tools/cmd/vet")
+ tg.run("install", "cmd/vet")
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("vet", "vetpkg")
tg.grepBoth("missing argument for Printf", "go vet vetpkg did not find missing argument for Printf")
@@ -2333,8 +2321,7 @@ func TestGoVetWithTags(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
- tg.setenv("GOPATH", tg.path("."))
- tg.run("get", "golang.org/x/tools/cmd/vet")
+ tg.run("install", "cmd/vet")
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("vet", "-tags", "tagtest", "vetpkg")
tg.grepBoth(`c\.go.*wrong number of args for format`, "go get vetpkg did not run scan tagged file")
@@ -2384,6 +2371,8 @@ func TestIssue4210(t *testing.T) {
func TestGoGetInsecure(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ t.Skip("golang.org/issue/15410")
+
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
diff --git a/src/cmd/go/http.go b/src/cmd/go/http.go
index 19e1fe4f77..05ea503049 100644
--- a/src/cmd/go/http.go
+++ b/src/cmd/go/http.go
@@ -30,7 +30,7 @@ var httpClient = http.DefaultClient
// when we're connecting to https servers that might not be there
// or might be using self-signed certificates.
var impatientInsecureHTTPClient = &http.Client{
- Timeout: time.Duration(5 * time.Second),
+ Timeout: 5 * time.Second,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go
index 9409f37154..49a63425bf 100644
--- a/src/cmd/go/list.go
+++ b/src/cmd/go/list.go
@@ -41,6 +41,7 @@ syntax of package template. The default output is equivalent to -f
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?
+ StaleReason string // explanation for Stale==true
Root string // Go root or Go path dir containing this package
// Source files
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index fa923c8873..00e0d73153 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -39,6 +39,7 @@ type Package struct {
Goroot bool `json:",omitempty"` // is this package found in the Go root?
Standard bool `json:",omitempty"` // is this package part of the standard Go library?
Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
+ StaleReason string `json:",omitempty"` // why is Stale true?
Root string `json:",omitempty"` // Go root or Go path dir containing this package
ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
@@ -434,6 +435,12 @@ func vendoredImportPath(parent *Package, path string) (found string) {
}
targ := filepath.Join(dir[:i], vpath)
if isDir(targ) && hasGoFiles(targ) {
+ importPath := parent.ImportPath
+ if importPath == "command-line-arguments" {
+ // If parent.ImportPath is 'command-line-arguments'.
+ // set to relative directory to root (also chopped root directory)
+ importPath = dir[len(root)+1:]
+ }
// We started with parent's dir c:\gopath\src\foo\bar\baz\quux\xyzzy.
// We know the import path for parent's dir.
// We chopped off some number of path elements and
@@ -443,14 +450,14 @@ func vendoredImportPath(parent *Package, path string) (found string) {
// (actually the same number of bytes) from parent's import path
// and then append /vendor/path.
chopped := len(dir) - i
- if chopped == len(parent.ImportPath)+1 {
+ if chopped == len(importPath)+1 {
// We walked up from c:\gopath\src\foo\bar
// and found c:\gopath\src\vendor\path.
// We chopped \foo\bar (length 8) but the import path is "foo/bar" (length 7).
// Use "vendor/path" without any prefix.
return vpath
}
- return parent.ImportPath[:len(parent.ImportPath)-chopped] + "/" + vpath
+ return importPath[:len(importPath)-chopped] + "/" + vpath
}
}
return path
@@ -517,7 +524,7 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
return p
}
- // Check for "internal" element: four cases depending on begin of string and/or end of string.
+ // Check for "internal" element: three cases depending on begin of string and/or end of string.
i, ok := findInternal(p.ImportPath)
if !ok {
return p
@@ -554,7 +561,7 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
// If there isn't one, findInternal returns ok=false.
// Otherwise, findInternal returns ok=true and the index of the "internal".
func findInternal(path string) (index int, ok bool) {
- // Four cases, depending on internal at start/end of string or not.
+ // Three cases, depending on internal at start/end of string or not.
// The order matters: we must return the index of the final element,
// because the final one produces the most restrictive requirement
// on the importer.
@@ -652,7 +659,7 @@ func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Pack
// findVendor looks for the last non-terminating "vendor" path element in the given import path.
// If there isn't one, findVendor returns ok=false.
-// Otherwise, findInternal returns ok=true and the index of the "vendor".
+// Otherwise, findVendor returns ok=true and the index of the "vendor".
//
// Note that terminating "vendor" elements don't count: "x/vendor" is its own package,
// not the vendored copy of an import "" (the empty import path).
@@ -676,7 +683,6 @@ type targetDir int
const (
toRoot targetDir = iota // to bin dir inside package root (default)
toTool // GOROOT/pkg/tool
- toBin // GOROOT/bin
stalePath // the old import path; fail to build
)
@@ -700,7 +706,6 @@ var goTools = map[string]targetDir{
"cmd/trace": toTool,
"cmd/vet": toTool,
"cmd/yacc": toTool,
- "golang.org/x/tools/cmd/godoc": toBin,
"code.google.com/p/go.tools/cmd/cover": stalePath,
"code.google.com/p/go.tools/cmd/godoc": stalePath,
"code.google.com/p/go.tools/cmd/vet": stalePath,
@@ -787,12 +792,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// Install cross-compiled binaries to subdirectories of bin.
elem = full
}
- if p.build.BinDir != gobin && goTools[p.ImportPath] == toBin {
- // Override BinDir.
- // This is from a subrepo but installs to $GOROOT/bin
- // by default anyway (like godoc).
- p.target = filepath.Join(gorootBin, elem)
- } else if p.build.BinDir != "" {
+ if p.build.BinDir != "" {
// Install to GOBIN or bin of GOPATH entry.
p.target = filepath.Join(p.build.BinDir, elem)
if !p.Goroot && strings.Contains(elem, "/") && gobin != "" {
@@ -1086,7 +1086,7 @@ func packageList(roots []*Package) []*Package {
// at the named pkgs (command-line arguments).
func computeStale(pkgs ...*Package) {
for _, p := range packageList(pkgs) {
- p.Stale = isStale(p)
+ p.Stale, p.StaleReason = isStale(p)
}
}
@@ -1357,14 +1357,15 @@ var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
// standard library, even in release versions. This makes
// 'go build -tags netgo' work, among other things.
-// isStale reports whether package p needs to be rebuilt.
-func isStale(p *Package) bool {
+// isStale reports whether package p needs to be rebuilt,
+// along with the reason why.
+func isStale(p *Package) (bool, string) {
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
// fake, builtin package
- return false
+ return false, "builtin package"
}
if p.Error != nil {
- return true
+ return true, "errors loading package"
}
// A package without Go sources means we only found
@@ -1374,23 +1375,26 @@ func isStale(p *Package) bool {
// only useful with the specific version of the toolchain that
// created them.
if len(p.gofiles) == 0 && !p.usesSwig() {
- return false
+ return false, "no source files"
}
// If the -a flag is given, rebuild everything.
if buildA {
- return true
+ return true, "build -a flag in use"
}
// If there's no install target or it's already marked stale, we have to rebuild.
- if p.target == "" || p.Stale {
- return true
+ if p.target == "" {
+ return true, "no install target"
+ }
+ if p.Stale {
+ return true, p.StaleReason
}
// Package is stale if completely unbuilt.
fi, err := os.Stat(p.target)
if err != nil {
- return true
+ return true, "cannot stat install target"
}
// Package is stale if the expected build ID differs from the
@@ -1403,13 +1407,13 @@ func isStale(p *Package) bool {
// See issue 8290 and issue 10702.
targetBuildID, err := readBuildID(p)
if err == nil && targetBuildID != p.buildID {
- return true
+ return true, "build ID mismatch"
}
// Package is stale if a dependency is.
for _, p1 := range p.deps {
if p1.Stale {
- return true
+ return true, "stale dependency"
}
}
@@ -1432,7 +1436,7 @@ func isStale(p *Package) bool {
// install is to run make.bash, which will remove the old package archives
// before rebuilding.)
if p.Standard && isGoRelease {
- return false
+ return false, "standard package in Go release distribution"
}
// Time-based staleness.
@@ -1447,7 +1451,7 @@ func isStale(p *Package) bool {
// Package is stale if a dependency is, or if a dependency is newer.
for _, p1 := range p.deps {
if p1.target != "" && olderThan(p1.target) {
- return true
+ return true, "newer dependency"
}
}
@@ -1466,10 +1470,10 @@ func isStale(p *Package) bool {
// taken care of above (at least when the installed Go is a released version).
if p.Root != goroot {
if olderThan(buildToolchain.compiler()) {
- return true
+ return true, "newer compiler"
}
if p.build.IsCommand() && olderThan(buildToolchain.linker()) {
- return true
+ return true, "newer linker"
}
}
@@ -1514,11 +1518,11 @@ func isStale(p *Package) bool {
srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.FFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
for _, src := range srcs {
if olderThan(filepath.Join(p.Dir, src)) {
- return true
+ return true, "newer source file"
}
}
- return false
+ return false, ""
}
// computeBuildID computes the build ID for p, leaving it in p.buildID.
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index a17bc4e982..5c21de5d9b 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -125,7 +125,10 @@ control the execution of any test:
const testFlag2 = `
-bench regexp
- Run benchmarks matching the regular expression.
+ Run (sub)benchmarks matching a regular expression.
+ The given regular expression is split into smaller ones by
+ top-level '/', where each must match the corresponding part of a
+ benchmark's identifier.
By default, no benchmarks run. To run all benchmarks,
use '-bench .' or '-bench=.'.
@@ -213,8 +216,10 @@ const testFlag2 = `
(see 'go help build').
-run regexp
- Run only those tests and examples matching the regular
- expression.
+ Run only those tests and examples matching the regular expression.
+ For tests the regular expression is split into smaller ones by
+ top-level '/', where each must match the corresponding part of a
+ test's identifier.
-short
Tell long-running tests to shorten their run time.
@@ -507,7 +512,8 @@ func runTest(cmd *Command, args []string) {
continue
}
p.Stale = true // rebuild
- p.fake = true // do not warn about rebuild
+ p.StaleReason = "rebuild for coverage"
+ p.fake = true // do not warn about rebuild
p.coverMode = testCoverMode
var coverFiles []string
coverFiles = append(coverFiles, p.GoFiles...)
@@ -744,6 +750,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
ptest.fake = true
ptest.forceLibrary = true
ptest.Stale = true
+ ptest.StaleReason = "rebuild for test"
ptest.build = new(build.Package)
*ptest.build = *p.build
m := map[string][]token.Position{}
@@ -1022,6 +1029,7 @@ func recompileForTest(pmain, preal, ptest *Package, testDir string) {
p.target = ""
p.fake = true
p.Stale = true
+ p.StaleReason = "depends on package being tested"
}
}
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
index a9663b2185..4ff71f2168 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -253,7 +253,7 @@ func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string
return "", fmt.Errorf("unable to parse output of bzr info")
}
out = out[:i]
- return strings.TrimSpace(string(out)), nil
+ return strings.TrimSpace(out), nil
}
// vcsSvn describes how to use Subversion.
@@ -294,7 +294,7 @@ func svnRemoteRepo(vcsSvn *vcsCmd, rootDir string) (remoteRepo string, err error
return "", fmt.Errorf("unable to parse output of svn info")
}
out = out[:i]
- return strings.TrimSpace(string(out)), nil
+ return strings.TrimSpace(out), nil
}
func (v *vcsCmd) String() string {
@@ -479,15 +479,14 @@ type vcsPath struct {
regexp *regexp.Regexp // cached compiled form of re
}
-// vcsForDir inspects dir and its parents to determine the
+// vcsFromDir inspects dir and its parents to determine the
// version control system and code repository to use.
// On return, root is the import path
-// corresponding to the root of the repository
-// (thus root is a prefix of importPath).
-func vcsForDir(p *Package) (vcs *vcsCmd, root string, err error) {
+// corresponding to the root of the repository.
+func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) {
// Clean and double-check that dir is in (a subdirectory of) srcRoot.
- dir := filepath.Clean(p.Dir)
- srcRoot := filepath.Clean(p.build.SrcRoot)
+ dir = filepath.Clean(dir)
+ srcRoot = filepath.Clean(srcRoot)
if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
}
@@ -496,7 +495,7 @@ func vcsForDir(p *Package) (vcs *vcsCmd, root string, err error) {
for len(dir) > len(srcRoot) {
for _, vcs := range vcsList {
if fi, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil && fi.IsDir() {
- return vcs, dir[len(srcRoot)+1:], nil
+ return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil
}
}
diff --git a/src/cmd/go/vcs_test.go b/src/cmd/go/vcs_test.go
index 52a534a3a3..d951189459 100644
--- a/src/cmd/go/vcs_test.go
+++ b/src/cmd/go/vcs_test.go
@@ -6,6 +6,10 @@ package main
import (
"internal/testenv"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
"testing"
)
@@ -128,6 +132,37 @@ func TestRepoRootForImportPath(t *testing.T) {
}
}
+// Test that vcsFromDir correctly inspects a given directory and returns the right VCS and root.
+func TestFromDir(t *testing.T) {
+ tempDir, err := ioutil.TempDir("", "vcstest")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tempDir)
+
+ for _, vcs := range vcsList {
+ dir := filepath.Join(tempDir, "example.com", vcs.name, "."+vcs.cmd)
+ err := os.MkdirAll(dir, 0755)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ want := repoRoot{
+ vcs: vcs,
+ root: path.Join("example.com", vcs.name),
+ }
+ var got repoRoot
+ got.vcs, got.root, err = vcsFromDir(dir, tempDir)
+ if err != nil {
+ t.Errorf("FromDir(%q, %q): %v", dir, tempDir, err)
+ continue
+ }
+ if got.vcs.name != want.vcs.name || got.root != want.root {
+ t.Errorf("FromDir(%q, %q) = VCS(%s) Root(%s), want VCS(%s) Root(%s)", dir, tempDir, got.vcs, got.root, want.vcs, want.root)
+ }
+ }
+}
+
func TestIsSecure(t *testing.T) {
tests := []struct {
vcs *vcsCmd
diff --git a/src/cmd/go/vendor_test.go b/src/cmd/go/vendor_test.go
index 199eab4471..e3070e8e45 100644
--- a/src/cmd/go/vendor_test.go
+++ b/src/cmd/go/vendor_test.go
@@ -232,6 +232,32 @@ func TestVendorTest2(t *testing.T) {
tg.run("test", "github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2")
}
+func TestVendorTest3(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+ tg.run("get", "github.com/clsung/go-vendor-issue-14613")
+
+ tg.run("build", "-o", tg.path("a.out"), "-i", "github.com/clsung/go-vendor-issue-14613")
+
+ // test folder should work
+ tg.run("test", "-i", "github.com/clsung/go-vendor-issue-14613")
+ tg.run("test", "github.com/clsung/go-vendor-issue-14613")
+
+ // test with specified _test.go should work too
+ tg.cd(filepath.Join(tg.path("."), "src"))
+ tg.run("test", "-i", "github.com/clsung/go-vendor-issue-14613/vendor_test.go")
+ tg.run("test", "github.com/clsung/go-vendor-issue-14613/vendor_test.go")
+
+ // test with imported and not used
+ tg.run("test", "-i", "github.com/clsung/go-vendor-issue-14613/vendor/mylibtesttest/myapp/myapp_test.go")
+ tg.runFail("test", "github.com/clsung/go-vendor-issue-14613/vendor/mylibtesttest/myapp/myapp_test.go")
+ tg.grepStderr("imported and not used:", `should say "imported and not used"`)
+}
+
func TestVendorList(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
diff --git a/src/cmd/gofmt/simplify.go b/src/cmd/gofmt/simplify.go
index 69f7bf23c0..2ebf4cde0b 100644
--- a/src/cmd/gofmt/simplify.go
+++ b/src/cmd/gofmt/simplify.go
@@ -10,11 +10,9 @@ import (
"reflect"
)
-type simplifier struct {
- hasDotImport bool // package file contains: import . "some/import/path"
-}
+type simplifier struct{}
-func (s *simplifier) Visit(node ast.Node) ast.Visitor {
+func (s simplifier) Visit(node ast.Node) ast.Visitor {
switch n := node.(type) {
case *ast.CompositeLit:
// array, slice, and map composite literals may be simplified
@@ -68,10 +66,13 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor {
// a slice expression of the form: s[a:len(s)]
// can be simplified to: s[a:]
// if s is "simple enough" (for now we only accept identifiers)
- if n.Max != nil || s.hasDotImport {
+ //
+ // Note: This may not be correct because len may have been redeclared in another
+ // file belonging to the same package. However, this is extremely unlikely
+ // and so far (April 2016, after years of supporting this rewrite feature)
+ // has never come up, so let's keep it working as is (see also #15153).
+ if n.Max != nil {
// - 3-index slices always require the 2nd and 3rd index
- // - if dot imports are present, we cannot be certain that an
- // unresolved "len" identifier refers to the predefined len()
break
}
if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil {
@@ -118,20 +119,11 @@ func isBlank(x ast.Expr) bool {
}
func simplify(f *ast.File) {
- var s simplifier
-
- // determine if f contains dot imports
- for _, imp := range f.Imports {
- if imp.Name != nil && imp.Name.Name == "." {
- s.hasDotImport = true
- break
- }
- }
-
// remove empty declarations such as "const ()", etc
removeEmptyDeclGroups(f)
- ast.Walk(&s, f)
+ var s simplifier
+ ast.Walk(s, f)
}
func removeEmptyDeclGroups(f *ast.File) {
diff --git a/src/cmd/gofmt/testdata/slices2.golden b/src/cmd/gofmt/testdata/slices2.golden
deleted file mode 100644
index ab657004e6..0000000000
--- a/src/cmd/gofmt/testdata/slices2.golden
+++ /dev/null
@@ -1,63 +0,0 @@
-//gofmt -s
-
-// Test cases for slice expression simplification.
-// Because of a dot import, these slices must remain untouched.
-package p
-
-import . "math"
-
-var (
- a [10]byte
- b [20]float32
- s []int
- t struct {
- s []byte
- }
-
- _ = a[0:]
- _ = a[1:10]
- _ = a[2:len(a)]
- _ = a[3:(len(a))]
- _ = a[len(a) : len(a)-1]
- _ = a[0:len(b)]
-
- _ = a[:]
- _ = a[:10]
- _ = a[:len(a)]
- _ = a[:(len(a))]
- _ = a[:len(a)-1]
- _ = a[:len(b)]
-
- _ = s[0:]
- _ = s[1:10]
- _ = s[2:len(s)]
- _ = s[3:(len(s))]
- _ = s[len(a) : len(s)-1]
- _ = s[0:len(b)]
-
- _ = s[:]
- _ = s[:10]
- _ = s[:len(s)]
- _ = s[:(len(s))]
- _ = s[:len(s)-1]
- _ = s[:len(b)]
-
- _ = t.s[0:]
- _ = t.s[1:10]
- _ = t.s[2:len(t.s)]
- _ = t.s[3:(len(t.s))]
- _ = t.s[len(a) : len(t.s)-1]
- _ = t.s[0:len(b)]
-
- _ = t.s[:]
- _ = t.s[:10]
- _ = t.s[:len(t.s)]
- _ = t.s[:(len(t.s))]
- _ = t.s[:len(t.s)-1]
- _ = t.s[:len(b)]
-)
-
-func _() {
- s := s[0:len(s)]
- _ = s
-}
diff --git a/src/cmd/gofmt/testdata/slices2.input b/src/cmd/gofmt/testdata/slices2.input
deleted file mode 100644
index ab657004e6..0000000000
--- a/src/cmd/gofmt/testdata/slices2.input
+++ /dev/null
@@ -1,63 +0,0 @@
-//gofmt -s
-
-// Test cases for slice expression simplification.
-// Because of a dot import, these slices must remain untouched.
-package p
-
-import . "math"
-
-var (
- a [10]byte
- b [20]float32
- s []int
- t struct {
- s []byte
- }
-
- _ = a[0:]
- _ = a[1:10]
- _ = a[2:len(a)]
- _ = a[3:(len(a))]
- _ = a[len(a) : len(a)-1]
- _ = a[0:len(b)]
-
- _ = a[:]
- _ = a[:10]
- _ = a[:len(a)]
- _ = a[:(len(a))]
- _ = a[:len(a)-1]
- _ = a[:len(b)]
-
- _ = s[0:]
- _ = s[1:10]
- _ = s[2:len(s)]
- _ = s[3:(len(s))]
- _ = s[len(a) : len(s)-1]
- _ = s[0:len(b)]
-
- _ = s[:]
- _ = s[:10]
- _ = s[:len(s)]
- _ = s[:(len(s))]
- _ = s[:len(s)-1]
- _ = s[:len(b)]
-
- _ = t.s[0:]
- _ = t.s[1:10]
- _ = t.s[2:len(t.s)]
- _ = t.s[3:(len(t.s))]
- _ = t.s[len(a) : len(t.s)-1]
- _ = t.s[0:len(b)]
-
- _ = t.s[:]
- _ = t.s[:10]
- _ = t.s[:len(t.s)]
- _ = t.s[:(len(t.s))]
- _ = t.s[:len(t.s)-1]
- _ = t.s[:len(b)]
-)
-
-func _() {
- s := s[0:len(s)]
- _ = s
-}
diff --git a/src/cmd/internal/bio/buf.go b/src/cmd/internal/bio/buf.go
new file mode 100644
index 0000000000..54ce3c7681
--- /dev/null
+++ b/src/cmd/internal/bio/buf.go
@@ -0,0 +1,99 @@
+// 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 bio implements common I/O abstractions used within the Go toolchain.
+package bio
+
+import (
+ "bufio"
+ "log"
+ "os"
+)
+
+// Reader implements a seekable buffered io.Reader.
+type Reader struct {
+ f *os.File
+ *bufio.Reader
+}
+
+// Writer implements a seekable buffered io.Writer.
+type Writer struct {
+ f *os.File
+ *bufio.Writer
+}
+
+// Create creates the file named name and returns a Writer
+// for that file.
+func Create(name string) (*Writer, error) {
+ f, err := os.Create(name)
+ if err != nil {
+ return nil, err
+ }
+ return &Writer{f: f, Writer: bufio.NewWriter(f)}, nil
+}
+
+// Open returns a Reader for the file named name.
+func Open(name string) (*Reader, error) {
+ f, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ return &Reader{f: f, Reader: bufio.NewReader(f)}, nil
+}
+
+func (r *Reader) Seek(offset int64, whence int) int64 {
+ if whence == 1 {
+ offset -= int64(r.Buffered())
+ }
+ off, err := r.f.Seek(offset, whence)
+ if err != nil {
+ log.Fatalf("seeking in output: %v", err)
+ }
+ r.Reset(r.f)
+ return off
+}
+
+func (w *Writer) Seek(offset int64, whence int) int64 {
+ if err := w.Flush(); err != nil {
+ log.Fatalf("writing output: %v", err)
+ }
+ off, err := w.f.Seek(offset, whence)
+ if err != nil {
+ log.Fatalf("seeking in output: %v", err)
+ }
+ return off
+}
+
+func (r *Reader) Offset() int64 {
+ off, err := r.f.Seek(0, 1)
+ if err != nil {
+ log.Fatalf("seeking in output [0, 1]: %v", err)
+ }
+ off -= int64(r.Buffered())
+ return off
+}
+
+func (w *Writer) Offset() int64 {
+ if err := w.Flush(); err != nil {
+ log.Fatalf("writing output: %v", err)
+ }
+ off, err := w.f.Seek(0, 1)
+ if err != nil {
+ log.Fatalf("seeking in output [0, 1]: %v", err)
+ }
+ return off
+}
+
+func (r *Reader) Close() error {
+ return r.f.Close()
+}
+
+func (w *Writer) Close() error {
+ err := w.Flush()
+ err1 := w.f.Close()
+ if err == nil {
+ err = err1
+ }
+ return err
+}
diff --git a/src/cmd/internal/bio/must.go b/src/cmd/internal/bio/must.go
new file mode 100644
index 0000000000..3604b29175
--- /dev/null
+++ b/src/cmd/internal/bio/must.go
@@ -0,0 +1,43 @@
+// Copyright 2016 The Go 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 bio
+
+import (
+ "io"
+ "log"
+)
+
+// MustClose closes Closer c and calls log.Fatal if it returns a non-nil error.
+func MustClose(c io.Closer) {
+ if err := c.Close(); err != nil {
+ log.Fatal(err)
+ }
+}
+
+// MustWriter returns a Writer that wraps the provided Writer,
+// except that it calls log.Fatal instead of returning a non-nil error.
+func MustWriter(w io.Writer) io.Writer {
+ return mustWriter{w}
+}
+
+type mustWriter struct {
+ w io.Writer
+}
+
+func (w mustWriter) Write(b []byte) (int, error) {
+ n, err := w.w.Write(b)
+ if err != nil {
+ log.Fatal(err)
+ }
+ return n, nil
+}
+
+func (w mustWriter) WriteString(s string) (int, error) {
+ n, err := io.WriteString(w.w, s)
+ if err != nil {
+ log.Fatal(err)
+ }
+ return n, nil
+}
diff --git a/src/cmd/internal/goobj/read.go b/src/cmd/internal/goobj/read.go
index 5434661384..698d58efe0 100644
--- a/src/cmd/internal/goobj/read.go
+++ b/src/cmd/internal/goobj/read.go
@@ -229,11 +229,8 @@ var (
errCorruptArchive = errors.New("corrupt archive")
errTruncatedArchive = errors.New("truncated archive")
- errNotArchive = errors.New("unrecognized archive format")
-
- errCorruptObject = errors.New("corrupt object file")
- errTruncatedObject = errors.New("truncated object file")
- errNotObject = errors.New("unrecognized object file format")
+ errCorruptObject = errors.New("corrupt object file")
+ errNotObject = errors.New("unrecognized object file format")
)
// An objReader is an object file reader.
diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go
index f49ee65a04..564f96a94e 100644
--- a/src/cmd/internal/obj/arm/asm5.go
+++ b/src/cmd/internal/obj/arm/asm5.go
@@ -870,7 +870,7 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
t.To.Type = a.Type
t.To.Name = a.Name
- if ctxt.Flag_shared != 0 && t.To.Sym != nil {
+ if ctxt.Flag_shared && t.To.Sym != nil {
t.Rel = p
}
@@ -1015,7 +1015,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
ctxt.Instoffset = 0 // s.b. unused but just in case
if a.Sym.Type == obj.STLSBSS {
- if ctxt.Flag_shared != 0 {
+ if ctxt.Flag_shared {
return C_TLS_IE
} else {
return C_TLS_LE
@@ -1322,7 +1322,7 @@ func buildop(ctxt *obj.Link) {
}
for n = 0; optab[n].as != obj.AXXX; n++ {
if optab[n].flag&LPCREL != 0 {
- if ctxt.Flag_shared != 0 {
+ if ctxt.Flag_shared {
optab[n].size += int8(optab[n].pcrelsiz)
} else {
optab[n].flag &^= LPCREL
@@ -1633,7 +1633,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
rel.Sym = p.To.Sym
rel.Add = p.To.Offset
- if ctxt.Flag_shared != 0 {
+ if ctxt.Flag_shared {
if p.To.Name == obj.NAME_GOTREF {
rel.Type = obj.R_GOTPCREL
} else {
diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go
index 92ffc7b2f3..042e6ab648 100644
--- a/src/cmd/internal/obj/arm/obj5.go
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -32,7 +32,7 @@ package arm
import (
"cmd/internal/obj"
- "encoding/binary"
+ "cmd/internal/sys"
"fmt"
"log"
"math"
@@ -412,7 +412,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p.As = AMOVW
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
- p.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+ p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
@@ -708,9 +708,9 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
p.As = AMOVW
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
- p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+ p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
if ctxt.Cursym.Cfunc {
- p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+ p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
@@ -1032,15 +1032,10 @@ var unaryDst = map[obj.As]bool{
}
var Linkarm = obj.LinkArch{
- ByteOrder: binary.LittleEndian,
- Name: "arm",
- Thechar: '5',
+ Arch: sys.ArchARM,
Preprocess: preprocess,
Assemble: span5,
Follow: follow,
Progedit: progedit,
UnaryDst: unaryDst,
- Minlc: 4,
- Ptrsize: 4,
- Regsize: 4,
}
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index ff8d4fdf60..28bebaa3f7 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -155,6 +155,7 @@ var optab = []Optab{
{AADC, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
{AADC, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
{ANEG, C_REG, C_NONE, C_REG, 25, 4, 0, 0, 0},
+ {ANEG, C_NONE, C_NONE, C_REG, 25, 4, 0, 0, 0},
{ANGC, C_REG, C_NONE, C_REG, 17, 4, 0, 0, 0},
{ACMP, C_REG, C_REG, C_NONE, 1, 4, 0, 0, 0},
{AADD, C_ADDCON, C_RSP, C_RSP, 2, 4, 0, 0, 0},
@@ -972,7 +973,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
ctxt.Instoffset = a.Offset
if a.Sym != nil { // use relocation
if a.Sym.Type == obj.STLSBSS {
- if ctxt.Flag_shared != 0 {
+ if ctxt.Flag_shared {
return C_TLS_IE
} else {
return C_TLS_LE
@@ -1087,7 +1088,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
a1 := int(p.Optab)
if a1 != 0 {
- return &optab[a1-1:][0]
+ return &optab[a1-1]
}
a1 = int(p.From.Class)
if a1 == 0 {
@@ -2198,6 +2199,9 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o1 = oprrr(ctxt, p.As)
rf := int(p.From.Reg)
+ if rf == C_NONE {
+ rf = int(p.To.Reg)
+ }
rt := int(p.To.Reg)
o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
diff --git a/src/cmd/internal/obj/arm64/list7.go b/src/cmd/internal/obj/arm64/list7.go
index 36f544b53a..ad9ff0965c 100644
--- a/src/cmd/internal/obj/arm64/list7.go
+++ b/src/cmd/internal/obj/arm64/list7.go
@@ -71,7 +71,7 @@ func Rconv(r int) string {
case REG_F0 <= r && r <= REG_F31:
return fmt.Sprintf("F%d", r-REG_F0)
case REG_V0 <= r && r <= REG_V31:
- return fmt.Sprintf("V%d", r-REG_F0)
+ return fmt.Sprintf("V%d", r-REG_V0)
case COND_EQ <= r && r <= COND_NV:
return strcond[r-COND_EQ]
case r == REGSP:
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
index b3de44c029..ffa1b416d6 100644
--- a/src/cmd/internal/obj/arm64/obj7.go
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -32,7 +32,7 @@ package arm64
import (
"cmd/internal/obj"
- "encoding/binary"
+ "cmd/internal/sys"
"fmt"
"log"
"math"
@@ -56,9 +56,9 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
- p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+ p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
if ctxt.Cursym.Cfunc {
- p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+ p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
@@ -250,7 +250,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
if p.From.Type == obj.TYPE_FCONST {
f32 := float32(p.From.Val.(float64))
i32 := math.Float32bits(f32)
- literal := fmt.Sprintf("$f32.%08x", uint32(i32))
+ literal := fmt.Sprintf("$f32.%08x", i32)
s := obj.Linklookup(ctxt, literal, 0)
s.Size = 4
p.From.Type = obj.TYPE_MEM
@@ -263,7 +263,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
case AFMOVD:
if p.From.Type == obj.TYPE_FCONST {
i64 := math.Float64bits(p.From.Val.(float64))
- literal := fmt.Sprintf("$f64.%016x", uint64(i64))
+ literal := fmt.Sprintf("$f64.%016x", i64)
s := obj.Linklookup(ctxt, literal, 0)
s.Size = 8
p.From.Type = obj.TYPE_MEM
@@ -778,7 +778,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.From.Reg = REGG
- q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+ q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R1
@@ -941,15 +941,10 @@ var unaryDst = map[obj.As]bool{
}
var Linkarm64 = obj.LinkArch{
- ByteOrder: binary.LittleEndian,
- Name: "arm64",
- Thechar: '7',
+ Arch: sys.ArchARM64,
Preprocess: preprocess,
Assemble: span7,
Follow: follow,
Progedit: progedit,
UnaryDst: unaryDst,
- Minlc: 4,
- Ptrsize: 8,
- Regsize: 8,
}
diff --git a/src/cmd/internal/obj/data.go b/src/cmd/internal/obj/data.go
index a3cc178adc..5fe4cb10a5 100644
--- a/src/cmd/internal/obj/data.go
+++ b/src/cmd/internal/obj/data.go
@@ -75,7 +75,11 @@ func (s *LSym) prepwrite(ctxt *Link, off int64, siz int) {
if s.Type == SBSS || s.Type == STLSBSS {
ctxt.Diag("cannot supply data for BSS var")
}
- s.Grow(off + int64(siz))
+ l := off + int64(siz)
+ s.Grow(l)
+ if l > s.Size {
+ s.Size = l
+ }
}
// WriteFloat32 writes f into s at offset off.
@@ -110,18 +114,37 @@ func (s *LSym) WriteInt(ctxt *Link, off int64, siz int, i int64) {
// WriteAddr writes an address of size siz into s at offset off.
// rsym and roff specify the relocation for the address.
func (s *LSym) WriteAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64) {
- if siz != ctxt.Arch.Ptrsize {
- ctxt.Diag("WriteAddr: bad address size: %d", siz)
+ if siz != ctxt.Arch.PtrSize {
+ ctxt.Diag("WriteAddr: bad address size %d in %s", siz, s.Name)
}
s.prepwrite(ctxt, off, siz)
r := Addrel(s)
r.Off = int32(off)
+ if int64(r.Off) != off {
+ ctxt.Diag("WriteAddr: off overflow %d in %s", off, s.Name)
+ }
r.Siz = uint8(siz)
r.Sym = rsym
r.Type = R_ADDR
r.Add = roff
}
+// WriteOff writes a 4 byte offset to rsym+roff into s at offset off.
+// After linking the 4 bytes stored at s+off will be
+// rsym+roff-(start of section that s is in).
+func (s *LSym) WriteOff(ctxt *Link, off int64, rsym *LSym, roff int64) {
+ s.prepwrite(ctxt, off, 4)
+ r := Addrel(s)
+ r.Off = int32(off)
+ if int64(r.Off) != off {
+ ctxt.Diag("WriteOff: off overflow %d in %s", off, s.Name)
+ }
+ r.Siz = 4
+ r.Sym = rsym
+ r.Type = R_ADDROFF
+ r.Add = roff
+}
+
// WriteString writes a string of size siz into s at offset off.
func (s *LSym) WriteString(ctxt *Link, off int64, siz int, str string) {
if siz < len(str) {
@@ -131,6 +154,13 @@ func (s *LSym) WriteString(ctxt *Link, off int64, siz int, str string) {
copy(s.P[off:off+int64(siz)], str)
}
+// WriteBytes writes a slice of bytes into s at offset off.
+func (s *LSym) WriteBytes(ctxt *Link, off int64, b []byte) int64 {
+ s.prepwrite(ctxt, off, len(b))
+ copy(s.P[off:], b)
+ return off + int64(len(b))
+}
+
func Addrel(s *LSym) *Reloc {
s.R = append(s.R, Reloc{})
return &s.R[len(s.R)-1]
@@ -153,7 +183,7 @@ func Setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 {
case 4:
ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(v))
case 8:
- ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(v))
+ ctxt.Arch.ByteOrder.PutUint64(s.P[off:], v)
}
return off + wid
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 24f028f737..5f257f60ab 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -30,7 +30,10 @@
package obj
-import "encoding/binary"
+import (
+ "bufio"
+ "cmd/internal/sys"
+)
// An Addr is an argument to an instruction.
// The general forms and their encodings are:
@@ -423,6 +426,8 @@ const (
SCONST
SDYNIMPORT
SHOSTOBJ
+ SDWARFSECT
+ SDWARFINFO
SSUB = 1 << 8
SMASK = SSUB - 1
SHIDDEN = 1 << 9
@@ -452,6 +457,9 @@ const (
// R_ADDRMIPS (only used on mips64) resolves to a 32-bit external address,
// by loading the address into a register with two instructions (lui, ori).
R_ADDRMIPS
+ // R_ADDROFF resolves to a 32-bit offset from the beginning of the section
+ // holding the data being relocated to the referenced symbol.
+ R_ADDROFF
R_SIZE
R_CALL
R_CALLARM
@@ -484,17 +492,20 @@ const (
// should be linked into the final binary, even if there are no other
// direct references. (This is used for types reachable by reflection.)
R_USETYPE
- // R_METHOD resolves to an *rtype for a method.
- // It is used when linking from the uncommonType of another *rtype, and
- // may be set to zero by the linker if it determines the method text is
- // unreachable by the linked program.
- R_METHOD
+ // R_METHODOFF resolves to a 32-bit offset from the beginning of the section
+ // holding the data being relocated to the referenced symbol.
+ // It is a variant of R_ADDROFF used when linking from the uncommonType of a
+ // *rtype, and may be set to zero by the linker if it determines the method
+ // text is unreachable by the linked program.
+ R_METHODOFF
R_POWER_TOC
R_GOTPCREL
// R_JMPMIPS (only used on mips64) resolves to non-PC-relative target address
// of a JMP instruction, by encoding the address into the instruction.
// The stack nosplit check ignores this since it is not a function call.
R_JMPMIPS
+ // R_DWARFREF resolves to the offset of the symbol from its section.
+ R_DWARFREF
// Platform dependent relocations. Architectures with fixed width instructions
// have the inherent issue that a 32-bit (or 64-bit!) displacement cannot be
@@ -590,19 +601,6 @@ type Pcdata struct {
P []byte
}
-// Pcdata iterator.
-// for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
-type Pciter struct {
- d Pcdata
- p []byte
- pc uint32
- nextpc uint32
- pcscale uint32
- value int32
- start int
- done int
-}
-
// symbol version, incremented each time a file is loaded.
// version==1 is reserved for savehist.
const (
@@ -619,10 +617,10 @@ type Link struct {
Debugvlog int32
Debugdivmod int32
Debugpcln int32
- Flag_shared int32
+ Flag_shared bool
Flag_dynlink bool
Flag_optimize bool
- Bso *Biobuf
+ Bso *bufio.Writer
Pathname string
Goroot string
Goroot_final string
@@ -678,15 +676,15 @@ func (ctxt *Link) Diag(format string, args ...interface{}) {
// on the stack in the function prologue and so always have a pointer between
// the hardware stack pointer and the local variable area.
func (ctxt *Link) FixedFrameSize() int64 {
- switch ctxt.Arch.Thechar {
- case '6', '8':
+ switch ctxt.Arch.Family {
+ case sys.AMD64, sys.I386:
return 0
- case '9':
+ case sys.PPC64:
// PIC code on ppc64le requires 32 bytes of stack, and it's easier to
// just use that much stack always on ppc64x.
- return int64(4 * ctxt.Arch.Ptrsize)
+ return int64(4 * ctxt.Arch.PtrSize)
default:
- return int64(ctxt.Arch.Ptrsize)
+ return int64(ctxt.Arch.PtrSize)
}
}
@@ -697,17 +695,12 @@ type SymVer struct {
// LinkArch is the definition of a single architecture.
type LinkArch struct {
- ByteOrder binary.ByteOrder
- Name string
- Thechar int
+ *sys.Arch
Preprocess func(*Link, *LSym)
Assemble func(*Link, *LSym)
Follow func(*Link, *LSym)
Progedit func(*Link, *Prog)
UnaryDst map[As]bool // Instruction takes one operand, a destination.
- Minlc int
- Ptrsize int
- Regsize int
}
/* executable header types */
@@ -725,27 +718,6 @@ const (
Hwindows
)
-type Plist struct {
- Name *LSym
- Firstpc *Prog
- Recur int
- Link *Plist
-}
-
-/*
- * start a new Prog list.
- */
-func Linknewplist(ctxt *Link) *Plist {
- pl := new(Plist)
- if ctxt.Plist == nil {
- ctxt.Plist = pl
- } else {
- ctxt.Plast.Link = pl
- }
- ctxt.Plast = pl
- return pl
-}
-
// AsmBuf is a simple buffer to assemble variable-length x86 instructions into.
type AsmBuf struct {
buf [100]byte
diff --git a/src/cmd/internal/obj/mips/asm0.go b/src/cmd/internal/obj/mips/asm0.go
index 521cb66dec..73d6cabbcb 100644
--- a/src/cmd/internal/obj/mips/asm0.go
+++ b/src/cmd/internal/obj/mips/asm0.go
@@ -611,7 +611,7 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
a1 := int(p.Optab)
if a1 != 0 {
- return &optab[a1-1:][0]
+ return &optab[a1-1]
}
a1 = int(p.From.Class)
if a1 == 0 {
@@ -974,10 +974,6 @@ func OP_JMP(op uint32, i uint32) uint32 {
return op | i&0x3FFFFFF
}
-func oclass(a *obj.Addr) int {
- return int(a.Class) - 1
-}
-
func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o1 := uint32(0)
o2 := uint32(0)
@@ -1028,7 +1024,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o1 = OP_IRR(opirr(ctxt, p.As), uint32(v), uint32(r), uint32(p.To.Reg))
case 5: /* syscall */
- o1 = uint32(oprrr(ctxt, p.As))
+ o1 = oprrr(ctxt, p.As)
case 6: /* beq r1,[r2],sbra */
v := int32(0)
diff --git a/src/cmd/internal/obj/mips/obj0.go b/src/cmd/internal/obj/mips/obj0.go
index ca7d4465c9..49fc2fb864 100644
--- a/src/cmd/internal/obj/mips/obj0.go
+++ b/src/cmd/internal/obj/mips/obj0.go
@@ -31,7 +31,7 @@ package mips
import (
"cmd/internal/obj"
- "encoding/binary"
+ "cmd/internal/sys"
"fmt"
"math"
)
@@ -336,7 +336,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
q.As = AMOVV
q.From.Type = obj.TYPE_MEM
q.From.Reg = REGG
- q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+ q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R1
@@ -559,9 +559,9 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
p.As = AMOVV
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
- p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+ p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
if ctxt.Cursym.Cfunc {
- p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+ p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
@@ -1469,27 +1469,17 @@ loop:
}
var Linkmips64 = obj.LinkArch{
- ByteOrder: binary.BigEndian,
- Name: "mips64",
- Thechar: '0',
+ Arch: sys.ArchMIPS64,
Preprocess: preprocess,
Assemble: span0,
Follow: follow,
Progedit: progedit,
- Minlc: 4,
- Ptrsize: 8,
- Regsize: 8,
}
var Linkmips64le = obj.LinkArch{
- ByteOrder: binary.LittleEndian,
- Name: "mips64le",
- Thechar: '0',
+ Arch: sys.ArchMIPS64LE,
Preprocess: preprocess,
Assemble: span0,
Follow: follow,
Progedit: progedit,
- Minlc: 4,
- Ptrsize: 8,
- Regsize: 8,
}
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index 30a380fadf..17175ebf06 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -109,207 +109,21 @@ package obj
import (
"bufio"
+ "cmd/internal/sys"
"fmt"
"log"
"path/filepath"
"sort"
- "strings"
)
// The Go and C compilers, and the assembler, call writeobj to write
// out a Go object file. The linker does not call this; the linker
// does not write out object files.
-func Writeobjdirect(ctxt *Link, b *Biobuf) {
+func Writeobjdirect(ctxt *Link, b *bufio.Writer) {
Flushplist(ctxt)
WriteObjFile(ctxt, b)
}
-func Flushplist(ctxt *Link) {
- flushplist(ctxt, ctxt.Debugasm == 0)
-}
-func FlushplistNoFree(ctxt *Link) {
- flushplist(ctxt, false)
-}
-func flushplist(ctxt *Link, freeProgs bool) {
- // Build list of symbols, and assign instructions to lists.
- // Ignore ctxt->plist boundaries. There are no guarantees there,
- // and the assemblers just use one big list.
- var curtext *LSym
- var etext *Prog
- var text []*LSym
-
- for pl := ctxt.Plist; pl != nil; pl = pl.Link {
- var plink *Prog
- for p := pl.Firstpc; p != nil; p = plink {
- if ctxt.Debugasm != 0 && ctxt.Debugvlog != 0 {
- fmt.Printf("obj: %v\n", p)
- }
- plink = p.Link
- p.Link = nil
-
- switch p.As {
- case AEND:
- continue
-
- case ATYPE:
- // Assume each TYPE instruction describes
- // a different local variable or parameter,
- // so no dedup.
- // Using only the TYPE instructions means
- // that we discard location information about local variables
- // in C and assembly functions; that information is inferred
- // from ordinary references, because there are no TYPE
- // instructions there. Without the type information, gdb can't
- // use the locations, so we don't bother to save them.
- // If something else could use them, we could arrange to
- // preserve them.
- if curtext == nil {
- continue
- }
- a := new(Auto)
- a.Asym = p.From.Sym
- a.Aoffset = int32(p.From.Offset)
- a.Name = int16(p.From.Name)
- a.Gotype = p.From.Gotype
- a.Link = curtext.Autom
- curtext.Autom = a
- continue
-
- case AGLOBL:
- s := p.From.Sym
- if s.Seenglobl {
- fmt.Printf("duplicate %v\n", p)
- }
- s.Seenglobl = true
- if s.Onlist {
- log.Fatalf("symbol %s listed multiple times", s.Name)
- }
- s.Onlist = true
- ctxt.Data = append(ctxt.Data, s)
- s.Size = p.To.Offset
- if s.Type == 0 || s.Type == SXREF {
- s.Type = SBSS
- }
- flag := int(p.From3.Offset)
- if flag&DUPOK != 0 {
- s.Dupok = true
- }
- if flag&RODATA != 0 {
- s.Type = SRODATA
- } else if flag&NOPTR != 0 {
- s.Type = SNOPTRBSS
- } else if flag&TLSBSS != 0 {
- s.Type = STLSBSS
- }
- continue
-
- case ATEXT:
- s := p.From.Sym
- if s == nil {
- // func _() { }
- curtext = nil
-
- continue
- }
-
- if s.Text != nil {
- log.Fatalf("duplicate TEXT for %s", s.Name)
- }
- if s.Onlist {
- log.Fatalf("symbol %s listed multiple times", s.Name)
- }
- s.Onlist = true
- text = append(text, s)
- flag := int(p.From3Offset())
- if flag&DUPOK != 0 {
- s.Dupok = true
- }
- if flag&NOSPLIT != 0 {
- s.Nosplit = true
- }
- if flag&REFLECTMETHOD != 0 {
- s.ReflectMethod = true
- }
- s.Type = STEXT
- s.Text = p
- etext = p
- curtext = s
- continue
-
- case AFUNCDATA:
- // Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
- if curtext == nil { // func _() {}
- continue
- }
- if p.To.Sym.Name == "go_args_stackmap" {
- if p.From.Type != TYPE_CONST || p.From.Offset != FUNCDATA_ArgsPointerMaps {
- ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps")
- }
- p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", curtext.Name), int(curtext.Version))
- }
-
- }
-
- if curtext == nil {
- etext = nil
- continue
- }
- etext.Link = p
- etext = p
- }
- }
-
- // Add reference to Go arguments for C or assembly functions without them.
- for _, s := range text {
- if !strings.HasPrefix(s.Name, "\"\".") {
- continue
- }
- found := false
- var p *Prog
- for p = s.Text; p != nil; p = p.Link {
- if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == FUNCDATA_ArgsPointerMaps {
- found = true
- break
- }
- }
-
- if !found {
- p = Appendp(ctxt, s.Text)
- p.As = AFUNCDATA
- p.From.Type = TYPE_CONST
- p.From.Offset = FUNCDATA_ArgsPointerMaps
- p.To.Type = TYPE_MEM
- p.To.Name = NAME_EXTERN
- p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", s.Name), int(s.Version))
- }
- }
-
- // Turn functions into machine code images.
- for _, s := range text {
- mkfwd(s)
- linkpatch(ctxt, s)
- if ctxt.Flag_optimize {
- ctxt.Arch.Follow(ctxt, s)
- }
- ctxt.Arch.Preprocess(ctxt, s)
- ctxt.Arch.Assemble(ctxt, s)
- fieldtrack(ctxt, s)
- linkpcln(ctxt, s)
- if freeProgs {
- s.Text = nil
- }
- }
-
- // Add to running list in ctxt.
- ctxt.Text = append(ctxt.Text, text...)
- ctxt.Plist = nil
- ctxt.Plast = nil
- ctxt.Curp = nil
- if freeProgs {
- ctxt.freeProgs()
- }
-}
-
// objWriter writes Go object files.
type objWriter struct {
wr *bufio.Writer
@@ -372,16 +186,16 @@ func (w *objWriter) writeLengths() {
w.writeInt(int64(w.nFile))
}
-func newObjWriter(ctxt *Link, b *Biobuf) *objWriter {
+func newObjWriter(ctxt *Link, b *bufio.Writer) *objWriter {
return &objWriter{
ctxt: ctxt,
- wr: b.w,
+ wr: b,
vrefIdx: make(map[string]int),
refIdx: make(map[string]int),
}
}
-func WriteObjFile(ctxt *Link, b *Biobuf) {
+func WriteObjFile(ctxt *Link, b *bufio.Writer) {
w := newObjWriter(ctxt, b)
// Magic header
@@ -556,10 +370,10 @@ func (w *objWriter) writeSymDebug(s *LSym) {
} else if r.Type == R_TLS_LE {
name = "TLS"
}
- if ctxt.Arch.Thechar == '5' || ctxt.Arch.Thechar == '9' {
- fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(int64(r.Add)))
+ if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
+ fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add))
} else {
- fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, int64(r.Add))
+ fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add)
}
}
}
@@ -659,7 +473,7 @@ func (w *objWriter) writeSym(s *LSym) {
func (w *objWriter) writeInt(sval int64) {
var v uint64
- uv := (uint64(sval) << 1) ^ uint64(int64(sval>>63))
+ uv := (uint64(sval) << 1) ^ uint64(sval>>63)
p := w.varintbuf[:]
for v = uv; v >= 0x80; v >>= 7 {
p[0] = uint8(v | 0x80)
diff --git a/src/cmd/internal/obj/pcln.go b/src/cmd/internal/obj/pcln.go
index 9770c96fcc..b1536eb224 100644
--- a/src/cmd/internal/obj/pcln.go
+++ b/src/cmd/internal/obj/pcln.go
@@ -64,7 +64,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
if val == oldval && started != 0 {
val = valfunc(ctxt, func_, val, p, 1, arg)
if ctxt.Debugpcln != 0 {
- fmt.Fprintf(ctxt.Bso, "%6x %6s %v\n", uint64(int64(p.Pc)), "", p)
+ fmt.Fprintf(ctxt.Bso, "%6x %6s %v\n", uint64(p.Pc), "", p)
}
continue
}
@@ -76,7 +76,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
if p.Link != nil && p.Link.Pc == p.Pc {
val = valfunc(ctxt, func_, val, p, 1, arg)
if ctxt.Debugpcln != 0 {
- fmt.Fprintf(ctxt.Bso, "%6x %6s %v\n", uint64(int64(p.Pc)), "", p)
+ fmt.Fprintf(ctxt.Bso, "%6x %6s %v\n", uint64(p.Pc), "", p)
}
continue
}
@@ -96,11 +96,11 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
// where the 0x80 bit indicates that the integer continues.
if ctxt.Debugpcln != 0 {
- fmt.Fprintf(ctxt.Bso, "%6x %6d %v\n", uint64(int64(p.Pc)), val, p)
+ fmt.Fprintf(ctxt.Bso, "%6x %6d %v\n", uint64(p.Pc), val, p)
}
if started != 0 {
- addvarint(ctxt, dst, uint32((p.Pc-pc)/int64(ctxt.Arch.Minlc)))
+ addvarint(ctxt, dst, uint32((p.Pc-pc)/int64(ctxt.Arch.MinLC)))
pc = p.Pc
}
@@ -118,9 +118,9 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
if started != 0 {
if ctxt.Debugpcln != 0 {
- fmt.Fprintf(ctxt.Bso, "%6x done\n", uint64(int64(func_.Text.Pc)+func_.Size))
+ fmt.Fprintf(ctxt.Bso, "%6x done\n", uint64(func_.Text.Pc+func_.Size))
}
- addvarint(ctxt, dst, uint32((func_.Size-pc)/int64(ctxt.Arch.Minlc)))
+ addvarint(ctxt, dst, uint32((func_.Size-pc)/int64(ctxt.Arch.MinLC)))
addvarint(ctxt, dst, 0) // terminator
}
@@ -158,19 +158,18 @@ func pctofileline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg
return int32(pcln.Lastindex)
}
- var i int32
- for i = 0; i < int32(len(pcln.File)); i++ {
- file := pcln.File[i]
+ for i, file := range pcln.File {
if file == f {
pcln.Lastfile = f
- pcln.Lastindex = int(i)
+ pcln.Lastindex = i
return int32(i)
}
}
+ i := len(pcln.File)
pcln.File = append(pcln.File, f)
pcln.Lastfile = f
- pcln.Lastindex = int(i)
- return i
+ pcln.Lastindex = i
+ return int32(i)
}
// pctospadj computes the sp adjustment in effect.
diff --git a/src/cmd/internal/obj/plist.go b/src/cmd/internal/obj/plist.go
new file mode 100644
index 0000000000..e55dbeca1e
--- /dev/null
+++ b/src/cmd/internal/obj/plist.go
@@ -0,0 +1,218 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package obj
+
+import (
+ "fmt"
+ "log"
+ "strings"
+)
+
+type Plist struct {
+ Name *LSym
+ Firstpc *Prog
+ Recur int
+ Link *Plist
+}
+
+/*
+ * start a new Prog list.
+ */
+func Linknewplist(ctxt *Link) *Plist {
+ pl := new(Plist)
+ if ctxt.Plist == nil {
+ ctxt.Plist = pl
+ } else {
+ ctxt.Plast.Link = pl
+ }
+ ctxt.Plast = pl
+ return pl
+}
+
+func Flushplist(ctxt *Link) {
+ flushplist(ctxt, ctxt.Debugasm == 0)
+}
+func FlushplistNoFree(ctxt *Link) {
+ flushplist(ctxt, false)
+}
+func flushplist(ctxt *Link, freeProgs bool) {
+ // Build list of symbols, and assign instructions to lists.
+ // Ignore ctxt->plist boundaries. There are no guarantees there,
+ // and the assemblers just use one big list.
+ var curtext *LSym
+ var etext *Prog
+ var text []*LSym
+
+ for pl := ctxt.Plist; pl != nil; pl = pl.Link {
+ var plink *Prog
+ for p := pl.Firstpc; p != nil; p = plink {
+ if ctxt.Debugasm != 0 && ctxt.Debugvlog != 0 {
+ fmt.Printf("obj: %v\n", p)
+ }
+ plink = p.Link
+ p.Link = nil
+
+ switch p.As {
+ case AEND:
+ continue
+
+ case ATYPE:
+ // Assume each TYPE instruction describes
+ // a different local variable or parameter,
+ // so no dedup.
+ // Using only the TYPE instructions means
+ // that we discard location information about local variables
+ // in C and assembly functions; that information is inferred
+ // from ordinary references, because there are no TYPE
+ // instructions there. Without the type information, gdb can't
+ // use the locations, so we don't bother to save them.
+ // If something else could use them, we could arrange to
+ // preserve them.
+ if curtext == nil {
+ continue
+ }
+ a := new(Auto)
+ a.Asym = p.From.Sym
+ a.Aoffset = int32(p.From.Offset)
+ a.Name = int16(p.From.Name)
+ a.Gotype = p.From.Gotype
+ a.Link = curtext.Autom
+ curtext.Autom = a
+ continue
+
+ case AGLOBL:
+ s := p.From.Sym
+ if s.Seenglobl {
+ fmt.Printf("duplicate %v\n", p)
+ }
+ s.Seenglobl = true
+ if s.Onlist {
+ log.Fatalf("symbol %s listed multiple times", s.Name)
+ }
+ s.Onlist = true
+ ctxt.Data = append(ctxt.Data, s)
+ s.Size = p.To.Offset
+ if s.Type == 0 || s.Type == SXREF {
+ s.Type = SBSS
+ }
+ flag := int(p.From3.Offset)
+ if flag&DUPOK != 0 {
+ s.Dupok = true
+ }
+ if flag&RODATA != 0 {
+ s.Type = SRODATA
+ } else if flag&NOPTR != 0 {
+ s.Type = SNOPTRBSS
+ } else if flag&TLSBSS != 0 {
+ s.Type = STLSBSS
+ }
+ continue
+
+ case ATEXT:
+ s := p.From.Sym
+ if s == nil {
+ // func _() { }
+ curtext = nil
+
+ continue
+ }
+
+ if s.Text != nil {
+ log.Fatalf("duplicate TEXT for %s", s.Name)
+ }
+ if s.Onlist {
+ log.Fatalf("symbol %s listed multiple times", s.Name)
+ }
+ s.Onlist = true
+ text = append(text, s)
+ flag := int(p.From3Offset())
+ if flag&DUPOK != 0 {
+ s.Dupok = true
+ }
+ if flag&NOSPLIT != 0 {
+ s.Nosplit = true
+ }
+ if flag&REFLECTMETHOD != 0 {
+ s.ReflectMethod = true
+ }
+ s.Type = STEXT
+ s.Text = p
+ etext = p
+ curtext = s
+ continue
+
+ case AFUNCDATA:
+ // Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
+ if curtext == nil { // func _() {}
+ continue
+ }
+ if p.To.Sym.Name == "go_args_stackmap" {
+ if p.From.Type != TYPE_CONST || p.From.Offset != FUNCDATA_ArgsPointerMaps {
+ ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps")
+ }
+ p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", curtext.Name), int(curtext.Version))
+ }
+
+ }
+
+ if curtext == nil {
+ etext = nil
+ continue
+ }
+ etext.Link = p
+ etext = p
+ }
+ }
+
+ // Add reference to Go arguments for C or assembly functions without them.
+ for _, s := range text {
+ if !strings.HasPrefix(s.Name, "\"\".") {
+ continue
+ }
+ found := false
+ var p *Prog
+ for p = s.Text; p != nil; p = p.Link {
+ if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == FUNCDATA_ArgsPointerMaps {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ p = Appendp(ctxt, s.Text)
+ p.As = AFUNCDATA
+ p.From.Type = TYPE_CONST
+ p.From.Offset = FUNCDATA_ArgsPointerMaps
+ p.To.Type = TYPE_MEM
+ p.To.Name = NAME_EXTERN
+ p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", s.Name), int(s.Version))
+ }
+ }
+
+ // Turn functions into machine code images.
+ for _, s := range text {
+ mkfwd(s)
+ linkpatch(ctxt, s)
+ if ctxt.Flag_optimize {
+ ctxt.Arch.Follow(ctxt, s)
+ }
+ ctxt.Arch.Preprocess(ctxt, s)
+ ctxt.Arch.Assemble(ctxt, s)
+ fieldtrack(ctxt, s)
+ linkpcln(ctxt, s)
+ if freeProgs {
+ s.Text = nil
+ }
+ }
+
+ // Add to running list in ctxt.
+ ctxt.Text = append(ctxt.Text, text...)
+ ctxt.Plist = nil
+ ctxt.Plast = nil
+ ctxt.Curp = nil
+ if freeProgs {
+ ctxt.freeProgs()
+ }
+}
diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go
index 0497d3b678..f786f3c443 100644
--- a/src/cmd/internal/obj/ppc64/asm9.go
+++ b/src/cmd/internal/obj/ppc64/asm9.go
@@ -585,7 +585,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
ctxt.Instoffset = a.Offset
if a.Sym != nil { // use relocation
if a.Sym.Type == obj.STLSBSS {
- if ctxt.Flag_shared != 0 {
+ if ctxt.Flag_shared {
return C_TLS_IE
} else {
return C_TLS_LE
@@ -1384,7 +1384,7 @@ const (
// which relocation to use with a load or store and only supports the needed
// instructions.
func opform(ctxt *obj.Link, insn uint32) int {
- switch uint32(insn) {
+ switch insn {
default:
ctxt.Diag("bad insn in loadform: %x", insn)
case OPVCC(58, 0, 0, 0), // ld
@@ -1413,7 +1413,7 @@ func opform(ctxt *obj.Link, insn uint32) int {
func symbolAccess(ctxt *obj.Link, s *obj.LSym, d int64, reg int16, op uint32) (o1, o2 uint32) {
var base uint32
form := opform(ctxt, op)
- if ctxt.Flag_shared != 0 {
+ if ctxt.Flag_shared {
base = REG_R2
} else {
base = REG_R0
@@ -1425,7 +1425,7 @@ func symbolAccess(ctxt *obj.Link, s *obj.LSym, d int64, reg int16, op uint32) (o
rel.Siz = 8
rel.Sym = s
rel.Add = d
- if ctxt.Flag_shared != 0 {
+ if ctxt.Flag_shared {
switch form {
case D_FORM:
rel.Type = obj.R_ADDRPOWER_TOCREL
@@ -1646,7 +1646,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
if v != 0 {
ctxt.Diag("illegal indexed instruction\n%v", p)
}
- if ctxt.Flag_shared != 0 && r == REG_R13 {
+ if ctxt.Flag_shared && r == REG_R13 {
rel := obj.Addrel(ctxt.Cursym)
rel.Off = int32(ctxt.Pc)
rel.Siz = 4
@@ -1677,7 +1677,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
if v != 0 {
ctxt.Diag("illegal indexed instruction\n%v", p)
}
- if ctxt.Flag_shared != 0 && r == REG_R13 {
+ if ctxt.Flag_shared && r == REG_R13 {
rel := obj.Addrel(ctxt.Cursym)
rel.Off = int32(ctxt.Pc)
rel.Siz = 4
@@ -2198,9 +2198,9 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
}
v := oprrr(ctxt, p.As)
t := v & (1<<10 | 1) /* OE|Rc */
- o1 = AOP_RRR(uint32(v)&^uint32(t), REGTMP, uint32(r), uint32(p.From.Reg))
+ o1 = AOP_RRR(v&^t, REGTMP, uint32(r), uint32(p.From.Reg))
o2 = AOP_RRR(OP_MULLW, REGTMP, REGTMP, uint32(p.From.Reg))
- o3 = AOP_RRR(OP_SUBF|uint32(t), uint32(p.To.Reg), REGTMP, uint32(r))
+ o3 = AOP_RRR(OP_SUBF|t, uint32(p.To.Reg), REGTMP, uint32(r))
if p.As == AREMU {
o4 = o3
@@ -2216,9 +2216,9 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
}
v := oprrr(ctxt, p.As)
t := v & (1<<10 | 1) /* OE|Rc */
- o1 = AOP_RRR(uint32(v)&^uint32(t), REGTMP, uint32(r), uint32(p.From.Reg))
+ o1 = AOP_RRR(v&^t, REGTMP, uint32(r), uint32(p.From.Reg))
o2 = AOP_RRR(OP_MULLD, REGTMP, REGTMP, uint32(p.From.Reg))
- o3 = AOP_RRR(OP_SUBF|uint32(t), uint32(p.To.Reg), REGTMP, uint32(r))
+ o3 = AOP_RRR(OP_SUBF|t, uint32(p.To.Reg), REGTMP, uint32(r))
case 52: /* mtfsbNx cr(n) */
v := regoff(ctxt, &p.From) & 31
@@ -2485,7 +2485,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
ctxt.Diag("invalid offset against tls var %v", p)
}
o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R2, 0)
- o2 = AOP_IRR(uint32(opload(ctxt, AMOVD)), uint32(p.To.Reg), uint32(p.To.Reg), 0)
+ o2 = AOP_IRR(opload(ctxt, AMOVD), uint32(p.To.Reg), uint32(p.To.Reg), 0)
rel := obj.Addrel(ctxt.Cursym)
rel.Off = int32(ctxt.Pc)
rel.Siz = 8
@@ -2499,7 +2499,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
}
o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R2, 0)
- o2 = AOP_IRR(uint32(opload(ctxt, AMOVD)), uint32(p.To.Reg), uint32(p.To.Reg), 0)
+ o2 = AOP_IRR(opload(ctxt, AMOVD), uint32(p.To.Reg), uint32(p.To.Reg), 0)
rel := obj.Addrel(ctxt.Cursym)
rel.Off = int32(ctxt.Pc)
rel.Siz = 8
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index 483df3a2b3..4f9b3943cf 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -31,7 +31,7 @@ package ppc64
import (
"cmd/internal/obj"
- "encoding/binary"
+ "cmd/internal/sys"
"fmt"
"math"
)
@@ -470,7 +470,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
q = p
- if ctxt.Flag_shared != 0 && cursym.Name != "runtime.duffzero" && cursym.Name != "runtime.duffcopy" && cursym.Name != "runtime.stackBarrier" {
+ if ctxt.Flag_shared && cursym.Name != "runtime.duffzero" && cursym.Name != "runtime.duffcopy" && cursym.Name != "runtime.stackBarrier" {
// When compiling Go into PIC, all functions must start
// with instructions to load the TOC pointer into r2:
//
@@ -558,7 +558,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
q.Spadj = int32(-aoffset)
}
- if ctxt.Flag_shared != 0 {
+ if ctxt.Flag_shared {
q = obj.Appendp(ctxt, q)
q.As = AMOVD
q.Lineno = p.Lineno
@@ -592,7 +592,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.From.Reg = REGG
- q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+ q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R3
@@ -827,9 +827,9 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
- p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+ p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
if ctxt.Cursym.Cfunc {
- p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+ p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
@@ -1181,27 +1181,17 @@ loop:
}
var Linkppc64 = obj.LinkArch{
- ByteOrder: binary.BigEndian,
- Name: "ppc64",
- Thechar: '9',
+ Arch: sys.ArchPPC64,
Preprocess: preprocess,
Assemble: span9,
Follow: follow,
Progedit: progedit,
- Minlc: 4,
- Ptrsize: 8,
- Regsize: 8,
}
var Linkppc64le = obj.LinkArch{
- ByteOrder: binary.LittleEndian,
- Name: "ppc64le",
- Thechar: '9',
+ Arch: sys.ArchPPC64LE,
Preprocess: preprocess,
Assemble: span9,
Follow: follow,
Progedit: progedit,
- Minlc: 4,
- Ptrsize: 8,
- Regsize: 8,
}
diff --git a/src/cmd/internal/obj/s390x/a.out.go b/src/cmd/internal/obj/s390x/a.out.go
index 2cb03ae603..e7256d1d41 100644
--- a/src/cmd/internal/obj/s390x/a.out.go
+++ b/src/cmd/internal/obj/s390x/a.out.go
@@ -218,6 +218,7 @@ const (
ADIVDU
AMULLW
AMULLD
+ AMULHD
AMULHDU
ASUB
ASUBC
diff --git a/src/cmd/internal/obj/s390x/anames.go b/src/cmd/internal/obj/s390x/anames.go
index e79a147a90..62dd181eda 100644
--- a/src/cmd/internal/obj/s390x/anames.go
+++ b/src/cmd/internal/obj/s390x/anames.go
@@ -17,6 +17,7 @@ var Anames = []string{
"DIVDU",
"MULLW",
"MULLD",
+ "MULHD",
"MULHDU",
"SUB",
"SUBC",
diff --git a/src/cmd/internal/obj/s390x/asmz.go b/src/cmd/internal/obj/s390x/asmz.go
index bccd7c3bd8..9b26580d11 100644
--- a/src/cmd/internal/obj/s390x/asmz.go
+++ b/src/cmd/internal/obj/s390x/asmz.go
@@ -150,6 +150,8 @@ var optab = []Optab{
Optab{AMULLW, C_REG, C_NONE, C_NONE, C_REG, 2, 0},
Optab{AMULLW, C_LCON, C_REG, C_NONE, C_REG, 22, 0},
Optab{AMULLW, C_LCON, C_NONE, C_NONE, C_REG, 22, 0},
+ Optab{AMULHD, C_REG, C_NONE, C_NONE, C_REG, 4, 0},
+ Optab{AMULHD, C_REG, C_REG, C_NONE, C_REG, 4, 0},
Optab{ASUBC, C_REG, C_REG, C_NONE, C_REG, 10, 0},
Optab{ASUBC, C_REG, C_NONE, C_NONE, C_REG, 10, 0},
Optab{ADIVW, C_REG, C_REG, C_NONE, C_REG, 2, 0},
@@ -471,7 +473,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
}
ctxt.Instoffset = a.Offset
if a.Sym.Type == obj.STLSBSS {
- if ctxt.Flag_shared != 0 {
+ if ctxt.Flag_shared {
return C_TLS_IE // initial exec model
}
return C_TLS_LE // local exec model
@@ -604,7 +606,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
a1 := int(p.Optab)
if a1 != 0 {
- return &optab[a1-1:][0]
+ return &optab[a1-1]
}
a1 = int(p.From.Class)
if a1 == 0 {
@@ -793,10 +795,11 @@ func buildop(ctxt *obj.Link) {
case ADIVW:
opset(AADDE, r)
opset(AMULLD, r)
- opset(AMULHDU, r)
opset(ADIVD, r)
opset(ADIVDU, r)
opset(ADIVWU, r)
+ case AMULHD:
+ opset(AMULHDU, r)
case AMOVBZ:
opset(AMOVH, r)
opset(AMOVHZ, r)
@@ -2580,8 +2583,6 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
opcode = op_MSGFR
case AMULLD:
opcode = op_MSGR
- case AMULHDU:
- opcode = op_MLGR
case ADIVW:
opcode = op_DSGFR
case ADIVWU:
@@ -2628,11 +2629,6 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
zRRE(opcode, REGTMP, uint32(p.From.Reg), asm)
zRRE(op_LGR, uint32(p.To.Reg), REGTMP2, asm)
- case AMULHDU:
- zRRE(op_LGR, REGTMP2, uint32(r), asm)
- zRRE(opcode, REGTMP, uint32(p.From.Reg), asm)
- zRRE(op_LGR, uint32(p.To.Reg), REGTMP, asm)
-
case AFADD, AFADDS:
if r == int(p.To.Reg) {
zRRE(opcode, uint32(p.To.Reg), uint32(p.From.Reg), asm)
@@ -2695,6 +2691,28 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
zRIL(_a, op_IIHF, uint32(p.To.Reg), uint32(v>>32), asm)
}
+ case 4: // multiply high (a*b)>>64
+ r := p.Reg
+ if r == 0 {
+ r = p.To.Reg
+ }
+ zRRE(op_LGR, REGTMP2, uint32(r), asm)
+ zRRE(op_MLGR, REGTMP, uint32(p.From.Reg), asm)
+ switch p.As {
+ case AMULHDU:
+ // Unsigned: move result into correct register.
+ zRRE(op_LGR, uint32(p.To.Reg), REGTMP, asm)
+ case AMULHD:
+ // Signed: need to convert result.
+ // See Hacker's Delight 8-3.
+ zRSY(op_SRAG, REGTMP2, uint32(p.From.Reg), 0, 63, asm)
+ zRRE(op_NGR, REGTMP2, uint32(r), asm)
+ zRRE(op_SGR, REGTMP, REGTMP2, asm)
+ zRSY(op_SRAG, REGTMP2, uint32(r), 0, 63, asm)
+ zRRE(op_NGR, REGTMP2, uint32(p.From.Reg), asm)
+ zRRF(op_SGRK, REGTMP2, 0, uint32(p.To.Reg), REGTMP, asm)
+ }
+
case 5: // syscall
zI(op_SVC, 0, asm)
diff --git a/src/cmd/internal/obj/s390x/objz.go b/src/cmd/internal/obj/s390x/objz.go
index 239deec6a1..454a0d76ec 100644
--- a/src/cmd/internal/obj/s390x/objz.go
+++ b/src/cmd/internal/obj/s390x/objz.go
@@ -31,7 +31,7 @@ package s390x
import (
"cmd/internal/obj"
- "encoding/binary"
+ "cmd/internal/sys"
"fmt"
"math"
)
@@ -460,7 +460,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.From.Reg = REGG
- q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+ q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R3
@@ -664,9 +664,9 @@ func stacksplitPre(ctxt *obj.Link, p *obj.Prog, framesize int32) (*obj.Prog, *ob
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
- p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+ p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
if ctxt.Cursym.Cfunc {
- p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+ p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
@@ -999,15 +999,10 @@ var unaryDst = map[obj.As]bool{
}
var Links390x = obj.LinkArch{
- ByteOrder: binary.BigEndian,
- Name: "s390x",
- Thechar: 'z',
+ Arch: sys.ArchS390X,
Preprocess: preprocess,
Assemble: spanz,
Follow: follow,
Progedit: progedit,
UnaryDst: unaryDst,
- Minlc: 2,
- Ptrsize: 8,
- Regsize: 8,
}
diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go
index 64df62a2ae..beacc94ee8 100644
--- a/src/cmd/internal/obj/sym.go
+++ b/src/cmd/internal/obj/sym.go
@@ -32,6 +32,7 @@
package obj
import (
+ "cmd/internal/sys"
"log"
"os"
"path/filepath"
@@ -100,7 +101,7 @@ func Linknew(arch *LinkArch) *Link {
}
// On arm, record goarm.
- if ctxt.Arch.Thechar == '5' {
+ if ctxt.Arch.Family == sys.ARM {
ctxt.Goarm = Getgoarm()
}
diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go
index 245fab9690..294cedcb0a 100644
--- a/src/cmd/internal/obj/util.go
+++ b/src/cmd/internal/obj/util.go
@@ -5,10 +5,8 @@
package obj
import (
- "bufio"
"bytes"
"fmt"
- "io"
"log"
"os"
"strings"
@@ -26,144 +24,6 @@ func Cputime() float64 {
return time.Since(start).Seconds()
}
-type Biobuf struct {
- f *os.File
- r *bufio.Reader
- w *bufio.Writer
- linelen int
-}
-
-func (b *Biobuf) Reader() *bufio.Reader { return b.r }
-
-func Bopenw(name string) (*Biobuf, error) {
- f, err := os.Create(name)
- if err != nil {
- return nil, err
- }
- return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil
-}
-
-func Bopenr(name string) (*Biobuf, error) {
- f, err := os.Open(name)
- if err != nil {
- return nil, err
- }
- return &Biobuf{f: f, r: bufio.NewReader(f)}, nil
-}
-
-func Binitw(w io.Writer) *Biobuf {
- return &Biobuf{w: bufio.NewWriter(w)}
-}
-
-func Binitr(r io.Reader) *Biobuf {
- return &Biobuf{r: bufio.NewReader(r)}
-}
-
-func (b *Biobuf) Write(p []byte) (int, error) {
- return b.w.Write(p)
-}
-
-func Bwritestring(b *Biobuf, p string) (int, error) {
- return b.w.WriteString(p)
-}
-
-func Bseek(b *Biobuf, offset int64, whence int) int64 {
- if b.w != nil {
- if err := b.w.Flush(); err != nil {
- log.Fatalf("writing output: %v", err)
- }
- } else if b.r != nil {
- if whence == 1 {
- offset -= int64(b.r.Buffered())
- }
- }
- off, err := b.f.Seek(offset, whence)
- if err != nil {
- log.Fatalf("seeking in output: %v", err)
- }
- if b.r != nil {
- b.r.Reset(b.f)
- }
- return off
-}
-
-func Boffset(b *Biobuf) int64 {
- if b.w != nil {
- if err := b.w.Flush(); err != nil {
- log.Fatalf("writing output: %v", err)
- }
- }
- off, err := b.f.Seek(0, 1)
- if err != nil {
- log.Fatalf("seeking in output [0, 1]: %v", err)
- }
- if b.r != nil {
- off -= int64(b.r.Buffered())
- }
- return off
-}
-
-func (b *Biobuf) Flush() error {
- return b.w.Flush()
-}
-
-func Bputc(b *Biobuf, c byte) {
- b.w.WriteByte(c)
-}
-
-const Beof = -1
-
-func Bread(b *Biobuf, p []byte) int {
- n, err := io.ReadFull(b.r, p)
- if n == 0 {
- if err != nil && err != io.EOF {
- n = -1
- }
- }
- return n
-}
-
-func Bgetc(b *Biobuf) int {
- c, err := b.r.ReadByte()
- if err != nil {
- return -1
- }
- return int(c)
-}
-
-func (b *Biobuf) Read(p []byte) (int, error) {
- return b.r.Read(p)
-}
-
-func (b *Biobuf) Peek(n int) ([]byte, error) {
- return b.r.Peek(n)
-}
-
-func Brdline(b *Biobuf, delim int) string {
- s, err := b.r.ReadBytes(byte(delim))
- if err != nil {
- log.Fatalf("reading input: %v", err)
- }
- b.linelen = len(s)
- return string(s)
-}
-
-func Blinelen(b *Biobuf) int {
- return b.linelen
-}
-
-func Bterm(b *Biobuf) error {
- var err error
- if b.w != nil {
- err = b.w.Flush()
- }
- err1 := b.f.Close()
- if err == nil {
- err = err1
- }
- return err
-}
-
func envOr(key, value string) string {
if x := os.Getenv(key); x != "" {
return x
@@ -419,7 +279,7 @@ func Dconv(p *Prog, a *Addr) string {
case TYPE_SHIFT:
v := int(a.Offset)
- op := string("<<>>->@>"[((v>>5)&3)<<1:])
+ op := "<<>>->@>"[((v>>5)&3)<<1:]
if v&(1<<4) != 0 {
str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
} else {
diff --git a/src/cmd/internal/obj/x86/a.out.go b/src/cmd/internal/obj/x86/a.out.go
index 64bd865e42..c41fd953e7 100644
--- a/src/cmd/internal/obj/x86/a.out.go
+++ b/src/cmd/internal/obj/x86/a.out.go
@@ -739,6 +739,8 @@ const (
AUNPCKLPS
AXORPD
AXORPS
+ APCMPESTRI
+
ARETFW
ARETFL
ARETFQ
diff --git a/src/cmd/internal/obj/x86/anames.go b/src/cmd/internal/obj/x86/anames.go
index 3b59e2f36f..e3fef54e71 100644
--- a/src/cmd/internal/obj/x86/anames.go
+++ b/src/cmd/internal/obj/x86/anames.go
@@ -682,6 +682,7 @@ var Anames = []string{
"UNPCKLPS",
"XORPD",
"XORPS",
+ "PCMPESTRI",
"RETFW",
"RETFL",
"RETFQ",
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index 773494b7af..1c7fcf37be 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -884,11 +884,6 @@ var yvex_vpbroadcast = []ytab{
{Yxm, Ynone, Yyr, Zvex_rm_v_r, 2},
}
-var yvex_xxmyxm = []ytab{
- {Yxr, Ynone, Yxm, Zvex_r_v_rm, 2},
- {Yyr, Ynone, Yxm, Zvex_r_v_rm, 2},
-}
-
var ymmxmm0f38 = []ytab{
{Ymm, Ynone, Ymr, Zlitm_r, 3},
{Yxm, Ynone, Yxr, Zlitm_r, 5},
@@ -1653,6 +1648,7 @@ var optab =
{AROUNDSS, yaes2, Pq, [23]uint8{0x3a, 0x0a, 0}},
{APSHUFD, yxshuf, Pq, [23]uint8{0x70, 0}},
{APCLMULQDQ, yxshuf, Pq, [23]uint8{0x3a, 0x44, 0}},
+ {APCMPESTRI, yxshuf, Pq, [23]uint8{0x3a, 0x61, 0}},
{AANDNL, yvex_r3, Pvex, [23]uint8{VEX_LZ_0F38_W0, 0xF2}},
{AANDNQ, yvex_r3, Pvex, [23]uint8{VEX_LZ_0F38_W1, 0xF2}},
@@ -1754,7 +1750,7 @@ func naclpad(ctxt *obj.Link, s *obj.LSym, c int32, pad int32) int32 {
}
func spadjop(ctxt *obj.Link, p *obj.Prog, l, q obj.As) obj.As {
- if p.Mode != 64 || ctxt.Arch.Ptrsize == 4 {
+ if p.Mode != 64 || ctxt.Arch.PtrSize == 4 {
return l
}
return q
@@ -2170,7 +2166,7 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
return 0x64 // FS
}
- if ctxt.Flag_shared != 0 {
+ if ctxt.Flag_shared {
log.Fatalf("unknown TLS base register for linux with -shared")
} else {
return 0x64 // FS
@@ -2190,7 +2186,7 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
}
if p.Mode == 32 {
- if a.Index == REG_TLS && ctxt.Flag_shared != 0 {
+ if a.Index == REG_TLS && ctxt.Flag_shared {
// When building for inclusion into a shared library, an instruction of the form
// MOVL 0(CX)(TLS*1), AX
// becomes
@@ -2219,7 +2215,7 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
return 0x26
case REG_TLS:
- if ctxt.Flag_shared != 0 {
+ if ctxt.Flag_shared {
// When building for inclusion into a shared library, an instruction of the form
// MOV 0(CX)(TLS*1), AX
// becomes
@@ -2293,7 +2289,7 @@ func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
case obj.NAME_EXTERN,
obj.NAME_STATIC:
- if a.Sym != nil && isextern(a.Sym) || (p.Mode == 32 && ctxt.Flag_shared == 0) {
+ if a.Sym != nil && isextern(a.Sym) || (p.Mode == 32 && !ctxt.Flag_shared) {
return Yi32
}
return Yiauto // use pc-relative addressing
@@ -2712,7 +2708,7 @@ func vaddr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r *obj.Reloc) int64 {
if a.Name == obj.NAME_GOTREF {
r.Siz = 4
r.Type = obj.R_GOTPCREL
- } else if isextern(s) || (p.Mode != 64 && ctxt.Flag_shared == 0) {
+ } else if isextern(s) || (p.Mode != 64 && !ctxt.Flag_shared) {
r.Siz = 4
r.Type = obj.R_ADDR
} else {
@@ -2733,7 +2729,7 @@ func vaddr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r *obj.Reloc) int64 {
log.Fatalf("reloc")
}
- if ctxt.Flag_shared == 0 || isAndroid {
+ if !ctxt.Flag_shared || isAndroid {
r.Type = obj.R_TLS_LE
r.Siz = 4
r.Off = -1 // caller must fill in
@@ -2798,7 +2794,7 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
if !isextern(a.Sym) && p.Mode == 64 {
goto bad
}
- if p.Mode == 32 && ctxt.Flag_shared != 0 {
+ if p.Mode == 32 && ctxt.Flag_shared {
base = REG_CX
} else {
base = REG_NONE
@@ -2843,7 +2839,7 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
if a.Sym == nil {
ctxt.Diag("bad addr: %v", p)
}
- if p.Mode == 32 && ctxt.Flag_shared != 0 {
+ if p.Mode == 32 && ctxt.Flag_shared {
base = REG_CX
} else {
base = REG_NONE
@@ -2897,7 +2893,7 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
}
if REG_AX <= base && base <= REG_R15 {
- if a.Index == REG_TLS && ctxt.Flag_shared == 0 {
+ if a.Index == REG_TLS && !ctxt.Flag_shared {
rel = obj.Reloc{}
rel.Type = obj.R_TLS_LE
rel.Siz = 4
@@ -3313,7 +3309,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
case Pf2, /* xmm opcode escape */
Pf3:
- ctxt.AsmBuf.Put2(byte(o.prefix), Pm)
+ ctxt.AsmBuf.Put2(o.prefix, Pm)
case Pef3:
ctxt.AsmBuf.Put3(Pe, Pf3, Pm)
@@ -3426,7 +3422,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
asmand(ctxt, p, &p.From, &p.To)
case Zm2_r:
- ctxt.AsmBuf.Put2(byte(op), byte(o.op[z+1]))
+ ctxt.AsmBuf.Put2(byte(op), o.op[z+1])
asmand(ctxt, p, &p.From, &p.To)
case Zm_r_xm:
@@ -3536,7 +3532,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
}
ctxt.AsmBuf.Put1(byte(op))
if p.As == AXABORT {
- ctxt.AsmBuf.Put1(byte(o.op[z+1]))
+ ctxt.AsmBuf.Put1(o.op[z+1])
}
ctxt.AsmBuf.Put1(byte(vaddr(ctxt, p, a, nil)))
@@ -3662,7 +3658,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
if yt.zcase == Zcallcon {
ctxt.AsmBuf.Put1(byte(op))
} else {
- ctxt.AsmBuf.Put1(byte(o.op[z+1]))
+ ctxt.AsmBuf.Put1(o.op[z+1])
}
r = obj.Addrel(ctxt.Cursym)
r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
@@ -3672,7 +3668,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
ctxt.AsmBuf.PutInt32(0)
case Zcallind:
- ctxt.AsmBuf.Put2(byte(op), byte(o.op[z+1]))
+ ctxt.AsmBuf.Put2(byte(op), o.op[z+1])
r = obj.Addrel(ctxt.Cursym)
r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
r.Type = obj.R_ADDR
@@ -3727,7 +3723,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
log.Fatalf("bad code")
}
- ctxt.AsmBuf.Put1(byte(o.op[z+1]))
+ ctxt.AsmBuf.Put1(o.op[z+1])
r = obj.Addrel(ctxt.Cursym)
r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
r.Sym = p.To.Sym
@@ -3767,7 +3763,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
v--
}
- ctxt.AsmBuf.Put1(byte(o.op[z+1]))
+ ctxt.AsmBuf.Put1(o.op[z+1])
ctxt.AsmBuf.PutInt32(int32(v))
}
@@ -3789,7 +3785,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
if yt.zcase == Zbr {
ctxt.AsmBuf.Put1(0x0f)
}
- ctxt.AsmBuf.Put1(byte(o.op[z+1]))
+ ctxt.AsmBuf.Put1(o.op[z+1])
ctxt.AsmBuf.PutInt32(0)
}
@@ -3950,7 +3946,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
case obj.Hlinux,
obj.Hnacl:
- if ctxt.Flag_shared != 0 {
+ if ctxt.Flag_shared {
// Note that this is not generating the same insns as the other cases.
// MOV TLS, R_to
// becomes
@@ -4024,7 +4020,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
log.Fatalf("unknown TLS base location for %s", obj.Headstr(ctxt.Headtype))
case obj.Hlinux:
- if ctxt.Flag_shared == 0 {
+ if !ctxt.Flag_shared {
log.Fatalf("unknown TLS base location for linux without -shared")
}
// Note that this is not generating the same insn as the other cases.
@@ -4457,9 +4453,8 @@ func asmins(ctxt *obj.Link, p *obj.Prog) {
}
n := ctxt.AsmBuf.Len()
- var r *obj.Reloc
for i := len(ctxt.Cursym.R) - 1; i >= 0; i-- {
- r = &ctxt.Cursym.R[i:][0]
+ r := &ctxt.Cursym.R[i]
if int64(r.Off) < p.Pc {
break
}
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 0e8aeca4d3..b638c048e8 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -32,7 +32,7 @@ package x86
import (
"cmd/internal/obj"
- "encoding/binary"
+ "cmd/internal/sys"
"fmt"
"log"
"math"
@@ -49,7 +49,7 @@ func CanUse1InsnTLS(ctxt *obj.Link) bool {
return true
}
- if ctxt.Arch.Regsize == 4 {
+ if ctxt.Arch.RegSize == 4 {
switch ctxt.Headtype {
case obj.Hlinux,
obj.Hnacl,
@@ -66,7 +66,7 @@ func CanUse1InsnTLS(ctxt *obj.Link) bool {
obj.Hwindows:
return false
case obj.Hlinux:
- return ctxt.Flag_shared == 0
+ return !ctxt.Flag_shared
}
return true
@@ -75,7 +75,7 @@ func CanUse1InsnTLS(ctxt *obj.Link) bool {
func progedit(ctxt *obj.Link, p *obj.Prog) {
// Maintain information about code generation mode.
if ctxt.Mode == 0 {
- ctxt.Mode = ctxt.Arch.Regsize * 8
+ ctxt.Mode = ctxt.Arch.RegSize * 8
}
p.Mode = int8(ctxt.Mode)
@@ -207,7 +207,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
}
// Rewrite MOVL/MOVQ $XXX(FP/SP) as LEAL/LEAQ.
- if p.From.Type == obj.TYPE_ADDR && (ctxt.Arch.Thechar == '6' || p.From.Name != obj.NAME_EXTERN && p.From.Name != obj.NAME_STATIC) {
+ if p.From.Type == obj.TYPE_ADDR && (ctxt.Arch.Family == sys.AMD64 || p.From.Name != obj.NAME_EXTERN && p.From.Name != obj.NAME_STATIC) {
switch p.As {
case AMOVL:
p.As = ALEAL
@@ -314,7 +314,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
rewriteToUseGot(ctxt, p)
}
- if ctxt.Flag_shared != 0 && p.Mode == 32 {
+ if ctxt.Flag_shared && p.Mode == 32 {
rewriteToPcrel(ctxt, p)
}
}
@@ -614,7 +614,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
// Make room for to save a base pointer. If autoffset == 0,
// this might do something special like a tail jump to
// another function, so in that case we omit this.
- bpsize = ctxt.Arch.Ptrsize
+ bpsize = ctxt.Arch.PtrSize
autoffset += int32(bpsize)
p.To.Offset += int64(bpsize)
@@ -656,7 +656,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
}
if autoffset != 0 {
- if autoffset%int32(ctxt.Arch.Regsize) != 0 {
+ if autoffset%int32(ctxt.Arch.RegSize) != 0 {
ctxt.Diag("unaligned stack size %d", autoffset)
}
p = obj.Appendp(ctxt, p)
@@ -671,10 +671,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p = obj.Appendp(ctxt, p)
p.As = obj.ANOP
- p.Spadj = int32(-ctxt.Arch.Ptrsize)
+ p.Spadj = int32(-ctxt.Arch.PtrSize)
p = obj.Appendp(ctxt, p)
p.As = obj.ANOP
- p.Spadj = int32(ctxt.Arch.Ptrsize)
+ p.Spadj = int32(ctxt.Arch.PtrSize)
}
deltasp := autoffset
@@ -724,7 +724,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p.As = AMOVQ
p.From.Type = obj.TYPE_MEM
p.From.Reg = REG_CX
- p.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+ p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_BX
if ctxt.Headtype == obj.Hnacl && p.Mode == 64 {
@@ -757,7 +757,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p.As = ALEAQ
p.From.Type = obj.TYPE_MEM
p.From.Reg = REG_SP
- p.From.Offset = int64(autoffset) + int64(ctxt.Arch.Regsize)
+ p.From.Offset = int64(autoffset) + int64(ctxt.Arch.RegSize)
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_DI
if ctxt.Headtype == obj.Hnacl || p.Mode == 32 {
@@ -935,7 +935,7 @@ func indir_cx(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
// Returns last new instruction.
func load_g_cx(ctxt *obj.Link, p *obj.Prog) *obj.Prog {
p.As = AMOVQ
- if ctxt.Arch.Ptrsize == 4 {
+ if ctxt.Arch.PtrSize == 4 {
p.As = AMOVL
}
p.From.Type = obj.TYPE_MEM
@@ -984,9 +984,9 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_SP
indir_cx(ctxt, p, &p.To)
- p.To.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+ p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
if ctxt.Cursym.Cfunc {
- p.To.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+ p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
} else if framesize <= obj.StackBig {
// large stack: SP-framesize <= stackguard-StackSmall
@@ -1006,9 +1006,9 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_AX
indir_cx(ctxt, p, &p.To)
- p.To.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+ p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
if ctxt.Cursym.Cfunc {
- p.To.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+ p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
} else {
// Such a large stack we need to protect against wraparound.
@@ -1030,9 +1030,9 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
p.As = mov
indir_cx(ctxt, p, &p.From)
- p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+ p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
if ctxt.Cursym.Cfunc {
- p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+ p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_SI
@@ -1402,43 +1402,28 @@ var unaryDst = map[obj.As]bool{
}
var Linkamd64 = obj.LinkArch{
- ByteOrder: binary.LittleEndian,
- Name: "amd64",
- Thechar: '6',
+ Arch: sys.ArchAMD64,
Preprocess: preprocess,
Assemble: span6,
Follow: follow,
Progedit: progedit,
UnaryDst: unaryDst,
- Minlc: 1,
- Ptrsize: 8,
- Regsize: 8,
}
var Linkamd64p32 = obj.LinkArch{
- ByteOrder: binary.LittleEndian,
- Name: "amd64p32",
- Thechar: '6',
+ Arch: sys.ArchAMD64P32,
Preprocess: preprocess,
Assemble: span6,
Follow: follow,
Progedit: progedit,
UnaryDst: unaryDst,
- Minlc: 1,
- Ptrsize: 4,
- Regsize: 8,
}
var Link386 = obj.LinkArch{
- ByteOrder: binary.LittleEndian,
- Name: "386",
- Thechar: '8',
+ Arch: sys.Arch386,
Preprocess: preprocess,
Assemble: span6,
Follow: follow,
Progedit: progedit,
UnaryDst: unaryDst,
- Minlc: 1,
- Ptrsize: 4,
- Regsize: 4,
}
diff --git a/src/cmd/internal/obj/x86/obj6_test.go b/src/cmd/internal/obj/x86/obj6_test.go
index a5c80cea3b..fe1f95cc0d 100644
--- a/src/cmd/internal/obj/x86/obj6_test.go
+++ b/src/cmd/internal/obj/x86/obj6_test.go
@@ -76,7 +76,6 @@ func parseTestData(t *testing.T) *ParsedTestData {
}
var spaces_re *regexp.Regexp = regexp.MustCompile("\\s+")
-var marker_re *regexp.Regexp = regexp.MustCompile("MOVQ \\$([0-9]+), AX")
func normalize(s string) string {
return spaces_re.ReplaceAllLiteralString(strings.TrimSpace(s), " ")
diff --git a/src/cmd/internal/objfile/pe.go b/src/cmd/internal/objfile/pe.go
index 1b319941ac..c024762371 100644
--- a/src/cmd/internal/objfile/pe.go
+++ b/src/cmd/internal/objfile/pe.go
@@ -69,8 +69,6 @@ func (f *peFile) symbols() ([]Sym, error) {
text = 0x20
data = 0x40
bss = 0x80
- permX = 0x20000000
- permR = 0x40000000
permW = 0x80000000
)
ch := sect.Characteristics
diff --git a/src/cmd/internal/objfile/plan9obj.go b/src/cmd/internal/objfile/plan9obj.go
index 1d808f77eb..6ee389dc2e 100644
--- a/src/cmd/internal/objfile/plan9obj.go
+++ b/src/cmd/internal/objfile/plan9obj.go
@@ -59,7 +59,7 @@ func (f *plan9File) symbols() ([]Sym, error) {
if !validSymType[s.Type] {
continue
}
- sym := Sym{Addr: s.Value, Name: s.Name, Code: rune(s.Type)}
+ sym := Sym{Addr: s.Value, Name: s.Name, Code: s.Type}
i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
if i < len(addrs) {
sym.Size = int64(addrs[i] - s.Value)
diff --git a/src/cmd/pprof/internal/commands/commands.go b/src/cmd/internal/pprof/commands/commands.go
index 9aeee5762e..5018c02af1 100644
--- a/src/cmd/pprof/internal/commands/commands.go
+++ b/src/cmd/internal/pprof/commands/commands.go
@@ -16,10 +16,10 @@ import (
"strings"
"time"
- "cmd/pprof/internal/plugin"
- "cmd/pprof/internal/report"
- "cmd/pprof/internal/svg"
- "cmd/pprof/internal/tempfile"
+ "cmd/internal/pprof/plugin"
+ "cmd/internal/pprof/report"
+ "cmd/internal/pprof/svg"
+ "cmd/internal/pprof/tempfile"
)
// Commands describes the commands accepted by pprof.
diff --git a/src/cmd/pprof/internal/driver/driver.go b/src/cmd/internal/pprof/driver/driver.go
index 7cd1ddc928..782acfdf32 100644
--- a/src/cmd/pprof/internal/driver/driver.go
+++ b/src/cmd/internal/pprof/driver/driver.go
@@ -21,11 +21,11 @@ import (
"sync"
"time"
- "cmd/pprof/internal/commands"
- "cmd/pprof/internal/plugin"
- "cmd/pprof/internal/profile"
- "cmd/pprof/internal/report"
- "cmd/pprof/internal/tempfile"
+ "cmd/internal/pprof/commands"
+ "cmd/internal/pprof/plugin"
+ "cmd/internal/pprof/profile"
+ "cmd/internal/pprof/report"
+ "cmd/internal/pprof/tempfile"
)
// PProf acquires a profile, and symbolizes it using a profile
diff --git a/src/cmd/pprof/internal/driver/interactive.go b/src/cmd/internal/pprof/driver/interactive.go
index 13009bf7e9..1b08226527 100644
--- a/src/cmd/pprof/internal/driver/interactive.go
+++ b/src/cmd/internal/pprof/driver/interactive.go
@@ -12,9 +12,9 @@ import (
"strconv"
"strings"
- "cmd/pprof/internal/commands"
- "cmd/pprof/internal/plugin"
- "cmd/pprof/internal/profile"
+ "cmd/internal/pprof/commands"
+ "cmd/internal/pprof/plugin"
+ "cmd/internal/pprof/profile"
)
var profileFunctionNames = []string{}
diff --git a/src/cmd/pprof/internal/fetch/fetch.go b/src/cmd/internal/pprof/fetch/fetch.go
index ec4a6383c6..ffd282e74d 100644
--- a/src/cmd/pprof/internal/fetch/fetch.go
+++ b/src/cmd/internal/pprof/fetch/fetch.go
@@ -16,8 +16,8 @@ import (
"strings"
"time"
- "cmd/pprof/internal/plugin"
- "cmd/pprof/internal/profile"
+ "cmd/internal/pprof/plugin"
+ "cmd/internal/pprof/profile"
)
// FetchProfile reads from a data source (network, file) and generates a
diff --git a/src/cmd/pprof/internal/plugin/plugin.go b/src/cmd/internal/pprof/plugin/plugin.go
index a22ec5f3c5..d5025d5517 100644
--- a/src/cmd/pprof/internal/plugin/plugin.go
+++ b/src/cmd/internal/pprof/plugin/plugin.go
@@ -13,7 +13,7 @@ import (
"strings"
"time"
- "cmd/pprof/internal/profile"
+ "cmd/internal/pprof/profile"
)
// A FlagSet creates and parses command-line flags.
diff --git a/src/cmd/pprof/internal/profile/encode.go b/src/cmd/internal/pprof/profile/encode.go
index 6b879a84ac..6b879a84ac 100644
--- a/src/cmd/pprof/internal/profile/encode.go
+++ b/src/cmd/internal/pprof/profile/encode.go
diff --git a/src/cmd/pprof/internal/profile/filter.go b/src/cmd/internal/pprof/profile/filter.go
index 1baa096a49..1baa096a49 100644
--- a/src/cmd/pprof/internal/profile/filter.go
+++ b/src/cmd/internal/pprof/profile/filter.go
diff --git a/src/cmd/pprof/internal/profile/legacy_profile.go b/src/cmd/internal/pprof/profile/legacy_profile.go
index e1f24c4c6d..8ccfe45176 100644
--- a/src/cmd/pprof/internal/profile/legacy_profile.go
+++ b/src/cmd/internal/pprof/profile/legacy_profile.go
@@ -74,7 +74,7 @@ func parseGoCount(b []byte) (*Profile, error) {
if m == nil {
return nil, errUnrecognized
}
- profileType := string(m[1])
+ profileType := m[1]
p := &Profile{
PeriodType: &ValueType{Type: profileType, Unit: "count"},
Period: 1,
@@ -99,22 +99,19 @@ func parseGoCount(b []byte) (*Profile, error) {
if m == nil {
return nil, errMalformed
}
- n, err := strconv.ParseInt(string(m[1]), 0, 64)
+ n, err := strconv.ParseInt(m[1], 0, 64)
if err != nil {
return nil, errMalformed
}
- fields := strings.Fields(string(m[2]))
+ fields := strings.Fields(m[2])
locs := make([]*Location, 0, len(fields))
for _, stk := range fields {
addr, err := strconv.ParseUint(stk, 0, 64)
if err != nil {
return nil, errMalformed
}
- // Adjust all frames by -1 (except the leaf) to land on top of
- // the call instruction.
- if len(locs) > 0 {
- addr--
- }
+ // Adjust all frames by -1 to land on the call instruction.
+ addr--
loc := locations[addr]
if loc == nil {
loc = &Location{
@@ -291,11 +288,8 @@ func ParseTracebacks(b []byte) (*Profile, error) {
if s, addrs := extractHexAddresses(l); len(s) > 0 {
for _, addr := range addrs {
// Addresses from stack traces point to the next instruction after
- // each call. Adjust by -1 to land somewhere on the actual call
- // (except for the leaf, which is not a call).
- if len(sloc) > 0 {
- addr--
- }
+ // each call. Adjust by -1 to land somewhere on the actual call.
+ addr--
loc := locs[addr]
if locs[addr] == nil {
loc = &Location{
@@ -464,7 +458,7 @@ func parseCPUSamples(b []byte, parse func(b []byte) (uint64, []byte), adjust boo
}
p.Sample = append(p.Sample,
&Sample{
- Value: []int64{int64(count), int64(count) * int64(p.Period)},
+ Value: []int64{int64(count), int64(count) * p.Period},
Location: sloc,
})
}
@@ -494,7 +488,7 @@ func parseHeap(b []byte) (p *Profile, err error) {
var period int64
if len(header[6]) > 0 {
- if period, err = strconv.ParseInt(string(header[6]), 10, 64); err != nil {
+ if period, err = strconv.ParseInt(header[6], 10, 64); err != nil {
return nil, errUnrecognized
}
}
@@ -568,13 +562,10 @@ func parseHeap(b []byte) (p *Profile, err error) {
return nil, err
}
var sloc []*Location
- for i, addr := range addrs {
+ for _, addr := range addrs {
// Addresses from stack traces point to the next instruction after
- // each call. Adjust by -1 to land somewhere on the actual call
- // (except for the leaf, which is not a call).
- if i > 0 {
- addr--
- }
+ // each call. Adjust by -1 to land somewhere on the actual call.
+ addr--
loc := locs[addr]
if locs[addr] == nil {
loc = &Location{
@@ -776,13 +767,10 @@ func parseContention(b []byte) (p *Profile, err error) {
return nil, err
}
var sloc []*Location
- for i, addr := range addrs {
+ for _, addr := range addrs {
// Addresses from stack traces point to the next instruction after
- // each call. Adjust by -1 to land somewhere on the actual call
- // (except for the leaf, which is not a call).
- if i > 0 {
- addr--
- }
+ // each call. Adjust by -1 to land somewhere on the actual call.
+ addr--
loc := locs[addr]
if locs[addr] == nil {
loc = &Location{
@@ -919,13 +907,10 @@ func parseThread(b []byte) (*Profile, error) {
}
var sloc []*Location
- for i, addr := range addrs {
+ for _, addr := range addrs {
// Addresses from stack traces point to the next instruction after
- // each call. Adjust by -1 to land somewhere on the actual call
- // (except for the leaf, which is not a call).
- if i > 0 {
- addr--
- }
+ // each call. Adjust by -1 to land somewhere on the actual call.
+ addr--
loc := locs[addr]
if locs[addr] == nil {
loc = &Location{
diff --git a/src/cmd/pprof/internal/profile/profile.go b/src/cmd/internal/pprof/profile/profile.go
index 28e713d7be..28e713d7be 100644
--- a/src/cmd/pprof/internal/profile/profile.go
+++ b/src/cmd/internal/pprof/profile/profile.go
diff --git a/src/cmd/pprof/internal/profile/profile_test.go b/src/cmd/internal/pprof/profile/profile_test.go
index 09b11a456f..09b11a456f 100644
--- a/src/cmd/pprof/internal/profile/profile_test.go
+++ b/src/cmd/internal/pprof/profile/profile_test.go
diff --git a/src/cmd/pprof/internal/profile/proto.go b/src/cmd/internal/pprof/profile/proto.go
index 11d7f9ff9b..11d7f9ff9b 100644
--- a/src/cmd/pprof/internal/profile/proto.go
+++ b/src/cmd/internal/pprof/profile/proto.go
diff --git a/src/cmd/pprof/internal/profile/proto_test.go b/src/cmd/internal/pprof/profile/proto_test.go
index c2613fc375..c2613fc375 100644
--- a/src/cmd/pprof/internal/profile/proto_test.go
+++ b/src/cmd/internal/pprof/profile/proto_test.go
diff --git a/src/cmd/pprof/internal/profile/prune.go b/src/cmd/internal/pprof/profile/prune.go
index 1924fada7a..1924fada7a 100644
--- a/src/cmd/pprof/internal/profile/prune.go
+++ b/src/cmd/internal/pprof/profile/prune.go
diff --git a/src/cmd/pprof/internal/report/report.go b/src/cmd/internal/pprof/report/report.go
index 86bd4a280b..c492b752b9 100644
--- a/src/cmd/pprof/internal/report/report.go
+++ b/src/cmd/internal/pprof/report/report.go
@@ -17,8 +17,8 @@ import (
"strings"
"time"
- "cmd/pprof/internal/plugin"
- "cmd/pprof/internal/profile"
+ "cmd/internal/pprof/plugin"
+ "cmd/internal/pprof/profile"
)
// Generate generates a report as directed by the Report.
diff --git a/src/cmd/pprof/internal/report/source.go b/src/cmd/internal/pprof/report/source.go
index 908be21424..608e4d561d 100644
--- a/src/cmd/pprof/internal/report/source.go
+++ b/src/cmd/internal/pprof/report/source.go
@@ -18,7 +18,7 @@ import (
"strconv"
"strings"
- "cmd/pprof/internal/plugin"
+ "cmd/internal/pprof/plugin"
)
// printSource prints an annotated source listing, include all
@@ -257,7 +257,7 @@ func printHeader(w io.Writer, rpt *Report) {
// printFunctionHeader prints a function header for a weblist report.
func printFunctionHeader(w io.Writer, name, path string, flatSum, cumSum int64, rpt *Report) {
fmt.Fprintf(w, `<h1>%s</h1>%s
-<pre onClick="pprof_toggle_asm()">
+<pre onClick="pprof_toggle_asm(event)">
Total: %10s %10s (flat, cum) %s
`,
template.HTMLEscapeString(name), template.HTMLEscapeString(path),
diff --git a/src/cmd/pprof/internal/report/source_html.go b/src/cmd/internal/pprof/report/source_html.go
index 267fabdc4b..267fabdc4b 100644
--- a/src/cmd/pprof/internal/report/source_html.go
+++ b/src/cmd/internal/pprof/report/source_html.go
diff --git a/src/cmd/pprof/internal/svg/svg.go b/src/cmd/internal/pprof/svg/svg.go
index 04f6ff1870..04f6ff1870 100644
--- a/src/cmd/pprof/internal/svg/svg.go
+++ b/src/cmd/internal/pprof/svg/svg.go
diff --git a/src/cmd/pprof/internal/svg/svgpan.go b/src/cmd/internal/pprof/svg/svgpan.go
index 4975b103e3..4975b103e3 100644
--- a/src/cmd/pprof/internal/svg/svgpan.go
+++ b/src/cmd/internal/pprof/svg/svgpan.go
diff --git a/src/cmd/pprof/internal/symbolizer/symbolizer.go b/src/cmd/internal/pprof/symbolizer/symbolizer.go
index 86de5640d2..bc22800530 100644
--- a/src/cmd/pprof/internal/symbolizer/symbolizer.go
+++ b/src/cmd/internal/pprof/symbolizer/symbolizer.go
@@ -13,8 +13,8 @@ import (
"path/filepath"
"strings"
- "cmd/pprof/internal/plugin"
- "cmd/pprof/internal/profile"
+ "cmd/internal/pprof/plugin"
+ "cmd/internal/pprof/profile"
)
// Symbolize adds symbol and line number information to all locations
diff --git a/src/cmd/pprof/internal/symbolz/symbolz.go b/src/cmd/internal/pprof/symbolz/symbolz.go
index 15b3b6df26..2f2850afeb 100644
--- a/src/cmd/pprof/internal/symbolz/symbolz.go
+++ b/src/cmd/internal/pprof/symbolz/symbolz.go
@@ -15,7 +15,7 @@ import (
"strconv"
"strings"
- "cmd/pprof/internal/profile"
+ "cmd/internal/pprof/profile"
)
var (
diff --git a/src/cmd/pprof/internal/tempfile/tempfile.go b/src/cmd/internal/pprof/tempfile/tempfile.go
index 31c117690a..31c117690a 100644
--- a/src/cmd/pprof/internal/tempfile/tempfile.go
+++ b/src/cmd/internal/pprof/tempfile/tempfile.go
diff --git a/src/cmd/internal/sys/arch.go b/src/cmd/internal/sys/arch.go
new file mode 100644
index 0000000000..18accdeb0c
--- /dev/null
+++ b/src/cmd/internal/sys/arch.go
@@ -0,0 +1,148 @@
+// Copyright 2016 The Go 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 sys
+
+import "encoding/binary"
+
+// ArchFamily represents a family of one or more related architectures.
+// For example, amd64 and amd64p32 are both members of the AMD64 family,
+// and ppc64 and ppc64le are both members of the PPC64 family.
+type ArchFamily byte
+
+const (
+ AMD64 ArchFamily = iota
+ ARM
+ ARM64
+ I386
+ MIPS64
+ PPC64
+ S390X
+)
+
+// Arch represents an individual architecture.
+type Arch struct {
+ Name string
+ Family ArchFamily
+
+ ByteOrder binary.ByteOrder
+
+ IntSize int
+ PtrSize int
+ RegSize int
+
+ // MinLC is the minimum length of an instruction code.
+ MinLC int
+}
+
+// InFamily reports whether a is a member of any of the specified
+// architecture families.
+func (a *Arch) InFamily(xs ...ArchFamily) bool {
+ for _, x := range xs {
+ if a.Family == x {
+ return true
+ }
+ }
+ return false
+}
+
+var Arch386 = &Arch{
+ Name: "386",
+ Family: I386,
+ ByteOrder: binary.LittleEndian,
+ IntSize: 4,
+ PtrSize: 4,
+ RegSize: 4,
+ MinLC: 1,
+}
+
+var ArchAMD64 = &Arch{
+ Name: "amd64",
+ Family: AMD64,
+ ByteOrder: binary.LittleEndian,
+ IntSize: 8,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 1,
+}
+
+var ArchAMD64P32 = &Arch{
+ Name: "amd64p32",
+ Family: AMD64,
+ ByteOrder: binary.LittleEndian,
+ IntSize: 4,
+ PtrSize: 4,
+ RegSize: 8,
+ MinLC: 1,
+}
+
+var ArchARM = &Arch{
+ Name: "arm",
+ Family: ARM,
+ ByteOrder: binary.LittleEndian,
+ IntSize: 4,
+ PtrSize: 4,
+ RegSize: 4,
+ MinLC: 4,
+}
+
+var ArchARM64 = &Arch{
+ Name: "arm64",
+ Family: ARM64,
+ ByteOrder: binary.LittleEndian,
+ IntSize: 8,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 4,
+}
+
+var ArchMIPS64 = &Arch{
+ Name: "mips64",
+ Family: MIPS64,
+ ByteOrder: binary.BigEndian,
+ IntSize: 8,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 4,
+}
+
+var ArchMIPS64LE = &Arch{
+ Name: "mips64le",
+ Family: MIPS64,
+ ByteOrder: binary.LittleEndian,
+ IntSize: 8,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 4,
+}
+
+var ArchPPC64 = &Arch{
+ Name: "ppc64",
+ Family: PPC64,
+ ByteOrder: binary.BigEndian,
+ IntSize: 8,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 4,
+}
+
+var ArchPPC64LE = &Arch{
+ Name: "ppc64le",
+ Family: PPC64,
+ ByteOrder: binary.LittleEndian,
+ IntSize: 8,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 4,
+}
+
+var ArchS390X = &Arch{
+ Name: "s390x",
+ Family: S390X,
+ ByteOrder: binary.BigEndian,
+ IntSize: 8,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 2,
+}
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go
index 6b4d73841b..cc81dc3f50 100644
--- a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go
+++ b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go
@@ -233,9 +233,9 @@ func decodeArg(aop instArg, x uint32) Arg {
typ, count := decodeShift(x)
// ROR #0 here means ROR #0, but decodeShift rewrites to RRX #1.
if typ == RotateRightExt {
- return Reg(Rm)
+ return Rm
}
- return RegShift{Rm, typ, uint8(count)}
+ return RegShift{Rm, typ, count}
case arg_R_shift_R:
Rm := Reg(x & (1<<4 - 1))
@@ -247,9 +247,9 @@ func decodeArg(aop instArg, x uint32) Arg {
Rm := Reg(x & (1<<4 - 1))
typ, count := decodeShift(x)
if typ == ShiftLeft && count == 0 {
- return Reg(Rm)
+ return Rm
}
- return RegShift{Rm, typ, uint8(count)}
+ return RegShift{Rm, typ, count}
case arg_R1_0:
return Reg((x & (1<<4 - 1)))
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go
index e4122c1e6d..9b3597300e 100644
--- a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go
+++ b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go
@@ -1041,7 +1041,7 @@ Decode:
case xArgMoffs8, xArgMoffs16, xArgMoffs32, xArgMoffs64:
// TODO(rsc): Can address be 64 bits?
- mem = Mem{Disp: int64(immc)}
+ mem = Mem{Disp: immc}
if segIndex >= 0 {
mem.Segment = prefixToSegment(inst.Prefix[segIndex])
inst.Prefix[segIndex] |= PrefixImplicit
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index d809f6e8ed..cdb0354579 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -86,12 +86,7 @@ func gentext() {
Addcall(ld.Ctxt, initfunc, addmoduledata)
// c: c3 retq
o(0xc3)
- if ld.Ctxt.Etextp != nil {
- ld.Ctxt.Etextp.Next = initfunc
- } else {
- ld.Ctxt.Textp = initfunc
- }
- ld.Ctxt.Etextp = initfunc
+ ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
initarray_entry.Attr |= ld.AttrReachable
initarray_entry.Attr |= ld.AttrLocal
@@ -99,12 +94,6 @@ func gentext() {
ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
}
-func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) {
- ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
- ld.Adduint64(ld.Ctxt, rela, ld.R_X86_64_RELATIVE)
- ld.Addaddrplus(ld.Ctxt, rela, r.Sym, r.Add) // Addend
-}
-
func adddynrel(s *ld.LSym, r *ld.Reloc) {
targ := r.Sym
ld.Ctxt.Cursym = s
@@ -285,7 +274,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
return
}
- if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.Thearch.Ptrsize) && r.Off == 0 {
+ if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 {
// Mach-O relocations are a royal pain to lay out.
// They use a compact stateful bytecode representation
// that is too much bother to deal with.
@@ -611,12 +600,12 @@ func addgotsym(s *ld.LSym) {
func asmb() {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
}
ld.Bso.Flush()
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f codeblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f codeblk\n", obj.Cputime())
}
ld.Bso.Flush()
@@ -634,7 +623,7 @@ func asmb() {
if ld.Segrodata.Filelen > 0 {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
}
ld.Bso.Flush()
@@ -643,26 +632,18 @@ func asmb() {
}
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
}
ld.Bso.Flush()
ld.Cseek(int64(ld.Segdata.Fileoff))
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.Cseek(int64(ld.Segdwarf.Fileoff))
+ ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+
machlink := int64(0)
if ld.HEADTYPE == obj.Hdarwin {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
- }
-
- dwarfoff := ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))
- ld.Cseek(dwarfoff)
-
- ld.Segdwarf.Fileoff = uint64(ld.Cpos())
- ld.Dwarfemitdebugsections()
- ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
-
machlink = ld.Domacholink()
}
@@ -696,7 +677,7 @@ func asmb() {
symo := int64(0)
if ld.Debug['s'] == 0 {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
}
ld.Bso.Flush()
switch ld.HEADTYPE {
@@ -715,11 +696,11 @@ func asmb() {
obj.Hdragonfly,
obj.Hsolaris,
obj.Hnacl:
- symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+ symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
symo = ld.Rnd(symo, int64(ld.INITRND))
case obj.Hwindows:
- symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+ symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
symo = ld.Rnd(symo, ld.PEFILEALIGN)
}
@@ -733,11 +714,9 @@ func asmb() {
ld.Cwrite(ld.Elfstrdat)
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime())
}
- ld.Dwarfemitdebugsections()
-
if ld.Linkmode == ld.LinkExternal {
ld.Elfemitreloc()
}
@@ -751,7 +730,7 @@ func asmb() {
if sym != nil {
ld.Lcsize = int32(len(sym.P))
for i := 0; int32(i) < ld.Lcsize; i++ {
- ld.Cput(uint8(sym.P[i]))
+ ld.Cput(sym.P[i])
}
ld.Cflush()
@@ -759,11 +738,9 @@ func asmb() {
case obj.Hwindows:
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime())
}
- ld.Dwarfemitdebugsections()
-
case obj.Hdarwin:
if ld.Linkmode == ld.LinkExternal {
ld.Machoemitreloc()
@@ -772,7 +749,7 @@ func asmb() {
}
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f headr\n", obj.Cputime())
}
ld.Bso.Flush()
ld.Cseek(0)
diff --git a/src/cmd/link/internal/amd64/l.go b/src/cmd/link/internal/amd64/l.go
index 4ec8610afb..2fbc8adc51 100644
--- a/src/cmd/link/internal/amd64/l.go
+++ b/src/cmd/link/internal/amd64/l.go
@@ -31,16 +31,11 @@
package amd64
const (
- thechar = '6'
MaxAlign = 32 // max data alignment
MinAlign = 1 // min data alignment
FuncAlign = 16
)
-const (
- MINLC = 1
-)
-
/* Used by ../internal/ld/dwarf.go */
const (
DWARFREGSP = 7
diff --git a/src/cmd/link/internal/amd64/obj.go b/src/cmd/link/internal/amd64/obj.go
index f9e13f2e18..860f588224 100644
--- a/src/cmd/link/internal/amd64/obj.go
+++ b/src/cmd/link/internal/amd64/obj.go
@@ -32,6 +32,7 @@ package amd64
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
"log"
@@ -45,20 +46,14 @@ func Main() {
}
func linkarchinit() {
- ld.Thestring = "amd64"
- ld.Thelinkarch = &ld.Linkamd64
+ ld.SysArch = sys.ArchAMD64
if obj.Getgoarch() == "amd64p32" {
- ld.Thelinkarch = &ld.Linkamd64p32
+ ld.SysArch = sys.ArchAMD64P32
}
- ld.Thearch.Thechar = thechar
- ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
- ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
- ld.Thearch.Regsize = ld.Thelinkarch.Regsize
ld.Thearch.Funcalign = FuncAlign
ld.Thearch.Maxalign = MaxAlign
ld.Thearch.Minalign = MinAlign
- ld.Thearch.Minlc = MINLC
ld.Thearch.Dwarfregsp = DWARFREGSP
ld.Thearch.Dwarfreglr = DWARFREGLR
diff --git a/src/cmd/link/internal/amd64/z.go b/src/cmd/link/internal/amd64/z.go
deleted file mode 100644
index f70035b9e3..0000000000
--- a/src/cmd/link/internal/amd64/z.go
+++ /dev/null
@@ -1 +0,0 @@
-package amd64
diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go
index bb90cf77b6..aafdd9bc3d 100644
--- a/src/cmd/link/internal/arm/asm.go
+++ b/src/cmd/link/internal/arm/asm.go
@@ -95,12 +95,7 @@ func gentext() {
rel.Type = obj.R_PCREL
rel.Add = 4
- if ld.Ctxt.Etextp != nil {
- ld.Ctxt.Etextp.Next = initfunc
- } else {
- ld.Ctxt.Textp = initfunc
- }
- ld.Ctxt.Etextp = initfunc
+ ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
initarray_entry.Attr |= ld.AttrReachable
initarray_entry.Attr |= ld.AttrLocal
@@ -114,11 +109,6 @@ func braddoff(a int32, b int32) int32 {
return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b))
}
-func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
- ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
- ld.Adduint32(ld.Ctxt, rel, ld.R_ARM_RELATIVE)
-}
-
func adddynrel(s *ld.LSym, r *ld.Reloc) {
targ := r.Sym
ld.Ctxt.Cursym = s
@@ -340,6 +330,36 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
rs := r.Xsym
+ if r.Type == obj.R_PCREL {
+ if rs.Type == obj.SHOSTOBJ {
+ ld.Diag("pc-relative relocation of external symbol is not supported")
+ return -1
+ }
+ if r.Siz != 4 {
+ return -1
+ }
+
+ // emit a pair of "scattered" relocations that
+ // resolve to the difference of section addresses of
+ // the symbol and the instruction
+ // this value is added to the field being relocated
+ o1 := uint32(sectoff)
+ o1 |= 1 << 31 // scattered bit
+ o1 |= ld.MACHO_ARM_RELOC_SECTDIFF << 24
+ o1 |= 2 << 28 // size = 4
+
+ o2 := uint32(0)
+ o2 |= 1 << 31 // scattered bit
+ o2 |= ld.MACHO_ARM_RELOC_PAIR << 24
+ o2 |= 2 << 28 // size = 4
+
+ ld.Thearch.Lput(o1)
+ ld.Thearch.Lput(uint32(ld.Symaddr(rs)))
+ ld.Thearch.Lput(o2)
+ ld.Thearch.Lput(uint32(ld.Ctxt.Cursym.Value + int64(r.Off)))
+ return 0
+ }
+
if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_CALLARM {
if rs.Dynid < 0 {
ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
@@ -563,7 +583,7 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) {
func asmb() {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
}
ld.Bso.Flush()
@@ -581,7 +601,7 @@ func asmb() {
if ld.Segrodata.Filelen > 0 {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
}
ld.Bso.Flush()
@@ -590,26 +610,18 @@ func asmb() {
}
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
}
ld.Bso.Flush()
ld.Cseek(int64(ld.Segdata.Fileoff))
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.Cseek(int64(ld.Segdwarf.Fileoff))
+ ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+
machlink := uint32(0)
if ld.HEADTYPE == obj.Hdarwin {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
- }
-
- 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
-
machlink = uint32(ld.Domacholink())
}
@@ -621,13 +633,13 @@ func asmb() {
if ld.Debug['s'] == 0 {
// TODO: rationalize
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
}
ld.Bso.Flush()
switch ld.HEADTYPE {
default:
if ld.Iself {
- symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+ symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
}
@@ -643,17 +655,12 @@ func asmb() {
default:
if ld.Iself {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime())
}
ld.Asmelfsym()
ld.Cflush()
ld.Cwrite(ld.Elfstrdat)
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
- }
- ld.Dwarfemitdebugsections()
-
if ld.Linkmode == ld.LinkExternal {
ld.Elfemitreloc()
}
@@ -667,7 +674,7 @@ func asmb() {
if sym != nil {
ld.Lcsize = int32(len(sym.P))
for i := 0; int32(i) < ld.Lcsize; i++ {
- ld.Cput(uint8(sym.P[i]))
+ ld.Cput(sym.P[i])
}
ld.Cflush()
@@ -682,7 +689,7 @@ func asmb() {
ld.Ctxt.Cursym = nil
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime())
}
ld.Bso.Flush()
ld.Cseek(0)
diff --git a/src/cmd/link/internal/arm/l.go b/src/cmd/link/internal/arm/l.go
index 58aecc4b64..2b73a7b172 100644
--- a/src/cmd/link/internal/arm/l.go
+++ b/src/cmd/link/internal/arm/l.go
@@ -63,11 +63,9 @@ package arm
// THE SOFTWARE.
const (
- thechar = '5'
MaxAlign = 8 // max data alignment
MinAlign = 1 // min data alignment
FuncAlign = 4 // single-instruction alignment
- MINLC = 4
)
/* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/arm/obj.go b/src/cmd/link/internal/arm/obj.go
index bcd61fda9b..9125a1fa32 100644
--- a/src/cmd/link/internal/arm/obj.go
+++ b/src/cmd/link/internal/arm/obj.go
@@ -32,6 +32,7 @@ package arm
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
"log"
@@ -45,17 +46,11 @@ func Main() {
}
func linkarchinit() {
- ld.Thestring = "arm"
- ld.Thelinkarch = &ld.Linkarm
+ ld.SysArch = sys.ArchARM
- ld.Thearch.Thechar = thechar
- ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
- ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
- ld.Thearch.Regsize = ld.Thelinkarch.Regsize
ld.Thearch.Funcalign = FuncAlign
ld.Thearch.Maxalign = MaxAlign
ld.Thearch.Minalign = MinAlign
- ld.Thearch.Minlc = MINLC
ld.Thearch.Dwarfregsp = DWARFREGSP
ld.Thearch.Dwarfreglr = DWARFREGLR
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 250f0afb16..97803c9d03 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -78,12 +78,7 @@ func gentext() {
rel.Sym = ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
rel.Type = obj.R_CALLARM64 // Really should be R_AARCH64_JUMP26 but doesn't seem to make any difference
- if ld.Ctxt.Etextp != nil {
- ld.Ctxt.Etextp.Next = initfunc
- } else {
- ld.Ctxt.Textp = initfunc
- }
- ld.Ctxt.Etextp = initfunc
+ ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
initarray_entry.Attr |= ld.AttrReachable
initarray_entry.Attr |= ld.AttrLocal
@@ -91,10 +86,6 @@ func gentext() {
ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
}
-func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
- log.Fatalf("adddynrela not implemented")
-}
-
func adddynrel(s *ld.LSym, r *ld.Reloc) {
log.Fatalf("adddynrel not implemented")
}
@@ -375,7 +366,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
}
// The TCB is two pointers. This is not documented anywhere, but is
// de facto part of the ABI.
- v := r.Sym.Value + int64(2*ld.Thearch.Ptrsize)
+ v := r.Sym.Value + int64(2*ld.SysArch.PtrSize)
if v < 0 || v >= 32678 {
ld.Diag("TLS offset out of range %d", v)
}
@@ -401,7 +392,7 @@ func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
func asmb() {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
}
ld.Bso.Flush()
@@ -419,7 +410,7 @@ func asmb() {
if ld.Segrodata.Filelen > 0 {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
}
ld.Bso.Flush()
@@ -428,26 +419,18 @@ func asmb() {
}
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
}
ld.Bso.Flush()
ld.Cseek(int64(ld.Segdata.Fileoff))
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.Cseek(int64(ld.Segdwarf.Fileoff))
+ ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+
machlink := uint32(0)
if ld.HEADTYPE == obj.Hdarwin {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
- }
-
- 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
-
machlink = uint32(ld.Domacholink())
}
@@ -459,13 +442,13 @@ func asmb() {
if ld.Debug['s'] == 0 {
// TODO: rationalize
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
}
ld.Bso.Flush()
switch ld.HEADTYPE {
default:
if ld.Iself {
- symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+ symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
}
@@ -481,17 +464,12 @@ func asmb() {
default:
if ld.Iself {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime())
}
ld.Asmelfsym()
ld.Cflush()
ld.Cwrite(ld.Elfstrdat)
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
- }
- ld.Dwarfemitdebugsections()
-
if ld.Linkmode == ld.LinkExternal {
ld.Elfemitreloc()
}
@@ -505,7 +483,7 @@ func asmb() {
if sym != nil {
ld.Lcsize = int32(len(sym.P))
for i := 0; int32(i) < ld.Lcsize; i++ {
- ld.Cput(uint8(sym.P[i]))
+ ld.Cput(sym.P[i])
}
ld.Cflush()
@@ -520,7 +498,7 @@ func asmb() {
ld.Ctxt.Cursym = nil
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime())
}
ld.Bso.Flush()
ld.Cseek(0)
diff --git a/src/cmd/link/internal/arm64/l.go b/src/cmd/link/internal/arm64/l.go
index b9b7ea50e3..67ad5c977f 100644
--- a/src/cmd/link/internal/arm64/l.go
+++ b/src/cmd/link/internal/arm64/l.go
@@ -62,11 +62,9 @@ package arm64
// THE SOFTWARE.
const (
- thechar = '7'
MaxAlign = 32 // max data alignment
MinAlign = 1 // min data alignment
FuncAlign = 8
- MINLC = 4
)
/* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go
index 693e106ff1..1169e79a58 100644
--- a/src/cmd/link/internal/arm64/obj.go
+++ b/src/cmd/link/internal/arm64/obj.go
@@ -32,6 +32,7 @@ package arm64
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
"log"
@@ -45,17 +46,11 @@ func Main() {
}
func linkarchinit() {
- ld.Thestring = obj.Getgoarch()
- ld.Thelinkarch = &ld.Linkarm64
+ ld.SysArch = sys.ArchARM64
- ld.Thearch.Thechar = thechar
- ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
- ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
- ld.Thearch.Regsize = ld.Thelinkarch.Regsize
ld.Thearch.Funcalign = FuncAlign
ld.Thearch.Maxalign = MaxAlign
ld.Thearch.Minalign = MinAlign
- ld.Thearch.Minlc = MINLC
ld.Thearch.Dwarfregsp = DWARFREGSP
ld.Thearch.Dwarfreglr = DWARFREGLR
diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go
index d07756071d..323dfbefc5 100644
--- a/src/cmd/link/internal/ld/ar.go
+++ b/src/cmd/link/internal/ld/ar.go
@@ -31,9 +31,11 @@
package ld
import (
+ "cmd/internal/bio"
"cmd/internal/obj"
"encoding/binary"
"fmt"
+ "io"
"os"
)
@@ -62,26 +64,26 @@ type ArHdr struct {
// define them. This is used for the compiler support library
// libgcc.a.
func hostArchive(name string) {
- f, err := obj.Bopenr(name)
+ f, err := bio.Open(name)
if err != nil {
if os.IsNotExist(err) {
// It's OK if we don't have a libgcc file at all.
if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "skipping libgcc file: %v\n", err)
+ fmt.Fprintf(Bso, "skipping libgcc file: %v\n", err)
}
return
}
Exitf("cannot open file %s: %v", name, err)
}
- defer obj.Bterm(f)
+ defer f.Close()
- magbuf := make([]byte, len(ARMAG))
- if obj.Bread(f, magbuf) != len(magbuf) {
+ var magbuf [len(ARMAG)]byte
+ if _, err := io.ReadFull(f, magbuf[:]); err != nil {
Exitf("file %s too short", name)
}
var arhdr ArHdr
- l := nextar(f, obj.Boffset(f), &arhdr)
+ l := nextar(f, f.Offset(), &arhdr)
if l <= 0 {
Exitf("%s missing armap", name)
}
@@ -117,7 +119,7 @@ func hostArchive(name string) {
l = atolwhex(arhdr.size)
h := ldobj(f, "libgcc", l, pname, name, ArchiveObj)
- obj.Bseek(f, h.off, 0)
+ f.Seek(h.off, 0)
h.ld(f, h.pkg, h.length, h.pn)
}
@@ -130,16 +132,15 @@ func hostArchive(name string) {
type archiveMap map[string]uint64
// readArmap reads the archive symbol map.
-func readArmap(filename string, f *obj.Biobuf, arhdr ArHdr) archiveMap {
+func readArmap(filename string, f *bio.Reader, arhdr ArHdr) archiveMap {
is64 := arhdr.name == "/SYM64/"
wordSize := 4
if is64 {
wordSize = 8
}
- l := atolwhex(arhdr.size)
- contents := make([]byte, l)
- if obj.Bread(f, contents) != int(l) {
+ contents := make([]byte, atolwhex(arhdr.size))
+ if _, err := io.ReadFull(f, contents); err != nil {
Exitf("short read from %s", filename)
}
diff --git a/src/cmd/link/internal/ld/arch.go b/src/cmd/link/internal/ld/arch.go
deleted file mode 100644
index d28f37fa02..0000000000
--- a/src/cmd/link/internal/ld/arch.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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 "encoding/binary"
-
-var Linkarm = LinkArch{
- ByteOrder: binary.LittleEndian,
- Name: "arm",
- Thechar: '5',
- Minlc: 4,
- Ptrsize: 4,
- Regsize: 4,
-}
-
-var Linkarm64 = LinkArch{
- ByteOrder: binary.LittleEndian,
- Name: "arm64",
- Thechar: '7',
- Minlc: 4,
- Ptrsize: 8,
- Regsize: 8,
-}
-
-var Linkamd64 = LinkArch{
- ByteOrder: binary.LittleEndian,
- Name: "amd64",
- Thechar: '6',
- Minlc: 1,
- Ptrsize: 8,
- Regsize: 8,
-}
-
-var Linkamd64p32 = LinkArch{
- ByteOrder: binary.LittleEndian,
- Name: "amd64p32",
- Thechar: '6',
- Minlc: 1,
- Ptrsize: 4,
- Regsize: 8,
-}
-
-var Link386 = LinkArch{
- ByteOrder: binary.LittleEndian,
- Name: "386",
- Thechar: '8',
- Minlc: 1,
- Ptrsize: 4,
- Regsize: 4,
-}
-
-var Linkppc64 = LinkArch{
- ByteOrder: binary.BigEndian,
- Name: "ppc64",
- Thechar: '9',
- Minlc: 4,
- Ptrsize: 8,
- Regsize: 8,
-}
-
-var Linkppc64le = LinkArch{
- ByteOrder: binary.LittleEndian,
- Name: "ppc64le",
- Thechar: '9',
- Minlc: 4,
- Ptrsize: 8,
- Regsize: 8,
-}
-
-var Linkmips64 = LinkArch{
- ByteOrder: binary.BigEndian,
- Name: "mips64",
- Thechar: '0',
- Minlc: 4,
- Ptrsize: 8,
- Regsize: 8,
-}
-
-var Linkmips64le = LinkArch{
- ByteOrder: binary.LittleEndian,
- Name: "mips64le",
- Thechar: '0',
- Minlc: 4,
- Ptrsize: 8,
- Regsize: 8,
-}
-
-var Links390x = LinkArch{
- ByteOrder: binary.BigEndian,
- Name: "s390x",
- Thechar: 'z',
- Minlc: 2,
- Ptrsize: 8,
- Regsize: 8,
-}
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index fe74cc9208..8964757846 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -34,12 +34,14 @@ package ld
import (
"cmd/internal/gcprog"
"cmd/internal/obj"
+ "cmd/internal/sys"
"fmt"
"log"
"os"
"sort"
"strconv"
"strings"
+ "sync"
)
func Symgrow(ctxt *Link, s *LSym, siz int64) {
@@ -49,8 +51,9 @@ func Symgrow(ctxt *Link, s *LSym, siz int64) {
if int64(len(s.P)) >= siz {
return
}
- for cap(s.P) < int(siz) {
- s.P = append(s.P[:len(s.P)], 0)
+ if cap(s.P) < int(siz) {
+ p := make([]byte, 2*(siz+1))
+ s.P = append(p[:0], s.P...)
}
s.P = s.P[:siz]
}
@@ -78,12 +81,23 @@ func setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 {
case 4:
ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(v))
case 8:
- ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(v))
+ ctxt.Arch.ByteOrder.PutUint64(s.P[off:], v)
}
return off + wid
}
+func Addbytes(ctxt *Link, s *LSym, bytes []byte) int64 {
+ if s.Type == 0 {
+ s.Type = obj.SDATA
+ }
+ s.Attr |= AttrReachable
+ s.P = append(s.P, bytes...)
+ s.Size = int64(len(s.P))
+
+ return s.Size
+}
+
func adduintxx(ctxt *Link, s *LSym, v uint64, wid int) int64 {
off := s.Size
setuintxx(ctxt, s, off, v, int64(wid))
@@ -91,7 +105,15 @@ func adduintxx(ctxt *Link, s *LSym, v uint64, wid int) int64 {
}
func Adduint8(ctxt *Link, s *LSym, v uint8) int64 {
- return adduintxx(ctxt, s, uint64(v), 1)
+ off := s.Size
+ if s.Type == 0 {
+ s.Type = obj.SDATA
+ }
+ s.Attr |= AttrReachable
+ s.Size++
+ s.P = append(s.P, v)
+
+ return off
}
func Adduint16(ctxt *Link, s *LSym, v uint16) int64 {
@@ -107,7 +129,7 @@ func Adduint64(ctxt *Link, s *LSym, v uint64) int64 {
}
func adduint(ctxt *Link, s *LSym, v uint64) int64 {
- return adduintxx(ctxt, s, v, Thearch.Intsize)
+ return adduintxx(ctxt, s, v, SysArch.IntSize)
}
func setuint8(ctxt *Link, s *LSym, r int64, v uint8) int64 {
@@ -124,12 +146,12 @@ func Addaddrplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
}
s.Attr |= AttrReachable
i := s.Size
- s.Size += int64(ctxt.Arch.Ptrsize)
+ s.Size += int64(ctxt.Arch.PtrSize)
Symgrow(ctxt, s, s.Size)
r := Addrel(s)
r.Sym = t
r.Off = int32(i)
- r.Siz = uint8(ctxt.Arch.Ptrsize)
+ r.Siz = uint8(ctxt.Arch.PtrSize)
r.Type = obj.R_ADDR
r.Add = add
return i + int64(r.Siz)
@@ -149,7 +171,7 @@ func Addpcrelplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
r.Add = add
r.Type = obj.R_PCREL
r.Siz = 4
- if Thearch.Thechar == 'z' {
+ if SysArch.Family == sys.S390X {
r.Variant = RV_390_DBL
}
return i + int64(r.Siz)
@@ -164,15 +186,15 @@ func setaddrplus(ctxt *Link, s *LSym, off int64, t *LSym, add int64) int64 {
s.Type = obj.SDATA
}
s.Attr |= AttrReachable
- if off+int64(ctxt.Arch.Ptrsize) > s.Size {
- s.Size = off + int64(ctxt.Arch.Ptrsize)
+ if off+int64(ctxt.Arch.PtrSize) > s.Size {
+ s.Size = off + int64(ctxt.Arch.PtrSize)
Symgrow(ctxt, s, s.Size)
}
r := Addrel(s)
r.Sym = t
r.Off = int32(off)
- r.Siz = uint8(ctxt.Arch.Ptrsize)
+ r.Siz = uint8(ctxt.Arch.PtrSize)
r.Type = obj.R_ADDR
r.Add = add
return off + int64(r.Siz)
@@ -188,12 +210,12 @@ func addsize(ctxt *Link, s *LSym, t *LSym) int64 {
}
s.Attr |= AttrReachable
i := s.Size
- s.Size += int64(ctxt.Arch.Ptrsize)
+ s.Size += int64(ctxt.Arch.PtrSize)
Symgrow(ctxt, s, s.Size)
r := Addrel(s)
r.Sym = t
r.Off = int32(i)
- r.Siz = uint8(ctxt.Arch.Ptrsize)
+ r.Siz = uint8(ctxt.Arch.PtrSize)
r.Type = obj.R_SIZE
return i + int64(r.Siz)
}
@@ -221,10 +243,6 @@ func addaddrplus4(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
* Used for the data block.
*/
-func listnextp(s *LSym) **LSym {
- return &s.Next
-}
-
func listsubp(s *LSym) **LSym {
return &s.Sub
}
@@ -342,7 +360,7 @@ func relocsym(s *LSym) {
// We need to be able to reference dynimport symbols when linking against
// shared libraries, and Solaris needs it always
if HEADTYPE != obj.Hsolaris && r.Sym != nil && r.Sym.Type == obj.SDYNIMPORT && !DynlinkingGo() {
- if !(Thearch.Thechar == '9' && Linkmode == LinkExternal && r.Sym.Name == ".TOC.") {
+ if !(SysArch.Family == sys.PPC64 && Linkmode == LinkExternal && r.Sym.Name == ".TOC.") {
Diag("unhandled relocation for %s (type %d rtype %d)", r.Sym.Name, r.Sym.Type, r.Type)
}
}
@@ -351,7 +369,7 @@ func relocsym(s *LSym) {
}
// TODO(mundaym): remove this special case - see issue 14218.
- if Thearch.Thechar == 'z' {
+ if SysArch.Family == sys.S390X {
switch r.Type {
case obj.R_PCRELDBL:
r.Type = obj.R_PCREL
@@ -380,7 +398,7 @@ func relocsym(s *LSym) {
}
case obj.R_TLS_LE:
- isAndroidX86 := goos == "android" && (Thearch.Thechar == '6' || Thearch.Thechar == '8')
+ isAndroidX86 := goos == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 {
r.Done = 0
@@ -390,13 +408,13 @@ func relocsym(s *LSym) {
r.Xsym = r.Sym
r.Xadd = r.Add
o = 0
- if Thearch.Thechar != '6' {
+ if SysArch.Family != sys.AMD64 {
o = r.Add
}
break
}
- if Iself && Thearch.Thechar == '5' {
+ if Iself && SysArch.Family == sys.ARM {
// On ELF ARM, the thread pointer is 8 bytes before
// the start of the thread-local data block, so add 8
// to the actual TLS offset (r->sym->value).
@@ -414,7 +432,7 @@ func relocsym(s *LSym) {
}
case obj.R_TLS_IE:
- isAndroidX86 := goos == "android" && (Thearch.Thechar == '6' || Thearch.Thechar == '8')
+ isAndroidX86 := goos == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 {
r.Done = 0
@@ -424,7 +442,7 @@ func relocsym(s *LSym) {
r.Xsym = r.Sym
r.Xadd = r.Add
o = 0
- if Thearch.Thechar != '6' {
+ if SysArch.Family != sys.AMD64 {
o = r.Add
}
break
@@ -451,7 +469,7 @@ func relocsym(s *LSym) {
o = r.Xadd
if Iself {
- if Thearch.Thechar == '6' {
+ if SysArch.Family == sys.AMD64 {
o = 0
}
} else if HEADTYPE == obj.Hdarwin {
@@ -461,10 +479,10 @@ func relocsym(s *LSym) {
// The workaround is that on arm64 don't ever add symaddr to o and always use
// extern relocation by requiring rs->dynid >= 0.
if rs.Type != obj.SHOSTOBJ {
- if Thearch.Thechar == '7' && rs.Dynid < 0 {
+ if SysArch.Family == sys.ARM64 && rs.Dynid < 0 {
Diag("R_ADDR reloc to %s+%d is not supported on darwin/arm64", rs.Name, o)
}
- if Thearch.Thechar != '7' {
+ if SysArch.Family != sys.ARM64 {
o += Symaddr(rs)
}
}
@@ -484,11 +502,33 @@ func relocsym(s *LSym) {
// fail at runtime. See https://golang.org/issue/7980.
// Instead of special casing only amd64, we treat this as an error on all
// 64-bit architectures so as to be future-proof.
- if int32(o) < 0 && Thearch.Ptrsize > 4 && siz == 4 {
+ if int32(o) < 0 && SysArch.PtrSize > 4 && siz == 4 {
Diag("non-pc-relative relocation address is too big: %#x (%#x + %#x)", uint64(o), Symaddr(r.Sym), r.Add)
errorexit()
}
+ case obj.R_DWARFREF:
+ if r.Sym.Sect == nil {
+ Diag("missing DWARF section: %s from %s", r.Sym.Name, s.Name)
+ }
+ if Linkmode == LinkExternal {
+ r.Done = 0
+ r.Type = obj.R_ADDR
+
+ r.Xsym = Linkrlookup(Ctxt, r.Sym.Sect.Name, 0)
+ r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
+ o = r.Xadd
+ rs = r.Xsym
+ if Iself && SysArch.Family == sys.AMD64 {
+ o = 0
+ }
+ break
+ }
+ o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
+
+ case obj.R_ADDROFF:
+ o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add
+
// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
case obj.R_CALL, obj.R_GOTPCREL, obj.R_PCREL:
if Linkmode == LinkExternal && r.Sym != nil && r.Sym.Type != obj.SCONST && (r.Sym.Sect != Ctxt.Cursym.Sect || r.Type == obj.R_GOTPCREL) {
@@ -511,7 +551,7 @@ func relocsym(s *LSym) {
o = r.Xadd
if Iself {
- if Thearch.Thechar == '6' {
+ if SysArch.Family == sys.AMD64 {
o = 0
}
} else if HEADTYPE == obj.Hdarwin {
@@ -520,10 +560,13 @@ func relocsym(s *LSym) {
o += int64(uint64(Symaddr(rs)) - rs.Sect.Vaddr)
}
o -= int64(r.Off) // relative to section offset, not symbol
+ } else if SysArch.Family == sys.ARM {
+ // see ../arm/asm.go:/machoreloc1
+ o += Symaddr(rs) - int64(Ctxt.Cursym.Value) - int64(r.Off)
} else {
o += int64(r.Siz)
}
- } else if HEADTYPE == obj.Hwindows && Thearch.Thechar == '6' { // only amd64 needs PCREL
+ } else if HEADTYPE == obj.Hwindows && SysArch.Family == sys.AMD64 { // only amd64 needs PCREL
// PE/COFF's PC32 relocation uses the address after the relocated
// bytes as the base. Compensate by skewing the addend.
o += int64(r.Siz)
@@ -604,14 +647,17 @@ func relocsym(s *LSym) {
func reloc() {
if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime())
+ fmt.Fprintf(Bso, "%5.2f reloc\n", obj.Cputime())
}
Bso.Flush()
- for s := Ctxt.Textp; s != nil; s = s.Next {
+ for _, s := range Ctxt.Textp {
relocsym(s)
}
- for s := datap; s != nil; s = s.Next {
+ for _, sym := range datap {
+ relocsym(sym)
+ }
+ for s := dwarfp; s != nil; s = s.Next {
relocsym(s)
}
}
@@ -622,11 +668,9 @@ func dynrelocsym(s *LSym) {
if s == rel {
return
}
- var r *Reloc
- var targ *LSym
for ri := 0; ri < len(s.R); ri++ {
- r = &s.R[ri]
- targ = r.Sym
+ r := &s.R[ri]
+ targ := r.Sym
if targ == nil {
continue
}
@@ -639,7 +683,7 @@ func dynrelocsym(s *LSym) {
r.Add = int64(targ.Plt)
// jmp *addr
- if Thearch.Thechar == '8' {
+ if SysArch.Family == sys.I386 {
Adduint8(Ctxt, rel, 0xff)
Adduint8(Ctxt, rel, 0x25)
Addaddr(Ctxt, rel, targ)
@@ -661,9 +705,8 @@ func dynrelocsym(s *LSym) {
return
}
- var r *Reloc
for ri := 0; ri < len(s.R); ri++ {
- r = &s.R[ri]
+ r := &s.R[ri]
if r.Sym != nil && r.Sym.Type == obj.SDYNIMPORT || r.Type >= 256 {
if r.Sym != nil && !r.Sym.Attr.Reachable() {
Diag("internal inconsistency: dynamic symbol %s is not reachable.", r.Sym.Name)
@@ -673,22 +716,24 @@ func dynrelocsym(s *LSym) {
}
}
-func dynreloc() {
+func dynreloc(data *[obj.SXREF][]*LSym) {
// -d suppresses dynamic loader format, so we may as well not
// compute these sections or mark their symbols as reachable.
if Debug['d'] != 0 && HEADTYPE != obj.Hwindows {
return
}
if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime())
+ fmt.Fprintf(Bso, "%5.2f reloc\n", obj.Cputime())
}
Bso.Flush()
- for s := Ctxt.Textp; s != nil; s = s.Next {
+ for _, s := range Ctxt.Textp {
dynrelocsym(s)
}
- for s := datap; s != nil; s = s.Next {
- dynrelocsym(s)
+ for _, syms := range data {
+ for _, sym := range syms {
+ dynrelocsym(sym)
+ }
}
if Iself {
elfdynhash()
@@ -705,7 +750,6 @@ func blk(start *LSym, addr int64, size int64) {
}
eaddr := addr + size
- var p []byte
for ; sym != nil; sym = sym.Next {
if sym.Type&obj.SSUB != 0 {
continue
@@ -715,7 +759,7 @@ func blk(start *LSym, addr int64, size int64) {
}
Ctxt.Cursym = sym
if sym.Value < addr {
- Diag("phase error: addr=%#x but sym=%#x type=%d", int64(addr), int64(sym.Value), sym.Type)
+ Diag("phase error: addr=%#x but sym=%#x type=%d", addr, sym.Value, sym.Type)
errorexit()
}
@@ -723,15 +767,14 @@ func blk(start *LSym, addr int64, size int64) {
strnput("", int(sym.Value-addr))
addr = sym.Value
}
- p = sym.P
- Cwrite(p)
+ Cwrite(sym.P)
addr += int64(len(sym.P))
if addr < sym.Value+sym.Size {
strnput("", int(sym.Value+sym.Size-addr))
addr = sym.Value + sym.Size
}
if addr != sym.Value+sym.Size {
- Diag("phase error: addr=%#x value+size=%#x", int64(addr), int64(sym.Value)+sym.Size)
+ Diag("phase error: addr=%#x value+size=%#x", addr, sym.Value+sym.Size)
errorexit()
}
@@ -748,29 +791,30 @@ func blk(start *LSym, addr int64, size int64) {
func Codeblk(addr int64, size int64) {
if Debug['a'] != 0 {
- fmt.Fprintf(&Bso, "codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
+ fmt.Fprintf(Bso, "codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
}
- blk(Ctxt.Textp, addr, size)
+ blkSlice(Ctxt.Textp, addr, size)
/* again for printing */
if Debug['a'] == 0 {
return
}
- var sym *LSym
- for sym = Ctxt.Textp; sym != nil; sym = sym.Next {
+ syms := Ctxt.Textp
+ for i, sym := range syms {
if !sym.Attr.Reachable() {
continue
}
if sym.Value >= addr {
+ syms = syms[i:]
break
}
}
eaddr := addr + size
var q []byte
- for ; sym != nil; sym = sym.Next {
+ for _, sym := range syms {
if !sym.Attr.Reachable() {
continue
}
@@ -779,118 +823,164 @@ func Codeblk(addr int64, size int64) {
}
if addr < sym.Value {
- fmt.Fprintf(&Bso, "%-20s %.8x|", "_", uint64(int64(addr)))
+ fmt.Fprintf(Bso, "%-20s %.8x|", "_", uint64(addr))
for ; addr < sym.Value; addr++ {
- fmt.Fprintf(&Bso, " %.2x", 0)
+ fmt.Fprintf(Bso, " %.2x", 0)
}
- fmt.Fprintf(&Bso, "\n")
+ fmt.Fprintf(Bso, "\n")
}
- fmt.Fprintf(&Bso, "%.6x\t%-20s\n", uint64(int64(addr)), sym.Name)
+ fmt.Fprintf(Bso, "%.6x\t%-20s\n", uint64(addr), sym.Name)
q = sym.P
for len(q) >= 16 {
- fmt.Fprintf(&Bso, "%.6x\t% x\n", uint64(addr), q[:16])
+ fmt.Fprintf(Bso, "%.6x\t% x\n", uint64(addr), q[:16])
addr += 16
q = q[16:]
}
if len(q) > 0 {
- fmt.Fprintf(&Bso, "%.6x\t% x\n", uint64(addr), q)
+ fmt.Fprintf(Bso, "%.6x\t% x\n", uint64(addr), q)
addr += int64(len(q))
}
}
if addr < eaddr {
- fmt.Fprintf(&Bso, "%-20s %.8x|", "_", uint64(int64(addr)))
+ fmt.Fprintf(Bso, "%-20s %.8x|", "_", uint64(addr))
for ; addr < eaddr; addr++ {
- fmt.Fprintf(&Bso, " %.2x", 0)
+ fmt.Fprintf(Bso, " %.2x", 0)
}
}
Bso.Flush()
}
+// blkSlice is a variant of blk that processes slices.
+// After text symbols are converted from a linked list to a slice,
+// delete blk and give this function its name.
+func blkSlice(syms []*LSym, addr, size int64) {
+ for i, s := range syms {
+ if s.Type&obj.SSUB == 0 && s.Value >= addr {
+ syms = syms[i:]
+ break
+ }
+ }
+
+ eaddr := addr + size
+ for _, s := range syms {
+ if s.Type&obj.SSUB != 0 {
+ continue
+ }
+ if s.Value >= eaddr {
+ break
+ }
+ Ctxt.Cursym = s
+ if s.Value < addr {
+ Diag("phase error: addr=%#x but sym=%#x type=%d", addr, s.Value, s.Type)
+ errorexit()
+ }
+ if addr < s.Value {
+ strnput("", int(s.Value-addr))
+ addr = s.Value
+ }
+ Cwrite(s.P)
+ addr += int64(len(s.P))
+ if addr < s.Value+s.Size {
+ strnput("", int(s.Value+s.Size-addr))
+ addr = s.Value + s.Size
+ }
+ if addr != s.Value+s.Size {
+ Diag("phase error: addr=%#x value+size=%#x", addr, s.Value+s.Size)
+ errorexit()
+ }
+ if s.Value+s.Size >= eaddr {
+ break
+ }
+ }
+
+ if addr < eaddr {
+ strnput("", int(eaddr-addr))
+ }
+ Cflush()
+}
+
func Datblk(addr int64, size int64) {
if Debug['a'] != 0 {
- fmt.Fprintf(&Bso, "datblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
+ fmt.Fprintf(Bso, "datblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
}
- blk(datap, addr, size)
+ blkSlice(datap, addr, size)
/* again for printing */
if Debug['a'] == 0 {
return
}
- var sym *LSym
- for sym = datap; sym != nil; sym = sym.Next {
+ syms := datap
+ for i, sym := range syms {
if sym.Value >= addr {
+ syms = syms[i:]
break
}
}
eaddr := addr + size
- var ep []byte
- var i int64
- var p []byte
- var r *Reloc
- var rsname string
- var typ string
- for ; sym != nil; sym = sym.Next {
+ for _, sym := range syms {
if sym.Value >= eaddr {
break
}
if addr < sym.Value {
- fmt.Fprintf(&Bso, "\t%.8x| 00 ...\n", uint64(addr))
+ fmt.Fprintf(Bso, "\t%.8x| 00 ...\n", uint64(addr))
addr = sym.Value
}
- fmt.Fprintf(&Bso, "%s\n\t%.8x|", sym.Name, uint(addr))
- p = sym.P
- ep = p[len(sym.P):]
- for -cap(p) < -cap(ep) {
- if -cap(p) > -cap(sym.P) && int(-cap(p)+cap(sym.P))%16 == 0 {
- fmt.Fprintf(&Bso, "\n\t%.8x|", uint(addr+int64(-cap(p)+cap(sym.P))))
+ fmt.Fprintf(Bso, "%s\n\t%.8x|", sym.Name, uint64(addr))
+ for i, b := range sym.P {
+ if i > 0 && i%16 == 0 {
+ fmt.Fprintf(Bso, "\n\t%.8x|", uint64(addr)+uint64(i))
}
- fmt.Fprintf(&Bso, " %.2x", p[0])
- p = p[1:]
+ fmt.Fprintf(Bso, " %.2x", b)
}
addr += int64(len(sym.P))
for ; addr < sym.Value+sym.Size; addr++ {
- fmt.Fprintf(&Bso, " %.2x", 0)
+ fmt.Fprintf(Bso, " %.2x", 0)
}
- fmt.Fprintf(&Bso, "\n")
-
- if Linkmode == LinkExternal {
- for i = 0; i < int64(len(sym.R)); i++ {
- r = &sym.R[i]
- rsname = ""
- if r.Sym != nil {
- rsname = r.Sym.Name
- }
- typ = "?"
- switch r.Type {
- case obj.R_ADDR:
- typ = "addr"
-
- case obj.R_PCREL:
- typ = "pcrel"
+ fmt.Fprintf(Bso, "\n")
- case obj.R_CALL:
- typ = "call"
- }
-
- fmt.Fprintf(&Bso, "\treloc %.8x/%d %s %s+%#x [%#x]\n", uint(sym.Value+int64(r.Off)), r.Siz, typ, rsname, int64(r.Add), int64(r.Sym.Value+r.Add))
+ if Linkmode != LinkExternal {
+ continue
+ }
+ for _, r := range sym.R {
+ rsname := ""
+ if r.Sym != nil {
+ rsname = r.Sym.Name
+ }
+ typ := "?"
+ switch r.Type {
+ case obj.R_ADDR:
+ typ = "addr"
+ case obj.R_PCREL:
+ typ = "pcrel"
+ case obj.R_CALL:
+ typ = "call"
}
+ fmt.Fprintf(Bso, "\treloc %.8x/%d %s %s+%#x [%#x]\n", uint(sym.Value+int64(r.Off)), r.Siz, typ, rsname, r.Add, r.Sym.Value+r.Add)
}
}
if addr < eaddr {
- fmt.Fprintf(&Bso, "\t%.8x| 00 ...\n", uint(addr))
+ fmt.Fprintf(Bso, "\t%.8x| 00 ...\n", uint(addr))
}
- fmt.Fprintf(&Bso, "\t%.8x|\n", uint(eaddr))
+ fmt.Fprintf(Bso, "\t%.8x|\n", uint(eaddr))
+}
+
+func Dwarfblk(addr int64, size int64) {
+ if Debug['a'] != 0 {
+ fmt.Fprintf(Bso, "dwarfblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
+ }
+
+ blk(dwarfp, addr, size)
}
var zeros [512]byte
@@ -938,7 +1028,7 @@ func addstrdata(name string, value string) {
s.Attr |= AttrDuplicateOK
reachable := s.Attr.Reachable()
Addaddr(Ctxt, s, sp)
- adduintxx(Ctxt, s, uint64(len(value)), Thearch.Ptrsize)
+ adduintxx(Ctxt, s, uint64(len(value)), SysArch.PtrSize)
// addstring, addaddr, etc., mark the symbols as reachable.
// In this case that is not necessarily true, so stick to what
@@ -965,16 +1055,14 @@ func Addstring(s *LSym, str string) int64 {
s.Type = obj.SNOPTRDATA
}
s.Attr |= AttrReachable
- r := int32(s.Size)
- n := len(str) + 1
+ r := s.Size
if s.Name == ".shstrtab" {
elfsetstring(str, int(r))
}
- Symgrow(Ctxt, s, int64(r)+int64(n))
- copy(s.P[r:], str)
- s.P[int(r)+len(str)] = 0
- s.Size += int64(n)
- return int64(r)
+ s.P = append(s.P, str...)
+ s.P = append(s.P, 0)
+ s.Size = int64(len(s.P))
+ return r
}
// addgostring adds str, as a Go string value, to s. symname is the name of the
@@ -1031,7 +1119,7 @@ func symalign(s *LSym) int32 {
} else if s.Align != 0 {
return min
}
- if strings.HasPrefix(s.Name, "go.string.") && !strings.HasPrefix(s.Name, "go.string.hdr.") {
+ if (strings.HasPrefix(s.Name, "go.string.") && !strings.HasPrefix(s.Name, "go.string.hdr.")) || strings.HasPrefix(s.Name, "type..namedata.") {
// String data is just bytes.
// If we align it, we waste a lot of space to padding.
return min
@@ -1047,22 +1135,6 @@ func aligndatsize(datsize int64, s *LSym) int64 {
return Rnd(datsize, int64(symalign(s)))
}
-// maxalign returns the maximum required alignment for
-// the list of symbols s; the list stops when s->type exceeds type.
-func maxalign(s *LSym, type_ int) int32 {
- var align int32
-
- max := int32(0)
- for ; s != nil && int(s.Type) <= type_; s = s.Next {
- align = symalign(s)
- if max < align {
- max = align
- }
- }
-
- return max
-}
-
const debugGCProg = false
type GCProg struct {
@@ -1084,7 +1156,7 @@ func (p *GCProg) writeByte(x byte) {
}
func (p *GCProg) End(size int64) {
- p.w.ZeroUntil(size / int64(Thearch.Ptrsize))
+ p.w.ZeroUntil(size / int64(SysArch.PtrSize))
p.w.End()
if debugGCProg {
fmt.Fprintf(os.Stderr, "ld: end GCProg\n")
@@ -1100,7 +1172,7 @@ func (p *GCProg) AddSym(s *LSym) {
return
}
- ptrsize := int64(Thearch.Ptrsize)
+ ptrsize := int64(SysArch.PtrSize)
nptr := decodetype_ptrdata(typ) / ptrsize
if debugGCProg {
@@ -1124,236 +1196,170 @@ func (p *GCProg) AddSym(s *LSym) {
p.w.Append(prog[4:], nptr)
}
+// dataSortKey is used to sort a slice of data symbol *LSym pointers.
+// The sort keys are kept inline to improve cache behaviour while sorting.
type dataSortKey struct {
- // keep sort keys inline to improve cache behaviour while sorting
- Type int16
- Size int64
- Name string
-
- Lsym *LSym
+ size int64
+ name string
+ lsym *LSym
}
-type dataSlice []dataSortKey
-
-func (d dataSlice) Len() int { return len(d) }
-func (d dataSlice) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
-func (d dataSlice) Less(i, j int) bool {
- s1, s2 := &d[i], &d[j]
- if s1.Type != s2.Type {
- return s1.Type < s2.Type
- }
+type bySizeAndName []dataSortKey
- // For ppc64, we want to interleave the .got and .toc sections
- // from input files. Both are type SELFGOT, so in that case
- // fall through to the name comparison (conveniently, .got
- // sorts before .toc).
- if s1.Type != obj.SELFGOT && s1.Size != s2.Size {
- return s1.Size < s2.Size
+func (d bySizeAndName) Len() int { return len(d) }
+func (d bySizeAndName) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
+func (d bySizeAndName) Less(i, j int) bool {
+ s1, s2 := d[i], d[j]
+ if s1.size != s2.size {
+ return s1.size < s2.size
}
-
- return s1.Name < s2.Name
+ return s1.name < s2.name
}
-func growdatsize(datsizep *int64, s *LSym) {
- datsize := *datsizep
- const cutoff int64 = 2e9 // 2 GB (or so; looks better in errors than 2^31)
- switch {
- case s.Size < 0:
- Diag("%s: negative size (%d bytes)", s.Name, s.Size)
- case s.Size > cutoff:
- Diag("%s: symbol too large (%d bytes)", s.Name, s.Size)
- case datsize <= cutoff && datsize+s.Size > cutoff:
- Diag("%s: too much data (over %d bytes)", s.Name, cutoff)
- }
- *datsizep = datsize + s.Size
-}
+const cutoff int64 = 2e9 // 2 GB (or so; looks better in errors than 2^31)
-func list2Slice(head *LSym) dataSlice {
- n := 0
- for s := datap; s != nil; s = s.Next {
- n++
+func checkdatsize(datsize int64, symn int) {
+ if datsize > cutoff {
+ Diag("too much data in section %v (over %d bytes)", symn, cutoff)
}
- slice := make(dataSlice, n)
- i := 0
- for s := datap; s != nil; s = s.Next {
- k := &slice[i]
- k.Type = s.Type
- k.Size = s.Size
- k.Name = s.Name
- k.Lsym = s
-
- i++
- }
- return slice
}
-func slice2List(d dataSlice) *LSym {
- for i := 0; i < len(d)-1; i++ {
- d[i].Lsym.Next = d[i+1].Lsym
+func list2slice(s *LSym) []*LSym {
+ var syms []*LSym
+ for ; s != nil; s = s.Next {
+ syms = append(syms, s)
}
- d[len(d)-1].Lsym.Next = nil
- return d[0].Lsym
+ return syms
}
-func dataSort(head *LSym) *LSym {
- d := list2Slice(head)
- sort.Sort(d)
- return slice2List(d)
-}
+// datap is a collection of reachable data symbols in address order.
+// Generated by dodata.
+var datap []*LSym
func dodata() {
if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "%5.2f dodata\n", obj.Cputime())
+ fmt.Fprintf(Bso, "%5.2f dodata\n", obj.Cputime())
}
Bso.Flush()
- var last *LSym
- datap = nil
-
+ // Collect data symbols by type into data.
+ var data [obj.SXREF][]*LSym
for _, s := range Ctxt.Allsym {
if !s.Attr.Reachable() || s.Attr.Special() {
continue
}
- if obj.STEXT < s.Type && s.Type < obj.SXREF {
- if s.Attr.OnList() {
- log.Fatalf("symbol %s listed multiple times", s.Name)
- }
- s.Attr |= AttrOnList
- if last == nil {
- datap = s
- } else {
- last.Next = s
- }
- s.Next = nil
- last = s
- }
- }
-
- for s := datap; s != nil; s = s.Next {
- if int64(len(s.P)) > s.Size {
- Diag("%s: initialize bounds (%d < %d)", s.Name, int64(s.Size), len(s.P))
+ if s.Type <= obj.STEXT || s.Type >= obj.SXREF {
+ continue
}
+ data[s.Type] = append(data[s.Type], s)
}
- /*
- * now that we have the datap list, but before we start
- * to assign addresses, record all the necessary
- * dynamic relocations. these will grow the relocation
- * symbol, which is itself data.
- *
- * on darwin, we need the symbol table numbers for dynreloc.
- */
+ // Now that we have the data symbols, but before we start
+ // to assign addresses, record all the necessary
+ // dynamic relocations. These will grow the relocation
+ // symbol, which is itself data.
+ //
+ // On darwin, we need the symbol table numbers for dynreloc.
if HEADTYPE == obj.Hdarwin {
machosymorder()
}
- dynreloc()
-
- /* some symbols may no longer belong in datap (Mach-O) */
- var l **LSym
- var s *LSym
- for l = &datap; ; {
- s = *l
- if s == nil {
- break
- }
-
- if s.Type <= obj.STEXT || obj.SXREF <= s.Type {
- *l = s.Next
- } else {
- l = &s.Next
- }
- }
-
- *l = nil
+ dynreloc(&data)
if UseRelro() {
// "read only" data with relocations needs to go in its own section
// when building a shared library. We do this by boosting objects of
// type SXXX with relocations to type SXXXRELRO.
- for s := datap; s != nil; s = s.Next {
- if (s.Type >= obj.STYPE && s.Type <= obj.SFUNCTAB && len(s.R) > 0) || s.Type == obj.STYPE || s.Type == obj.SGOSTRINGHDR {
- s.Type += (obj.STYPERELRO - obj.STYPE)
- if s.Outer != nil {
- s.Outer.Type = s.Type
- }
- }
- }
- // Check that we haven't made two symbols with the same .Outer into
- // different types (because references two symbols with non-nil Outer
- // become references to the outer symbol + offset it's vital that the
- // symbol and the outer end up in the same section).
- for s := datap; s != nil; s = s.Next {
- if s.Outer != nil && s.Outer.Type != s.Type {
- Diag("inconsistent types for %s and its Outer %s (%d != %d)",
- s.Name, s.Outer.Name, s.Type, s.Outer.Type)
- }
- }
-
- }
+ for symnro := int16(obj.STYPE); symnro < obj.STYPERELRO; symnro++ {
+ symnrelro := symnro + obj.STYPERELRO - obj.STYPE
- datap = dataSort(datap)
+ ro := []*LSym{}
+ relro := data[symnrelro]
- if Iself {
- // Make .rela and .rela.plt contiguous, the ELF ABI requires this
- // and Solaris actually cares.
- var relplt *LSym
- for l = &datap; *l != nil; l = &(*l).Next {
- if (*l).Name == ".rel.plt" || (*l).Name == ".rela.plt" {
- relplt = (*l)
- *l = (*l).Next
- break
+ for _, s := range data[symnro] {
+ isRelro := len(s.R) > 0
+ switch s.Type {
+ case obj.STYPE, obj.SGOSTRINGHDR, obj.STYPERELRO, obj.SGOSTRINGHDRRELRO:
+ // Symbols are not sorted yet, so it is possible
+ // that an Outer symbol has been changed to a
+ // relro Type before it reaches here.
+ isRelro = true
+ }
+ if isRelro {
+ s.Type = symnrelro
+ if s.Outer != nil {
+ s.Outer.Type = s.Type
+ }
+ relro = append(relro, s)
+ } else {
+ ro = append(ro, s)
+ }
}
- }
- if relplt != nil {
- for s = datap; s != nil; s = s.Next {
- if s.Name == ".rel" || s.Name == ".rela" {
- relplt.Next = s.Next
- s.Next = relplt
+
+ // Check that we haven't made two symbols with the same .Outer into
+ // different types (because references two symbols with non-nil Outer
+ // become references to the outer symbol + offset it's vital that the
+ // symbol and the outer end up in the same section).
+ for _, s := range relro {
+ if s.Outer != nil && s.Outer.Type != s.Type {
+ Diag("inconsistent types for %s and its Outer %s (%d != %d)",
+ s.Name, s.Outer.Name, s.Type, s.Outer.Type)
}
}
+
+ data[symnro] = ro
+ data[symnrelro] = relro
}
}
- /*
- * allocate sections. list is sorted by type,
- * so we can just walk it for each piece we want to emit.
- * segdata is processed before segtext, because we need
- * to see all symbols in the .data and .bss sections in order
- * to generate garbage collection information.
- */
-
- /* begin segdata */
-
- /* skip symbols belonging to segtext */
- s = datap
-
- for ; s != nil && s.Type < obj.SELFSECT; s = s.Next {
+ // Sort symbols.
+ var dataMaxAlign [obj.SXREF]int32
+ var wg sync.WaitGroup
+ for symn := range data {
+ symn := symn
+ wg.Add(1)
+ go func() {
+ data[symn], dataMaxAlign[symn] = dodataSect(symn, data[symn])
+ wg.Done()
+ }()
}
+ wg.Wait()
- /* writable ELF sections */
+ // Allocate sections.
+ // Data is processed before segtext, because we need
+ // to see all symbols in the .data and .bss sections in order
+ // to generate garbage collection information.
datsize := int64(0)
- var sect *Section
- for ; s != nil && s.Type < obj.SELFGOT; s = s.Next {
- sect = addsection(&Segdata, s.Name, 06)
- sect.Align = symalign(s)
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- s.Sect = sect
- s.Type = obj.SDATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- growdatsize(&datsize, s)
- sect.Length = uint64(datsize) - sect.Vaddr
+ // Writable sections.
+ writableSects := []int{
+ obj.SELFSECT,
+ obj.SMACHO,
+ obj.SMACHOGOT,
+ obj.SWINDOWS,
+ }
+ for _, symn := range writableSects {
+ for _, s := range data[symn] {
+ sect := addsection(&Segdata, s.Name, 06)
+ sect.Align = symalign(s)
+ datsize = Rnd(datsize, int64(sect.Align))
+ sect.Vaddr = uint64(datsize)
+ s.Sect = sect
+ s.Type = obj.SDATA
+ s.Value = int64(uint64(datsize) - sect.Vaddr)
+ datsize += s.Size
+ sect.Length = uint64(datsize) - sect.Vaddr
+ }
+ checkdatsize(datsize, symn)
}
- /* .got (and .toc on ppc64) */
- if s.Type == obj.SELFGOT {
+ // .got (and .toc on ppc64)
+ if len(data[obj.SELFGOT]) > 0 {
sect := addsection(&Segdata, ".got", 06)
- sect.Align = maxalign(s, obj.SELFGOT)
+ sect.Align = dataMaxAlign[obj.SELFGOT]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
var toc *LSym
- for ; s != nil && s.Type == obj.SELFGOT; s = s.Next {
+ for _, s := range data[obj.SELFGOT] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
s.Type = obj.SDATA
@@ -1361,7 +1367,6 @@ func dodata() {
// Resolve .TOC. symbol for this object file (ppc64)
toc = Linkrlookup(Ctxt, ".TOC.", int(s.Version))
-
if toc != nil {
toc.Sect = sect
toc.Outer = s
@@ -1371,28 +1376,27 @@ func dodata() {
toc.Value = 0x8000
}
- growdatsize(&datsize, s)
+ datsize += s.Size
}
-
+ checkdatsize(datsize, obj.SELFGOT)
sect.Length = uint64(datsize) - sect.Vaddr
}
/* pointer-free data */
- sect = addsection(&Segdata, ".noptrdata", 06)
-
- sect.Align = maxalign(s, obj.SINITARR-1)
+ sect := addsection(&Segdata, ".noptrdata", 06)
+ sect.Align = dataMaxAlign[obj.SNOPTRDATA]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
Linklookup(Ctxt, "runtime.noptrdata", 0).Sect = sect
Linklookup(Ctxt, "runtime.enoptrdata", 0).Sect = sect
- for ; s != nil && s.Type < obj.SINITARR; s = s.Next {
+ for _, s := range data[obj.SNOPTRDATA] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
s.Type = obj.SDATA
s.Value = int64(uint64(datsize) - sect.Vaddr)
- growdatsize(&datsize, s)
+ datsize += s.Size
}
-
+ checkdatsize(datsize, obj.SNOPTRDATA)
sect.Length = uint64(datsize) - sect.Vaddr
hasinitarr := Linkshared
@@ -1402,116 +1406,102 @@ func dodata() {
case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared:
hasinitarr = true
}
-
if hasinitarr {
sect := addsection(&Segdata, ".init_array", 06)
- sect.Align = maxalign(s, obj.SINITARR)
+ sect.Align = dataMaxAlign[obj.SINITARR]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
- for ; s != nil && s.Type == obj.SINITARR; s = s.Next {
+ for _, s := range data[obj.SINITARR] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
s.Value = int64(uint64(datsize) - sect.Vaddr)
- growdatsize(&datsize, s)
+ datsize += s.Size
}
-
sect.Length = uint64(datsize) - sect.Vaddr
+ checkdatsize(datsize, obj.SINITARR)
}
/* data */
sect = addsection(&Segdata, ".data", 06)
- sect.Align = maxalign(s, obj.SBSS-1)
+ sect.Align = dataMaxAlign[obj.SDATA]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
Linklookup(Ctxt, "runtime.data", 0).Sect = sect
Linklookup(Ctxt, "runtime.edata", 0).Sect = sect
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
- Diag("unexpected symbol type %d", s.Type)
- }
-
+ for _, s := range data[obj.SDATA] {
s.Sect = sect
s.Type = obj.SDATA
datsize = aligndatsize(datsize, s)
s.Value = int64(uint64(datsize) - sect.Vaddr)
gc.AddSym(s)
- growdatsize(&datsize, s)
+ datsize += s.Size
}
+ checkdatsize(datsize, obj.SDATA)
sect.Length = uint64(datsize) - sect.Vaddr
gc.End(int64(sect.Length))
/* bss */
sect = addsection(&Segdata, ".bss", 06)
- sect.Align = maxalign(s, obj.SNOPTRBSS-1)
+ sect.Align = dataMaxAlign[obj.SBSS]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
Linklookup(Ctxt, "runtime.bss", 0).Sect = sect
Linklookup(Ctxt, "runtime.ebss", 0).Sect = sect
gc = GCProg{}
gc.Init("runtime.gcbss")
- for ; s != nil && s.Type < obj.SNOPTRBSS; s = s.Next {
+ for _, s := range data[obj.SBSS] {
s.Sect = sect
datsize = aligndatsize(datsize, s)
s.Value = int64(uint64(datsize) - sect.Vaddr)
gc.AddSym(s)
- growdatsize(&datsize, s)
+ datsize += s.Size
}
+ checkdatsize(datsize, obj.SBSS)
sect.Length = uint64(datsize) - sect.Vaddr
gc.End(int64(sect.Length))
/* pointer-free bss */
sect = addsection(&Segdata, ".noptrbss", 06)
-
- sect.Align = maxalign(s, obj.SNOPTRBSS)
+ sect.Align = dataMaxAlign[obj.SNOPTRBSS]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
Linklookup(Ctxt, "runtime.noptrbss", 0).Sect = sect
Linklookup(Ctxt, "runtime.enoptrbss", 0).Sect = sect
- for ; s != nil && s.Type == obj.SNOPTRBSS; s = s.Next {
+ for _, s := range data[obj.SNOPTRBSS] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
s.Value = int64(uint64(datsize) - sect.Vaddr)
- growdatsize(&datsize, s)
+ datsize += s.Size
}
sect.Length = uint64(datsize) - sect.Vaddr
Linklookup(Ctxt, "runtime.end", 0).Sect = sect
+ checkdatsize(datsize, obj.SNOPTRBSS)
- // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
- if datsize != int64(uint32(datsize)) {
- Diag("data or bss segment too large")
- }
-
- if s != nil && s.Type == obj.STLSBSS {
+ if len(data[obj.STLSBSS]) > 0 {
+ var sect *Section
if Iself && (Linkmode == LinkExternal || Debug['d'] == 0) && HEADTYPE != obj.Hopenbsd {
sect = addsection(&Segdata, ".tbss", 06)
- sect.Align = int32(Thearch.Ptrsize)
+ sect.Align = int32(SysArch.PtrSize)
sect.Vaddr = 0
- } else {
- sect = nil
}
datsize = 0
- for ; s != nil && s.Type == obj.STLSBSS; s = s.Next {
+ for _, s := range data[obj.STLSBSS] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
s.Value = datsize
- growdatsize(&datsize, s)
+ datsize += s.Size
}
+ checkdatsize(datsize, obj.STLSBSS)
if sect != nil {
sect.Length = uint64(datsize)
}
}
- if s != nil {
- Ctxt.Cursym = nil
- Diag("unexpected symbol type %d for %s", s.Type, s.Name)
- }
-
/*
* We finished data, begin read-only data.
* Not all systems support a separate read-only non-executable data section.
@@ -1529,39 +1519,62 @@ func dodata() {
segro = &Segtext
}
- s = datap
-
datsize = 0
/* read-only executable ELF, Mach-O sections */
- for ; s != nil && s.Type < obj.STYPE; s = s.Next {
- sect = addsection(&Segtext, s.Name, 04)
+ if len(data[obj.STEXT]) != 0 {
+ Diag("dodata found an STEXT symbol: %s", data[obj.STEXT][0].Name)
+ }
+ for _, s := range data[obj.SELFRXSECT] {
+ sect := addsection(&Segtext, s.Name, 04)
sect.Align = symalign(s)
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
s.Sect = sect
s.Type = obj.SRODATA
s.Value = int64(uint64(datsize) - sect.Vaddr)
- growdatsize(&datsize, s)
+ datsize += s.Size
sect.Length = uint64(datsize) - sect.Vaddr
+ checkdatsize(datsize, obj.SELFRXSECT)
}
/* read-only data */
sect = addsection(segro, ".rodata", 04)
- sect.Align = maxalign(s, obj.STYPERELRO-1)
- datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = 0
Linklookup(Ctxt, "runtime.rodata", 0).Sect = sect
Linklookup(Ctxt, "runtime.erodata", 0).Sect = sect
- for ; s != nil && s.Type < obj.STYPERELRO; s = s.Next {
- datsize = aligndatsize(datsize, s)
- s.Sect = sect
- s.Type = obj.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- growdatsize(&datsize, s)
+ if !UseRelro() {
+ Linklookup(Ctxt, "runtime.types", 0).Sect = sect
+ Linklookup(Ctxt, "runtime.etypes", 0).Sect = sect
+ }
+ roSects := []int{
+ obj.STYPE,
+ obj.SSTRING,
+ obj.SGOSTRING,
+ obj.SGOSTRINGHDR,
+ obj.SGOFUNC,
+ obj.SGCBITS,
+ obj.SRODATA,
+ obj.SFUNCTAB,
+ }
+ for _, symn := range roSects {
+ align := dataMaxAlign[symn]
+ if sect.Align < align {
+ sect.Align = align
+ }
+ }
+ datsize = Rnd(datsize, int64(sect.Align))
+ for _, symn := range roSects {
+ for _, s := range data[symn] {
+ datsize = aligndatsize(datsize, s)
+ s.Sect = sect
+ s.Type = obj.SRODATA
+ s.Value = int64(uint64(datsize) - sect.Vaddr)
+ datsize += s.Size
+ }
+ checkdatsize(datsize, symn)
}
-
sect.Length = uint64(datsize) - sect.Vaddr
// There is some data that are conceptually read-only but are written to by
@@ -1583,18 +1596,38 @@ func dodata() {
/* data only written by relocations */
sect = addsection(segro, ".data.rel.ro", 06)
- sect.Align = maxalign(s, obj.STYPELINK-1)
- datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = 0
- for ; s != nil && s.Type < obj.STYPELINK; s = s.Next {
- datsize = aligndatsize(datsize, s)
- if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect {
- Diag("s.Outer (%s) in different section from s (%s)", s.Outer.Name, s.Name)
+ Linklookup(Ctxt, "runtime.types", 0).Sect = sect
+ Linklookup(Ctxt, "runtime.etypes", 0).Sect = sect
+ relroSects := []int{
+ obj.STYPERELRO,
+ obj.SSTRINGRELRO,
+ obj.SGOSTRINGRELRO,
+ obj.SGOSTRINGHDRRELRO,
+ obj.SGOFUNCRELRO,
+ obj.SGCBITSRELRO,
+ obj.SRODATARELRO,
+ obj.SFUNCTABRELRO,
+ }
+ for _, symn := range relroSects {
+ align := dataMaxAlign[symn]
+ if sect.Align < align {
+ sect.Align = align
}
- s.Sect = sect
- s.Type = obj.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- growdatsize(&datsize, s)
+ }
+ datsize = Rnd(datsize, int64(sect.Align))
+ for _, symn := range relroSects {
+ for _, s := range data[symn] {
+ datsize = aligndatsize(datsize, s)
+ if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect {
+ Diag("s.Outer (%s) in different section from s (%s)", s.Outer.Name, s.Name)
+ }
+ s.Sect = sect
+ s.Type = obj.SRODATA
+ s.Value = int64(uint64(datsize) - sect.Vaddr)
+ datsize += s.Size
+ }
+ checkdatsize(datsize, symn)
}
sect.Length = uint64(datsize) - sect.Vaddr
@@ -1603,78 +1636,74 @@ func dodata() {
/* typelink */
sect = addsection(segro, relro_prefix+".typelink", relro_perms)
-
- sect.Align = maxalign(s, obj.STYPELINK)
+ sect.Align = dataMaxAlign[obj.STYPELINK]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
Linklookup(Ctxt, "runtime.typelink", 0).Sect = sect
Linklookup(Ctxt, "runtime.etypelink", 0).Sect = sect
- for ; s != nil && s.Type == obj.STYPELINK; s = s.Next {
+ for _, s := range data[obj.STYPELINK] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
s.Type = obj.SRODATA
s.Value = int64(uint64(datsize) - sect.Vaddr)
- growdatsize(&datsize, s)
+ datsize += s.Size
}
-
+ checkdatsize(datsize, obj.STYPELINK)
sect.Length = uint64(datsize) - sect.Vaddr
/* itablink */
sect = addsection(segro, relro_prefix+".itablink", relro_perms)
-
- sect.Align = maxalign(s, obj.SITABLINK)
+ sect.Align = dataMaxAlign[obj.SITABLINK]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
Linklookup(Ctxt, "runtime.itablink", 0).Sect = sect
Linklookup(Ctxt, "runtime.eitablink", 0).Sect = sect
- for ; s != nil && s.Type == obj.SITABLINK; s = s.Next {
+ for _, s := range data[obj.SITABLINK] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
s.Type = obj.SRODATA
s.Value = int64(uint64(datsize) - sect.Vaddr)
- growdatsize(&datsize, s)
+ datsize += s.Size
}
-
+ checkdatsize(datsize, obj.SITABLINK)
sect.Length = uint64(datsize) - sect.Vaddr
/* gosymtab */
sect = addsection(segro, relro_prefix+".gosymtab", relro_perms)
-
- sect.Align = maxalign(s, obj.SPCLNTAB-1)
+ sect.Align = dataMaxAlign[obj.SSYMTAB]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
Linklookup(Ctxt, "runtime.symtab", 0).Sect = sect
Linklookup(Ctxt, "runtime.esymtab", 0).Sect = sect
- for ; s != nil && s.Type < obj.SPCLNTAB; s = s.Next {
+ for _, s := range data[obj.SSYMTAB] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
s.Type = obj.SRODATA
s.Value = int64(uint64(datsize) - sect.Vaddr)
- growdatsize(&datsize, s)
+ datsize += s.Size
}
-
+ checkdatsize(datsize, obj.SSYMTAB)
sect.Length = uint64(datsize) - sect.Vaddr
/* gopclntab */
sect = addsection(segro, relro_prefix+".gopclntab", relro_perms)
-
- sect.Align = maxalign(s, obj.SELFROSECT-1)
+ sect.Align = dataMaxAlign[obj.SPCLNTAB]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
Linklookup(Ctxt, "runtime.pclntab", 0).Sect = sect
Linklookup(Ctxt, "runtime.epclntab", 0).Sect = sect
- for ; s != nil && s.Type < obj.SELFROSECT; s = s.Next {
+ for _, s := range data[obj.SPCLNTAB] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
s.Type = obj.SRODATA
s.Value = int64(uint64(datsize) - sect.Vaddr)
- growdatsize(&datsize, s)
+ datsize += s.Size
}
-
+ checkdatsize(datsize, obj.SRODATA)
sect.Length = uint64(datsize) - sect.Vaddr
/* read-only ELF, Mach-O sections */
- for ; s != nil && s.Type < obj.SELFSECT; s = s.Next {
+ for _, s := range data[obj.SELFROSECT] {
sect = addsection(segro, s.Name, 04)
sect.Align = symalign(s)
datsize = Rnd(datsize, int64(sect.Align))
@@ -1682,15 +1711,65 @@ func dodata() {
s.Sect = sect
s.Type = obj.SRODATA
s.Value = int64(uint64(datsize) - sect.Vaddr)
- growdatsize(&datsize, s)
+ datsize += s.Size
sect.Length = uint64(datsize) - sect.Vaddr
}
+ checkdatsize(datsize, obj.SELFROSECT)
+
+ for _, s := range data[obj.SMACHOPLT] {
+ sect = addsection(segro, s.Name, 04)
+ sect.Align = symalign(s)
+ datsize = Rnd(datsize, int64(sect.Align))
+ sect.Vaddr = uint64(datsize)
+ s.Sect = sect
+ s.Type = obj.SRODATA
+ s.Value = int64(uint64(datsize) - sect.Vaddr)
+ datsize += s.Size
+ sect.Length = uint64(datsize) - sect.Vaddr
+ }
+ checkdatsize(datsize, obj.SMACHOPLT)
// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
if datsize != int64(uint32(datsize)) {
Diag("read-only data segment too large")
}
+ for symn := obj.SELFRXSECT; symn < obj.SXREF; symn++ {
+ datap = append(datap, data[symn]...)
+ }
+
+ dwarfgeneratedebugsyms()
+
+ var s *LSym
+ for s = dwarfp; s != nil && s.Type == obj.SDWARFSECT; s = s.Next {
+ sect = addsection(&Segdwarf, s.Name, 04)
+ sect.Align = 1
+ datsize = Rnd(datsize, int64(sect.Align))
+ sect.Vaddr = uint64(datsize)
+ s.Sect = sect
+ s.Type = obj.SRODATA
+ s.Value = int64(uint64(datsize) - sect.Vaddr)
+ datsize += s.Size
+ sect.Length = uint64(datsize) - sect.Vaddr
+ }
+ checkdatsize(datsize, obj.SDWARFSECT)
+
+ if s != nil {
+ sect = addsection(&Segdwarf, ".debug_info", 04)
+ sect.Align = 1
+ datsize = Rnd(datsize, int64(sect.Align))
+ sect.Vaddr = uint64(datsize)
+ for ; s != nil && s.Type == obj.SDWARFINFO; s = s.Next {
+ s.Sect = sect
+ s.Type = obj.SRODATA
+ s.Value = int64(uint64(datsize) - sect.Vaddr)
+ s.Attr |= AttrLocal
+ datsize += s.Size
+ }
+ sect.Length = uint64(datsize) - sect.Vaddr
+ checkdatsize(datsize, obj.SDWARFINFO)
+ }
+
/* number the sections */
n := int32(1)
@@ -1706,6 +1785,97 @@ func dodata() {
sect.Extnum = int16(n)
n++
}
+ for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+ sect.Extnum = int16(n)
+ n++
+ }
+}
+
+func dodataSect(symn int, syms []*LSym) (result []*LSym, maxAlign int32) {
+ if HEADTYPE == obj.Hdarwin {
+ // Some symbols may no longer belong in syms
+ // due to movement in machosymorder.
+ newSyms := make([]*LSym, 0, len(syms))
+ for _, s := range syms {
+ if int(s.Type) == symn {
+ newSyms = append(newSyms, s)
+ }
+ }
+ syms = newSyms
+ }
+
+ symsSort := make([]dataSortKey, len(syms))
+ for i, s := range syms {
+ if s.Attr.OnList() {
+ log.Fatalf("symbol %s listed multiple times", s.Name)
+ }
+ s.Attr |= AttrOnList
+ switch {
+ case s.Size < int64(len(s.P)):
+ Diag("%s: initialize bounds (%d < %d)", s.Name, s.Size, len(s.P))
+ case s.Size < 0:
+ Diag("%s: negative size (%d bytes)", s.Name, s.Size)
+ case s.Size > cutoff:
+ Diag("%s: symbol too large (%d bytes)", s.Name, s.Size)
+ }
+
+ symsSort[i] = dataSortKey{
+ size: s.Size,
+ name: s.Name,
+ lsym: s,
+ }
+
+ switch s.Type {
+ case obj.SELFGOT:
+ // For ppc64, we want to interleave the .got and .toc sections
+ // from input files. Both are type SELFGOT, so in that case
+ // we skip size comparison and fall through to the name
+ // comparison (conveniently, .got sorts before .toc).
+ symsSort[i].size = 0
+ case obj.STYPELINK:
+ // Sort typelinks by the rtype.string field so the reflect
+ // package can binary search type links.
+ symsSort[i].name = string(decodetype_str(s.R[0].Sym))
+ }
+ }
+
+ sort.Sort(bySizeAndName(symsSort))
+
+ for i, symSort := range symsSort {
+ syms[i] = symSort.lsym
+ align := symalign(symSort.lsym)
+ if maxAlign < align {
+ maxAlign = align
+ }
+ }
+
+ if Iself && symn == obj.SELFROSECT {
+ // Make .rela and .rela.plt contiguous, the ELF ABI requires this
+ // and Solaris actually cares.
+ reli, plti := -1, -1
+ for i, s := range syms {
+ switch s.Name {
+ case ".rel.plt", ".rela.plt":
+ plti = i
+ case ".rel", ".rela":
+ reli = i
+ }
+ }
+ if reli >= 0 && plti >= 0 && plti != reli+1 {
+ var first, second int
+ if plti > reli {
+ first, second = reli, plti
+ } else {
+ first, second = plti, reli
+ }
+ rel, plt := syms[reli], syms[plti]
+ copy(syms[first+2:], syms[first+1:second])
+ syms[first+0] = rel
+ syms[first+1] = plt
+ }
+ }
+
+ return syms, maxAlign
}
// Add buildid to beginning of text segment, on non-ELF systems.
@@ -1727,14 +1897,13 @@ func textbuildid() {
sym.P = []byte(data)
sym.Size = int64(len(sym.P))
- sym.Next = Ctxt.Textp
- Ctxt.Textp = sym
+ Ctxt.Textp = append(Ctxt.Textp, nil)
+ copy(Ctxt.Textp[1:], Ctxt.Textp)
+ Ctxt.Textp[0] = sym
}
// assign addresses to text
func textaddress() {
- var sub *LSym
-
addsection(&Segtext, ".text", 05)
// Assign PCs in text segment.
@@ -1750,7 +1919,7 @@ func textaddress() {
}
va := uint64(INITTEXT)
sect.Vaddr = va
- for sym := Ctxt.Textp; sym != nil; sym = sym.Next {
+ for _, sym := range Ctxt.Textp {
sym.Sect = sect
if sym.Type&obj.SSUB != 0 {
continue
@@ -1761,7 +1930,7 @@ func textaddress() {
va = uint64(Rnd(int64(va), int64(Funcalign)))
}
sym.Value = 0
- for sub = sym; sub != nil; sub = sub.Sub {
+ for sub := sym; sub != nil; sub = sub.Sub {
sub.Value += int64(va)
}
if sym.Size == 0 && sym.Sub != nil {
@@ -1857,6 +2026,29 @@ func address() {
Segdata.Filelen = bss.Vaddr - Segdata.Vaddr
+ va = uint64(Rnd(int64(va), int64(INITRND)))
+ Segdwarf.Rwx = 06
+ Segdwarf.Vaddr = va
+ Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(INITRND)))
+ Segdwarf.Filelen = 0
+ if HEADTYPE == obj.Hwindows {
+ Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(PEFILEALIGN)))
+ }
+ for s := Segdwarf.Sect; s != nil; s = s.Next {
+ vlen = int64(s.Length)
+ if s.Next != nil {
+ vlen = int64(s.Next.Vaddr - s.Vaddr)
+ }
+ s.Vaddr = va
+ va += uint64(vlen)
+ if HEADTYPE == obj.Hwindows {
+ va = uint64(Rnd(int64(va), PEFILEALIGN))
+ }
+ Segdwarf.Length = va - Segdwarf.Vaddr
+ }
+
+ Segdwarf.Filelen = va - Segdwarf.Vaddr
+
text := Segtext.Sect
var rodata *Section
if Segrodata.Sect != nil {
@@ -1864,23 +2056,34 @@ func address() {
} else {
rodata = text.Next
}
+ var relrodata *Section
typelink := rodata.Next
if UseRelro() {
// There is another section (.data.rel.ro) when building a shared
// object on elf systems.
+ relrodata = typelink
typelink = typelink.Next
}
itablink := typelink.Next
symtab := itablink.Next
pclntab := symtab.Next
- var sub *LSym
- for sym := datap; sym != nil; sym = sym.Next {
+ for _, s := range datap {
+ Ctxt.Cursym = s
+ if s.Sect != nil {
+ s.Value += int64(s.Sect.Vaddr)
+ }
+ for sub := s.Sub; sub != nil; sub = sub.Sub {
+ sub.Value += s.Value
+ }
+ }
+
+ for sym := dwarfp; sym != nil; sym = sym.Next {
Ctxt.Cursym = sym
if sym.Sect != nil {
sym.Value += int64(sym.Sect.Vaddr)
}
- for sub = sym.Sub; sub != nil; sub = sub.Sub {
+ for sub := sym.Sub; sub != nil; sub = sub.Sub {
sub.Value += sym.Value
}
}
@@ -1892,6 +2095,11 @@ func address() {
s.Value = int64(sectSym.Sect.Vaddr + 16)
}
+ types := relrodata
+ if types == nil {
+ types = rodata
+ }
+
xdefine("runtime.text", obj.STEXT, int64(text.Vaddr))
xdefine("runtime.etext", obj.STEXT, int64(text.Vaddr+text.Length))
if HEADTYPE == obj.Hwindows {
@@ -1899,6 +2107,8 @@ func address() {
}
xdefine("runtime.rodata", obj.SRODATA, int64(rodata.Vaddr))
xdefine("runtime.erodata", obj.SRODATA, int64(rodata.Vaddr+rodata.Length))
+ xdefine("runtime.types", obj.SRODATA, int64(types.Vaddr))
+ xdefine("runtime.etypes", obj.SRODATA, int64(types.Vaddr+types.Length))
xdefine("runtime.typelink", obj.SRODATA, int64(typelink.Vaddr))
xdefine("runtime.etypelink", obj.SRODATA, int64(typelink.Vaddr+typelink.Length))
xdefine("runtime.itablink", obj.SRODATA, int64(itablink.Vaddr))
diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go
index 56c4370bcc..aaed6cde21 100644
--- a/src/cmd/link/internal/ld/deadcode.go
+++ b/src/cmd/link/internal/ld/deadcode.go
@@ -6,6 +6,7 @@ package ld
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"fmt"
"strings"
"unicode"
@@ -18,7 +19,7 @@ import (
//
// This flood fill is wrapped in logic for pruning unused methods.
// All methods are mentioned by relocations on their receiver's *rtype.
-// These relocations are specially defined as R_METHOD by the compiler
+// These relocations are specially defined as R_METHODOFF by the compiler
// so we can detect and manipulated them here.
//
// There are three ways a method of a reachable type can be invoked:
@@ -99,7 +100,7 @@ func deadcode(ctxt *Link) {
d.flood()
}
- // Remove all remaining unreached R_METHOD relocations.
+ // Remove all remaining unreached R_METHODOFF relocations.
for _, m := range d.markableMethods {
for _, r := range m.r {
d.cleanupReloc(r)
@@ -118,25 +119,13 @@ func deadcode(ctxt *Link) {
}
// Remove dead text but keep file information (z symbols).
- var last *LSym
- for s := ctxt.Textp; s != nil; s = s.Next {
- if !s.Attr.Reachable() {
- continue
+ textp := make([]*LSym, 0, len(ctxt.Textp))
+ for _, s := range ctxt.Textp {
+ if s.Attr.Reachable() {
+ textp = append(textp, s)
}
- if last == nil {
- ctxt.Textp = s
- } else {
- last.Next = s
- }
- last = s
- }
- if last == nil {
- ctxt.Textp = nil
- ctxt.Etextp = nil
- } else {
- last.Next = nil
- ctxt.Etextp = last
}
+ ctxt.Textp = textp
}
var markextra = []string{
@@ -166,12 +155,10 @@ var markextra = []string{
type methodref struct {
m methodsig
src *LSym // receiver type symbol
- r [3]*Reloc // R_METHOD relocations to fields of runtime.method
+ r [3]*Reloc // R_METHODOFF relocations to fields of runtime.method
}
-func (m methodref) mtyp() *LSym { return m.r[0].Sym }
-func (m methodref) ifn() *LSym { return m.r[1].Sym }
-func (m methodref) tfn() *LSym { return m.r[2].Sym }
+func (m methodref) ifn() *LSym { return m.r[1].Sym }
func (m methodref) isExported() bool {
for _, r := range m.m {
@@ -191,7 +178,7 @@ type deadcodepass struct {
func (d *deadcodepass) cleanupReloc(r *Reloc) {
if r.Sym.Attr.Reachable() {
- r.Type = obj.R_ADDR
+ r.Type = obj.R_ADDROFF
} else {
if Debug['v'] > 1 {
fmt.Fprintf(d.ctxt.Bso, "removing method %s\n", r.Sym.Name)
@@ -209,6 +196,13 @@ func (d *deadcodepass) mark(s, parent *LSym) {
if s.Attr.ReflectMethod() {
d.reflectMethod = true
}
+ if flag_dumpdep {
+ p := "_"
+ if parent != nil {
+ p = parent.Name
+ }
+ fmt.Printf("%s -> %s\n", p, s.Name)
+ }
s.Attr |= AttrReachable
s.Reachparent = parent
d.markQueue = append(d.markQueue, s)
@@ -218,7 +212,7 @@ func (d *deadcodepass) mark(s, parent *LSym) {
func (d *deadcodepass) markMethod(m methodref) {
for _, r := range m.r {
d.mark(r.Sym, m.src)
- r.Type = obj.R_ADDR
+ r.Type = obj.R_ADDROFF
}
}
@@ -227,7 +221,7 @@ func (d *deadcodepass) markMethod(m methodref) {
func (d *deadcodepass) init() {
var names []string
- if Thearch.Thechar == '5' {
+ if SysArch.Family == sys.ARM {
// mark some functions that are only referenced after linker code editing
if d.ctxt.Goarm == 5 {
names = append(names, "_sfloat")
@@ -273,9 +267,12 @@ func (d *deadcodepass) flood() {
if Debug['v'] > 1 {
fmt.Fprintf(d.ctxt.Bso, "marktext %s\n", s.Name)
}
- for _, a := range s.Autom {
- d.mark(a.Gotype, s)
+ if s.FuncInfo != nil {
+ for _, a := range s.FuncInfo.Autom {
+ d.mark(a.Gotype, s)
+ }
}
+
}
if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' {
@@ -289,14 +286,14 @@ func (d *deadcodepass) flood() {
}
}
- mpos := 0 // 0-3, the R_METHOD relocs of runtime.uncommontype
+ mpos := 0 // 0-3, the R_METHODOFF relocs of runtime.uncommontype
var methods []methodref
for i := 0; i < len(s.R); i++ {
r := &s.R[i]
if r.Sym == nil {
continue
}
- if r.Type != obj.R_METHOD {
+ if r.Type != obj.R_METHODOFF {
d.mark(r.Sym, s)
continue
}
@@ -333,9 +330,9 @@ func (d *deadcodepass) flood() {
d.markableMethods = append(d.markableMethods, methods...)
}
- if s.Pcln != nil {
- for i := range s.Pcln.Funcdata {
- d.mark(s.Pcln.Funcdata[i], s)
+ if s.FuncInfo != nil {
+ for i := range s.FuncInfo.Funcdata {
+ d.mark(s.FuncInfo.Funcdata[i], s)
}
}
d.mark(s.Gotype, s)
diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go
index 0a6bf094aa..551ff802d7 100644
--- a/src/cmd/link/internal/ld/decodesym.go
+++ b/src/cmd/link/internal/ld/decodesym.go
@@ -7,6 +7,7 @@ package ld
import (
"bytes"
"cmd/internal/obj"
+ "cmd/internal/sys"
"debug/elf"
"fmt"
)
@@ -15,10 +16,22 @@ import (
// ../../runtime/type.go, or more specifically, with what
// ../gc/reflect.c stuffs in these.
+// tflag is documented in reflect/type.go.
+//
+// tflag values must be kept in sync with copies in:
+// cmd/compile/internal/gc/reflect.go
+// cmd/link/internal/ld/decodesym.go
+// reflect/type.go
+// runtime/type.go
+const (
+ tflagUncommon = 1 << 0
+ tflagExtraStar = 1 << 1
+)
+
func decode_reloc(s *LSym, off int32) *Reloc {
- for i := 0; i < len(s.R); i++ {
+ for i := range s.R {
if s.R[i].Off == off {
- return &s.R[i:][0]
+ return &s.R[i]
}
}
return nil
@@ -46,39 +59,33 @@ func decode_inuxi(p []byte, sz int) uint64 {
}
}
-func commonsize() int { return 6*Thearch.Ptrsize + 8 } // runtime._type
-func structfieldSize() int { return 3 * Thearch.Ptrsize } // runtime.structfield
-func uncommonSize() int { return 2*Thearch.Ptrsize + 2*Thearch.Intsize } // runtime.uncommontype
+func commonsize() int { return 4*SysArch.PtrSize + 8 + 8 } // runtime._type
+func structfieldSize() int { return 3 * SysArch.PtrSize } // runtime.structfield
+func uncommonSize() int { return 4 + 2 + 2 } // runtime.uncommontype
// Type.commonType.kind
func decodetype_kind(s *LSym) uint8 {
- return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindMask) // 0x13 / 0x1f
-}
-
-// Type.commonType.kind
-func decodetype_noptr(s *LSym) uint8 {
- return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindNoPointers) // 0x13 / 0x1f
+ return s.P[2*SysArch.PtrSize+7] & obj.KindMask // 0x13 / 0x1f
}
// Type.commonType.kind
func decodetype_usegcprog(s *LSym) uint8 {
- return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindGCProg) // 0x13 / 0x1f
+ return s.P[2*SysArch.PtrSize+7] & obj.KindGCProg // 0x13 / 0x1f
}
// Type.commonType.size
func decodetype_size(s *LSym) int64 {
- return int64(decode_inuxi(s.P, Thearch.Ptrsize)) // 0x8 / 0x10
+ return int64(decode_inuxi(s.P, SysArch.PtrSize)) // 0x8 / 0x10
}
// Type.commonType.ptrdata
func decodetype_ptrdata(s *LSym) int64 {
- return int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Ptrsize)) // 0x8 / 0x10
+ return int64(decode_inuxi(s.P[SysArch.PtrSize:], SysArch.PtrSize)) // 0x8 / 0x10
}
// Type.commonType.tflag
func decodetype_hasUncommon(s *LSym) bool {
- const tflagUncommon = 1 // see ../../../../reflect/type.go:/^type.tflag
- return s.P[2*Thearch.Ptrsize+4]&tflagUncommon != 0
+ return s.P[2*SysArch.PtrSize+4]&tflagUncommon != 0
}
// Find the elf.Section of a given shared library that contains a given address.
@@ -112,11 +119,11 @@ func decodetype_gcprog(s *LSym) []byte {
Exitf("cannot find gcprog for %s", s.Name)
return nil
}
- return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize)).P
+ return decode_reloc_sym(s, 2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize)).P
}
func decodetype_gcprog_shlib(s *LSym) uint64 {
- if Thearch.Thechar == '7' {
+ if SysArch.Family == sys.ARM64 {
for _, shlib := range Ctxt.Shlibs {
if shlib.Path == s.File {
return shlib.gcdata_addresses[s]
@@ -124,7 +131,7 @@ func decodetype_gcprog_shlib(s *LSym) uint64 {
}
return 0
}
- return decode_inuxi(s.P[2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize):], Thearch.Ptrsize)
+ return decode_inuxi(s.P[2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize):], SysArch.PtrSize)
}
func decodetype_gcmask(s *LSym) []byte {
@@ -133,14 +140,14 @@ func decodetype_gcmask(s *LSym) []byte {
ptrdata := decodetype_ptrdata(s)
sect := findShlibSection(s.File, addr)
if sect != nil {
- r := make([]byte, ptrdata/int64(Thearch.Ptrsize))
+ r := make([]byte, ptrdata/int64(SysArch.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))
+ mask := decode_reloc_sym(s, 2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize))
return mask.P
}
@@ -150,7 +157,7 @@ func decodetype_arrayelem(s *LSym) *LSym {
}
func decodetype_arraylen(s *LSym) int64 {
- return int64(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Ptrsize))
+ return int64(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.PtrSize))
}
// Type.PtrType.elem
@@ -164,7 +171,7 @@ func decodetype_mapkey(s *LSym) *LSym {
}
func decodetype_mapvalue(s *LSym) *LSym {
- return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)) // 0x20 / 0x38
+ return decode_reloc_sym(s, int32(commonsize())+int32(SysArch.PtrSize)) // 0x20 / 0x38
}
// Type.ChanType.elem
@@ -188,13 +195,13 @@ func decodetype_funcoutcount(s *LSym) int {
func decodetype_funcintype(s *LSym, i int) *LSym {
uadd := commonsize() + 4
- if Thearch.Ptrsize == 8 {
+ if SysArch.PtrSize == 8 {
uadd += 4
}
if decodetype_hasUncommon(s) {
uadd += uncommonSize()
}
- return decode_reloc_sym(s, int32(uadd+i*Thearch.Ptrsize))
+ return decode_reloc_sym(s, int32(uadd+i*SysArch.PtrSize))
}
func decodetype_funcouttype(s *LSym, i int) *LSym {
@@ -203,11 +210,11 @@ func decodetype_funcouttype(s *LSym, i int) *LSym {
// Type.StructType.fields.Slice::length
func decodetype_structfieldcount(s *LSym) int {
- return int(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Intsize))
+ return int(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.IntSize))
}
func decodetype_structfieldarrayoff(s *LSym, i int) int {
- off := commonsize() + 2*Thearch.Ptrsize + 2*Thearch.Intsize
+ off := commonsize() + 2*SysArch.PtrSize + 2*SysArch.IntSize
if decodetype_hasUncommon(s) {
off += uncommonSize()
}
@@ -215,17 +222,13 @@ func decodetype_structfieldarrayoff(s *LSym, i int) int {
return off
}
-func decodetype_stringptr(s *LSym, off int) string {
- s = decode_reloc_sym(s, int32(off))
- if s == nil {
- return ""
- }
- r := decode_reloc(s, 0) // s has a pointer to the string data at offset 0
- if r == nil { // shouldn't happen.
- return ""
+// decodetype_str returns the contents of an rtype's str field (a nameOff).
+func decodetype_str(s *LSym) string {
+ str := decodetype_name(s, 4*SysArch.PtrSize+8)
+ if s.P[2*SysArch.PtrSize+4]&tflagExtraStar != 0 {
+ return str[1:]
}
- strlen := int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Intsize))
- return string(r.Sym.P[r.Add : r.Add+strlen])
+ return str
}
// decodetype_name decodes the name from a reflect.name.
@@ -236,9 +239,8 @@ func decodetype_name(s *LSym, off int) string {
}
data := r.Sym.P
- namelen := int(uint16(data[1]<<8) | uint16(data[2]))
+ namelen := int(uint16(data[1])<<8 | uint16(data[2]))
return string(data[3 : 3+namelen])
-
}
func decodetype_structfieldname(s *LSym, i int) string {
@@ -248,17 +250,17 @@ func decodetype_structfieldname(s *LSym, i int) string {
func decodetype_structfieldtype(s *LSym, i int) *LSym {
off := decodetype_structfieldarrayoff(s, i)
- return decode_reloc_sym(s, int32(off+Thearch.Ptrsize))
+ return decode_reloc_sym(s, int32(off+SysArch.PtrSize))
}
func decodetype_structfieldoffs(s *LSym, i int) int64 {
off := decodetype_structfieldarrayoff(s, i)
- return int64(decode_inuxi(s.P[off+2*Thearch.Ptrsize:], Thearch.Intsize))
+ return int64(decode_inuxi(s.P[off+2*SysArch.PtrSize:], SysArch.IntSize))
}
// InterfaceType.methods.length
func decodetype_ifacemethodcount(s *LSym) int64 {
- return int64(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Intsize))
+ return int64(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.IntSize))
}
// methodsig is a fully qualified typed method signature, like
@@ -279,8 +281,9 @@ const (
)
// decode_methodsig decodes an array of method signature information.
-// Each element of the array is size bytes. The first word is a
-// reflect.name for the name, the second word is a *rtype for the funcType.
+// Each element of the array is size bytes. The first 4 bytes is a
+// nameOff for the method name, and the next 4 bytes is a typeOff for
+// the function type.
//
// Conveniently this is the layout of both runtime.method and runtime.imethod.
func decode_methodsig(s *LSym, off, size, count int) []methodsig {
@@ -288,7 +291,7 @@ func decode_methodsig(s *LSym, off, size, count int) []methodsig {
var methods []methodsig
for i := 0; i < count; i++ {
buf.WriteString(decodetype_name(s, off))
- mtypSym := decode_reloc_sym(s, int32(off+Thearch.Ptrsize))
+ mtypSym := decode_reloc_sym(s, int32(off+4))
buf.WriteRune('(')
inCount := decodetype_funcincount(mtypSym)
@@ -319,7 +322,7 @@ func decodetype_ifacemethods(s *LSym) []methodsig {
if decodetype_kind(s)&kindMask != kindInterface {
panic(fmt.Sprintf("symbol %q is not an interface", s.Name))
}
- r := decode_reloc(s, int32(commonsize()+Thearch.Ptrsize))
+ r := decode_reloc(s, int32(commonsize()+SysArch.PtrSize))
if r == nil {
return nil
}
@@ -328,7 +331,7 @@ func decodetype_ifacemethods(s *LSym) []methodsig {
}
off := int(r.Add) // array of reflect.imethod values
numMethods := int(decodetype_ifacemethodcount(s))
- sizeofIMethod := 2 * Thearch.Ptrsize
+ sizeofIMethod := 4 + 4
return decode_methodsig(s, off, sizeofIMethod, numMethods)
}
@@ -339,31 +342,28 @@ func decodetype_methods(s *LSym) []methodsig {
off := commonsize() // reflect.rtype
switch decodetype_kind(s) & kindMask {
case kindStruct: // reflect.structType
- off += 2*Thearch.Ptrsize + 2*Thearch.Intsize
+ off += 2*SysArch.PtrSize + 2*SysArch.IntSize
case kindPtr: // reflect.ptrType
- off += Thearch.Ptrsize
+ off += SysArch.PtrSize
case kindFunc: // reflect.funcType
- off += Thearch.Ptrsize // 4 bytes, pointer aligned
+ off += SysArch.PtrSize // 4 bytes, pointer aligned
case kindSlice: // reflect.sliceType
- off += Thearch.Ptrsize
+ off += SysArch.PtrSize
case kindArray: // reflect.arrayType
- off += 3 * Thearch.Ptrsize
+ off += 3 * SysArch.PtrSize
case kindChan: // reflect.chanType
- off += 2 * Thearch.Ptrsize
+ off += 2 * SysArch.PtrSize
case kindMap: // reflect.mapType
- off += 4*Thearch.Ptrsize + 8
+ off += 4*SysArch.PtrSize + 8
case kindInterface: // reflect.interfaceType
- off += Thearch.Ptrsize + 2*Thearch.Intsize
+ off += SysArch.PtrSize + 2*SysArch.IntSize
default:
// just Sizeof(rtype)
}
- numMethods := int(decode_inuxi(s.P[off+2*Thearch.Ptrsize:], Thearch.Intsize))
- r := decode_reloc(s, int32(off+Thearch.Ptrsize))
- if r.Sym != s {
- panic(fmt.Sprintf("method slice pointer in %s leads to a different symbol %s", s, r.Sym))
- }
- off = int(r.Add) // array of reflect.method values
- sizeofMethod := 4 * Thearch.Ptrsize // sizeof reflect.method in program
- return decode_methodsig(s, off, sizeofMethod, numMethods)
+ mcount := int(decode_inuxi(s.P[off+4:], 2))
+ moff := int(decode_inuxi(s.P[off+4+2:], 2))
+ off += moff // offset to array of reflect.method values
+ const sizeofMethod = 4 * 4 // sizeof reflect.method in program
+ return decode_methodsig(s, off, sizeofMethod, mcount)
}
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index fd177cfef0..bf1a7e74c1 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -17,97 +17,34 @@ package ld
import (
"cmd/internal/obj"
"fmt"
+ "log"
"os"
"strings"
)
+const infoprefix = "go.dwarf.info."
+
/*
* Offsets and sizes of the debug_* sections in the cout file.
*/
-var abbrevo int64
-
-var abbrevsize int64
-
var abbrevsym *LSym
-
-var abbrevsympos int64
-
-var lineo int64
-
-var linesize int64
-
-var linesym *LSym
-
-var linesympos int64
-
-var infoo int64 // also the base for DWDie->offs and reference attributes.
-
-var infosize int64
-
-var infosym *LSym
-
-var infosympos int64
-
-var frameo int64
-
-var framesize int64
-
-var framesym *LSym
-
-var framesympos int64
-
-var pubnameso int64
-
-var pubnamessize int64
-
-var pubtypeso int64
-
-var pubtypessize int64
-
-var arangeso int64
-
-var arangessize int64
-
-var gdbscripto int64
-
-var gdbscriptsize int64
-
-var infosec *LSym
-
-var inforeloco int64
-
-var inforelocsize int64
-
var arangessec *LSym
-
-var arangesreloco int64
-
-var arangesrelocsize int64
-
-var linesec *LSym
-
-var linereloco int64
-
-var linerelocsize int64
-
var framesec *LSym
-
-var framereloco int64
-
-var framerelocsize int64
+var infosec *LSym
+var linesec *LSym
var gdbscript string
/*
* Basic I/O
*/
-func addrput(addr int64) {
- switch Thearch.Ptrsize {
+func addrput(s *LSym, addr int64) {
+ switch SysArch.PtrSize {
case 4:
- Thearch.Lput(uint32(addr))
+ Adduint32(Ctxt, s, uint32(addr))
case 8:
- Thearch.Vput(uint64(addr))
+ Adduint64(Ctxt, s, uint64(addr))
}
}
@@ -144,14 +81,14 @@ func appendSleb128(b []byte, v int64) []byte {
var encbuf [10]byte
-func uleb128put(v int64) {
+func uleb128put(s *LSym, v int64) {
b := appendUleb128(encbuf[:0], uint64(v))
- Cwrite(b)
+ Addbytes(Ctxt, s, b)
}
-func sleb128put(v int64) {
+func sleb128put(s *LSym, v int64) {
b := appendSleb128(encbuf[:0], v)
- Cwrite(b)
+ Addbytes(Ctxt, s, b)
}
/*
@@ -462,24 +399,29 @@ var abbrevs = [DW_NABRV]DWAbbrev{
},
}
-func writeabbrev() {
- abbrevo = Cpos()
+var dwarfp *LSym
+
+func writeabbrev() *LSym {
+ s := Linklookup(Ctxt, ".debug_abbrev", 0)
+ s.Type = obj.SDWARFSECT
+ abbrevsym = s
+
for i := 1; i < DW_NABRV; i++ {
// See section 7.5.3
- uleb128put(int64(i))
+ uleb128put(s, int64(i))
- uleb128put(int64(abbrevs[i].tag))
- Cput(abbrevs[i].children)
+ uleb128put(s, int64(abbrevs[i].tag))
+ Adduint8(Ctxt, s, abbrevs[i].children)
for _, f := range abbrevs[i].attr {
- uleb128put(int64(f.attr))
- uleb128put(int64(f.form))
+ uleb128put(s, int64(f.attr))
+ uleb128put(s, int64(f.form))
}
- uleb128put(0)
- uleb128put(0)
+ uleb128put(s, 0)
+ uleb128put(s, 0)
}
- Cput(0)
- abbrevsize = Cpos() - abbrevo
+ Adduint8(Ctxt, s, 0)
+ return s
}
/*
@@ -504,10 +446,7 @@ type DWDie struct {
link *DWDie
child *DWDie
attr *DWAttr
- // offset into .debug_info section, i.e relative to
- // infoo. only valid after call to putdie()
- offs int64
- hash map[string]*DWDie // optional index of DWAttr by name, enabled by mkindex()
+ sym *LSym
}
/*
@@ -556,9 +495,8 @@ func getattr(die *DWDie, attr uint16) *DWAttr {
}
// Every DIE has at least a DW_AT_name attribute (but it will only be
-// written out if it is listed in the abbrev). If its parent is
-// keeping an index, the new DIE will be inserted there.
-func newdie(parent *DWDie, abbrev int, name string) *DWDie {
+// written out if it is listed in the abbrev).
+func newdie(parent *DWDie, abbrev int, name string, version int) *DWDie {
die := new(DWDie)
die.abbrev = abbrev
die.link = parent.child
@@ -566,17 +504,17 @@ func newdie(parent *DWDie, abbrev int, name string) *DWDie {
newattr(die, DW_AT_name, DW_CLS_STRING, int64(len(name)), name)
- if parent.hash != nil {
- parent.hash[name] = die
+ if name != "" && (abbrev <= DW_ABRV_VARIABLE || abbrev >= DW_ABRV_NULLTYPE) {
+ if abbrev != DW_ABRV_VARIABLE || version == 0 {
+ die.sym = Linklookup(Ctxt, infoprefix+name, version)
+ die.sym.Attr |= AttrHidden
+ die.sym.Type = obj.SDWARFINFO
+ }
}
return die
}
-func mkindex(die *DWDie) {
- die.hash = make(map[string]*DWDie)
-}
-
func walktypedef(die *DWDie) *DWDie {
// Resolve typedef if present.
if die.abbrev == DW_ABRV_TYPEDECL {
@@ -590,159 +528,157 @@ func walktypedef(die *DWDie) *DWDie {
return die
}
+func walksymtypedef(s *LSym) *LSym {
+ if t := Linkrlookup(Ctxt, s.Name+".def", int(s.Version)); t != nil {
+ return t
+ }
+ return s
+}
+
// Find child by AT_name using hashtable if available or linear scan
// if not.
-func find(die *DWDie, name string) *DWDie {
+func findchild(die *DWDie, name string) *DWDie {
var prev *DWDie
for ; die != prev; prev, die = die, walktypedef(die) {
- if die.hash == nil {
- for a := die.child; a != nil; a = a.link {
- if name == getattr(a, DW_AT_name).data {
- return a
- }
+ for a := die.child; a != nil; a = a.link {
+ if name == getattr(a, DW_AT_name).data {
+ return a
}
- continue
- }
- if a := die.hash[name]; a != nil {
- return a
}
+ continue
}
return nil
}
-func mustFind(die *DWDie, name string) *DWDie {
- r := find(die, name)
+// Used to avoid string allocation when looking up dwarf symbols
+var prefixBuf = []byte(infoprefix)
+
+func find(name string) *LSym {
+ n := append(prefixBuf, name...)
+ // The string allocation below is optimized away because it is only used in a map lookup.
+ s := Linkrlookup(Ctxt, string(n), 0)
+ prefixBuf = n[:len(infoprefix)]
+ return s
+}
+
+func mustFind(name string) *LSym {
+ r := find(name)
if r == nil {
- Exitf("dwarf find: %s %p has no %s", getattr(die, DW_AT_name).data, die, name)
+ Exitf("dwarf find: cannot find %s", name)
}
return r
}
-func adddwarfrel(sec *LSym, sym *LSym, offsetbase int64, siz int, addend int64) {
- r := Addrel(sec)
- r.Sym = sym
- r.Xsym = sym
- r.Off = int32(Cpos() - offsetbase)
- r.Siz = uint8(siz)
- r.Type = obj.R_ADDR
- r.Add = addend
- r.Xadd = addend
- if Iself && Thearch.Thechar == '6' {
- addend = 0
- }
- if HEADTYPE == obj.Hdarwin {
- addend += sym.Value
- }
- switch siz {
- case 4:
- Thearch.Lput(uint32(addend))
-
- case 8:
- Thearch.Vput(uint64(addend))
-
+func adddwarfref(ctxt *Link, s *LSym, t *LSym, size int) int64 {
+ var result int64
+ switch size {
default:
- Diag("bad size in adddwarfrel")
+ Diag("invalid size %d in adddwarfref\n", size)
+ fallthrough
+ case SysArch.PtrSize:
+ result = Addaddr(ctxt, s, t)
+ case 4:
+ result = addaddrplus4(ctxt, s, t, 0)
}
+ r := &s.R[len(s.R)-1]
+ r.Type = obj.R_DWARFREF
+ return result
}
-func newrefattr(die *DWDie, attr uint16, ref *DWDie) *DWAttr {
+func newrefattr(die *DWDie, attr uint16, ref *LSym) *DWAttr {
if ref == nil {
return nil
}
return newattr(die, attr, DW_CLS_REFERENCE, 0, ref)
}
-var fwdcount int
-
-func putattr(abbrev int, form int, cls int, value int64, data interface{}) {
+func putattr(s *LSym, abbrev int, form int, cls int, value int64, data interface{}) {
switch form {
case DW_FORM_addr: // address
if Linkmode == LinkExternal {
value -= (data.(*LSym)).Value
- adddwarfrel(infosec, data.(*LSym), infoo, Thearch.Ptrsize, value)
+ Addaddrplus(Ctxt, s, data.(*LSym), value)
break
}
- addrput(value)
+ addrput(s, value)
case DW_FORM_block1: // block
if cls == DW_CLS_ADDRESS {
- Cput(uint8(1 + Thearch.Ptrsize))
- Cput(DW_OP_addr)
- if Linkmode == LinkExternal {
- value -= (data.(*LSym)).Value
- adddwarfrel(infosec, data.(*LSym), infoo, Thearch.Ptrsize, value)
- break
- }
-
- addrput(value)
+ Adduint8(Ctxt, s, uint8(1+SysArch.PtrSize))
+ Adduint8(Ctxt, s, DW_OP_addr)
+ Addaddr(Ctxt, s, data.(*LSym))
break
}
value &= 0xff
- Cput(uint8(value))
+ Adduint8(Ctxt, s, uint8(value))
p := data.([]byte)
for i := 0; int64(i) < value; i++ {
- Cput(uint8(p[i]))
+ Adduint8(Ctxt, s, p[i])
}
case DW_FORM_block2: // block
value &= 0xffff
- Thearch.Wput(uint16(value))
+ Adduint16(Ctxt, s, uint16(value))
p := data.([]byte)
for i := 0; int64(i) < value; i++ {
- Cput(uint8(p[i]))
+ Adduint8(Ctxt, s, p[i])
}
case DW_FORM_block4: // block
value &= 0xffffffff
- Thearch.Lput(uint32(value))
+ Adduint32(Ctxt, s, uint32(value))
p := data.([]byte)
for i := 0; int64(i) < value; i++ {
- Cput(uint8(p[i]))
+ Adduint8(Ctxt, s, p[i])
}
case DW_FORM_block: // block
- uleb128put(value)
+ uleb128put(s, value)
p := data.([]byte)
for i := 0; int64(i) < value; i++ {
- Cput(uint8(p[i]))
+ Adduint8(Ctxt, s, p[i])
}
case DW_FORM_data1: // constant
- Cput(uint8(value))
+ Adduint8(Ctxt, s, uint8(value))
case DW_FORM_data2: // constant
- Thearch.Wput(uint16(value))
+ Adduint16(Ctxt, s, uint16(value))
case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
if Linkmode == LinkExternal && cls == DW_CLS_PTR {
- adddwarfrel(infosec, linesym, infoo, 4, value)
+ adddwarfref(Ctxt, s, linesec, 4)
break
}
- Thearch.Lput(uint32(value))
+ Adduint32(Ctxt, s, uint32(value))
case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr
- Thearch.Vput(uint64(value))
+ Adduint64(Ctxt, s, uint64(value))
case DW_FORM_sdata: // constant
- sleb128put(value)
+ sleb128put(s, value)
case DW_FORM_udata: // constant
- uleb128put(value)
+ uleb128put(s, value)
case DW_FORM_string: // string
- strnput(data.(string), int(value+1))
+ str := data.(string)
+ Addstring(s, str)
+ for i := int64(len(str)); i < value; i++ {
+ Adduint8(Ctxt, s, 0)
+ }
case DW_FORM_flag: // flag
if value != 0 {
- Cput(1)
+ Adduint8(Ctxt, s, 1)
} else {
- Cput(0)
+ Adduint8(Ctxt, s, 0)
}
// In DWARF 2 (which is what we claim to generate),
@@ -752,22 +688,14 @@ func putattr(abbrev int, form int, cls int, value int64, data interface{}) {
case DW_FORM_ref_addr: // reference to a DIE in the .info section
if data == nil {
Diag("dwarf: null reference in %d", abbrev)
- if Thearch.Ptrsize == 8 {
- Thearch.Vput(0) // invalid dwarf, gdb will complain.
+ if SysArch.PtrSize == 8 {
+ Adduint64(Ctxt, s, 0) // invalid dwarf, gdb will complain.
} else {
- Thearch.Lput(0) // invalid dwarf, gdb will complain.
+ Adduint32(Ctxt, s, 0) // invalid dwarf, gdb will complain.
}
} else {
- off := (data.(*DWDie)).offs
- if off == 0 {
- fwdcount++
- }
- if Linkmode == LinkExternal {
- adddwarfrel(infosec, infosym, infoo, Thearch.Ptrsize, off)
- break
- }
-
- addrput(off)
+ dsym := data.(*LSym)
+ adddwarfref(Ctxt, s, dsym, SysArch.PtrSize)
}
case DW_FORM_ref1, // reference within the compilation unit
@@ -786,34 +714,45 @@ func putattr(abbrev int, form int, cls int, value int64, data interface{}) {
// Note that we can (and do) add arbitrary attributes to a DIE, but
// only the ones actually listed in the Abbrev will be written out.
-func putattrs(abbrev int, attr *DWAttr) {
+func putattrs(s *LSym, abbrev int, attr *DWAttr) {
Outer:
for _, f := range abbrevs[abbrev].attr {
for ap := attr; ap != nil; ap = ap.link {
if ap.atr == f.attr {
- putattr(abbrev, int(f.form), int(ap.cls), ap.value, ap.data)
+ putattr(s, abbrev, int(f.form), int(ap.cls), ap.value, ap.data)
continue Outer
}
}
- putattr(abbrev, int(f.form), 0, 0, nil)
+ putattr(s, abbrev, int(f.form), 0, 0, nil)
}
}
-func putdies(die *DWDie) {
+func putdies(prev *LSym, die *DWDie) *LSym {
for ; die != nil; die = die.link {
- putdie(die)
+ prev = putdie(prev, die)
}
+ Adduint8(Ctxt, prev, 0)
+ return prev
}
-func putdie(die *DWDie) {
- die.offs = Cpos() - infoo
- uleb128put(int64(die.abbrev))
- putattrs(die.abbrev, die.attr)
+func putdie(prev *LSym, die *DWDie) *LSym {
+ s := die.sym
+ if s == nil {
+ s = prev
+ } else {
+ if s.Attr.OnList() {
+ log.Fatalf("symbol %s listed multiple times", s.Name)
+ }
+ s.Attr |= AttrOnList
+ prev.Next = s
+ }
+ uleb128put(s, int64(die.abbrev))
+ putattrs(s, die.abbrev, die.attr)
if abbrevs[die.abbrev].children != 0 {
- putdies(die.child)
- Cput(0)
+ return putdies(s, die.child)
}
+ return s
}
func reverselist(list **DWDie) {
@@ -880,44 +819,50 @@ func dotypedef(parent *DWDie, name string, def *DWDie) {
Diag("dwarf: bad def in dotypedef")
}
+ def.sym = Linklookup(Ctxt, def.sym.Name+".def", 0)
+ def.sym.Attr |= AttrHidden
+ def.sym.Type = obj.SDWARFINFO
+
// The typedef entry must be created after the def,
// so that future lookups will find the typedef instead
// of the real definition. This hooks the typedef into any
// circular definition loops, so that gdb can understand them.
- die := newdie(parent, DW_ABRV_TYPEDECL, name)
+ die := newdie(parent, DW_ABRV_TYPEDECL, name, 0)
- newrefattr(die, DW_AT_type, def)
+ newrefattr(die, DW_AT_type, def.sym)
}
// Define gotype, for composite ones recurse into constituents.
-func defgotype(gotype *LSym) *DWDie {
+func defgotype(gotype *LSym) *LSym {
if gotype == nil {
- return mustFind(&dwtypes, "<unspecified>")
+ return mustFind("<unspecified>")
}
if !strings.HasPrefix(gotype.Name, "type.") {
Diag("dwarf: type name doesn't start with \"type.\": %s", gotype.Name)
- return mustFind(&dwtypes, "<unspecified>")
+ return mustFind("<unspecified>")
}
name := gotype.Name[5:] // could also decode from Type.string
- die := find(&dwtypes, name)
+ sdie := find(name)
- if die != nil {
- return die
+ if sdie != nil {
+ return sdie
}
- if false && Debug['v'] > 2 {
- fmt.Printf("new type: %v\n", gotype)
- }
+ return newtype(gotype).sym
+}
+func newtype(gotype *LSym) *DWDie {
+ name := gotype.Name[5:] // could also decode from Type.string
kind := decodetype_kind(gotype)
bytesize := decodetype_size(gotype)
+ var die *DWDie
switch kind {
case obj.KindBool:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_boolean, 0)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
@@ -926,7 +871,7 @@ func defgotype(gotype *LSym) *DWDie {
obj.KindInt16,
obj.KindInt32,
obj.KindInt64:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_signed, 0)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
@@ -936,66 +881,69 @@ func defgotype(gotype *LSym) *DWDie {
obj.KindUint32,
obj.KindUint64,
obj.KindUintptr:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
case obj.KindFloat32,
obj.KindFloat64:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_float, 0)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
case obj.KindComplex64,
obj.KindComplex128:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_complex_float, 0)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
case obj.KindArray:
- die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name, 0)
dotypedef(&dwtypes, name, die)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
s := decodetype_arrayelem(gotype)
newrefattr(die, DW_AT_type, defgotype(s))
- fld := newdie(die, DW_ABRV_ARRAYRANGE, "range")
+ fld := newdie(die, DW_ABRV_ARRAYRANGE, "range", 0)
// use actual length not upper bound; correct for 0-length arrays.
newattr(fld, DW_AT_count, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0)
- newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr"))
+ newrefattr(fld, DW_AT_type, mustFind("uintptr"))
case obj.KindChan:
- die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name, 0)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
s := decodetype_chanelem(gotype)
newrefattr(die, DW_AT_go_elem, defgotype(s))
+ // Save elem type for synthesizechantypes. We could synthesize here
+ // but that would change the order of DIEs we output.
+ newrefattr(die, DW_AT_type, s)
case obj.KindFunc:
- die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name, 0)
dotypedef(&dwtypes, name, die)
- newrefattr(die, DW_AT_type, mustFind(&dwtypes, "void"))
+ newrefattr(die, DW_AT_type, mustFind("void"))
nfields := decodetype_funcincount(gotype)
var fld *DWDie
var s *LSym
for i := 0; i < nfields; i++ {
s = decodetype_funcintype(gotype, i)
- fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:])
+ fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
newrefattr(fld, DW_AT_type, defgotype(s))
}
if decodetype_funcdotdotdot(gotype) {
- newdie(die, DW_ABRV_DOTDOTDOT, "...")
+ newdie(die, DW_ABRV_DOTDOTDOT, "...", 0)
}
nfields = decodetype_funcoutcount(gotype)
for i := 0; i < nfields; i++ {
s = decodetype_funcouttype(gotype, i)
- fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:])
+ fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
newrefattr(fld, DW_AT_type, defptrto(defgotype(s)))
}
case obj.KindInterface:
- die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name, 0)
dotypedef(&dwtypes, name, die)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
nfields := int(decodetype_ifacemethodcount(gotype))
@@ -1008,31 +956,35 @@ func defgotype(gotype *LSym) *DWDie {
newrefattr(die, DW_AT_type, defgotype(s))
case obj.KindMap:
- die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name, 0)
s := decodetype_mapkey(gotype)
newrefattr(die, DW_AT_go_key, defgotype(s))
s = decodetype_mapvalue(gotype)
newrefattr(die, DW_AT_go_elem, defgotype(s))
+ // Save gotype for use in synthesizemaptypes. We could synthesize here,
+ // but that would change the order of the DIEs.
+ newrefattr(die, DW_AT_type, gotype)
case obj.KindPtr:
- die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name, 0)
dotypedef(&dwtypes, name, die)
s := decodetype_ptrelem(gotype)
newrefattr(die, DW_AT_type, defgotype(s))
case obj.KindSlice:
- die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name, 0)
dotypedef(&dwtypes, name, die)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
s := decodetype_arrayelem(gotype)
- newrefattr(die, DW_AT_go_elem, defgotype(s))
+ elem := defgotype(s)
+ newrefattr(die, DW_AT_go_elem, elem)
case obj.KindString:
- die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name, 0)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
case obj.KindStruct:
- die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name, 0)
dotypedef(&dwtypes, name, die)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
nfields := decodetype_structfieldcount(gotype)
@@ -1045,32 +997,41 @@ func defgotype(gotype *LSym) *DWDie {
if f == "" {
f = s.Name[5:] // skip "type."
}
- fld = newdie(die, DW_ABRV_STRUCTFIELD, f)
+ fld = newdie(die, DW_ABRV_STRUCTFIELD, f, 0)
newrefattr(fld, DW_AT_type, defgotype(s))
newmemberoffsetattr(fld, int32(decodetype_structfieldoffs(gotype, i)))
}
case obj.KindUnsafePointer:
- die = newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, name)
+ die = newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, name, 0)
default:
Diag("dwarf: definition of unknown kind %d: %s", kind, gotype.Name)
- die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name)
- newrefattr(die, DW_AT_type, mustFind(&dwtypes, "<unspecified>"))
+ die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name, 0)
+ newrefattr(die, DW_AT_type, mustFind("<unspecified>"))
}
newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, int64(kind), 0)
+ if _, ok := prototypedies[gotype.Name]; ok {
+ prototypedies[gotype.Name] = die
+ }
+
return die
}
+func nameFromDIESym(dwtype *LSym) string {
+ return strings.TrimSuffix(dwtype.Name[len(infoprefix):], ".def")
+}
+
// Find or construct *T given T.
-func defptrto(dwtype *DWDie) *DWDie {
- ptrname := fmt.Sprintf("*%s", getattr(dwtype, DW_AT_name).data)
- die := find(&dwtypes, ptrname)
+func defptrto(dwtype *LSym) *LSym {
+ ptrname := "*" + nameFromDIESym(dwtype)
+ die := find(ptrname)
if die == nil {
- die = newdie(&dwtypes, DW_ABRV_PTRTYPE, ptrname)
- newrefattr(die, DW_AT_type, dwtype)
+ pdie := newdie(&dwtypes, DW_ABRV_PTRTYPE, ptrname, 0)
+ newrefattr(pdie, DW_AT_type, dwtype)
+ return pdie.sym
}
return die
@@ -1084,7 +1045,7 @@ func copychildrenexcept(dst *DWDie, src *DWDie, except *DWDie) {
if src == except {
continue
}
- c := newdie(dst, src.abbrev, getattr(src, DW_AT_name).data.(string))
+ c := newdie(dst, src.abbrev, getattr(src, DW_AT_name).data.(string), 0)
for a := src.attr; a != nil; a = a.link {
newattr(c, a.atr, int(a.cls), a.value, a.data)
}
@@ -1100,9 +1061,11 @@ func copychildren(dst *DWDie, src *DWDie) {
// Search children (assumed to have DW_TAG_member) for the one named
// field and set its DW_AT_type to dwtype
-func substitutetype(structdie *DWDie, field string, dwtype *DWDie) {
- child := mustFind(structdie, field)
+func substitutetype(structdie *DWDie, field string, dwtype *LSym) {
+ child := findchild(structdie, field)
if child == nil {
+ Exitf("dwarf substitutetype: %s does not have member %s",
+ getattr(structdie, DW_AT_name).data, field)
return
}
@@ -1114,8 +1077,17 @@ func substitutetype(structdie *DWDie, field string, dwtype *DWDie) {
}
}
+func findprotodie(name string) *DWDie {
+ die, ok := prototypedies[name]
+ if ok && die == nil {
+ defgotype(lookup_or_diag(name))
+ die = prototypedies[name]
+ }
+ return die
+}
+
func synthesizestringtypes(die *DWDie) {
- prototype := walktypedef(defgotype(lookup_or_diag("type.runtime.stringStructDWARF")))
+ prototype := walktypedef(findprotodie("type.runtime.stringStructDWARF"))
if prototype == nil {
return
}
@@ -1129,7 +1101,7 @@ func synthesizestringtypes(die *DWDie) {
}
func synthesizeslicetypes(die *DWDie) {
- prototype := walktypedef(defgotype(lookup_or_diag("type.runtime.slice")))
+ prototype := walktypedef(findprotodie("type.runtime.slice"))
if prototype == nil {
return
}
@@ -1139,7 +1111,7 @@ func synthesizeslicetypes(die *DWDie) {
continue
}
copychildren(die, prototype)
- elem := getattr(die, DW_AT_go_elem).data.(*DWDie)
+ elem := getattr(die, DW_AT_go_elem).data.(*LSym)
substitutetype(die, "array", defptrto(elem))
}
}
@@ -1163,9 +1135,21 @@ const (
BucketSize = 8
)
+func mkinternaltype(abbrev int, typename, keyname, valname string, f func(*DWDie)) *LSym {
+ name := mkinternaltypename(typename, keyname, valname)
+ symname := infoprefix + name
+ s := Linkrlookup(Ctxt, symname, 0)
+ if s != nil {
+ return s
+ }
+ die := newdie(&dwtypes, abbrev, name, 0)
+ f(die)
+ return die.sym
+}
+
func synthesizemaptypes(die *DWDie) {
- hash := walktypedef(defgotype(lookup_or_diag("type.runtime.hmap")))
- bucket := walktypedef(defgotype(lookup_or_diag("type.runtime.bmap")))
+ hash := walktypedef(findprotodie("type.runtime.hmap"))
+ bucket := walktypedef(findprotodie("type.runtime.bmap"))
if hash == nil {
return
@@ -1175,97 +1159,92 @@ func synthesizemaptypes(die *DWDie) {
if die.abbrev != DW_ABRV_MAPTYPE {
continue
}
-
- keytype := walktypedef(getattr(die, DW_AT_go_key).data.(*DWDie))
- valtype := walktypedef(getattr(die, DW_AT_go_elem).data.(*DWDie))
+ gotype := getattr(die, DW_AT_type).data.(*LSym)
+ keytype := decodetype_mapkey(gotype)
+ valtype := decodetype_mapvalue(gotype)
+ keysize, valsize := decodetype_size(keytype), decodetype_size(valtype)
+ keytype, valtype = walksymtypedef(defgotype(keytype)), walksymtypedef(defgotype(valtype))
// compute size info like hashmap.c does.
- keysize, valsize := Thearch.Ptrsize, Thearch.Ptrsize
- a := getattr(keytype, DW_AT_byte_size)
- if a != nil {
- keysize = int(a.value)
- }
- a = getattr(valtype, DW_AT_byte_size)
- if a != nil {
- valsize = int(a.value)
- }
indirect_key, indirect_val := false, false
if keysize > MaxKeySize {
- keysize = Thearch.Ptrsize
+ keysize = int64(SysArch.PtrSize)
indirect_key = true
}
if valsize > MaxValSize {
- valsize = Thearch.Ptrsize
+ valsize = int64(SysArch.PtrSize)
indirect_val = true
}
// Construct type to represent an array of BucketSize keys
- dwhk := newdie(&dwtypes, DW_ABRV_ARRAYTYPE, mkinternaltypename("[]key", getattr(keytype, DW_AT_name).data.(string), ""))
-
- newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*int64(keysize), 0)
- t := keytype
- if indirect_key {
- t = defptrto(keytype)
- }
- newrefattr(dwhk, DW_AT_type, t)
- fld := newdie(dwhk, DW_ABRV_ARRAYRANGE, "size")
- newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0)
- newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr"))
+ keyname := nameFromDIESym(keytype)
+ dwhks := mkinternaltype(DW_ABRV_ARRAYTYPE, "[]key", keyname, "", func(dwhk *DWDie) {
+ newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*keysize, 0)
+ t := keytype
+ if indirect_key {
+ t = defptrto(keytype)
+ }
+ newrefattr(dwhk, DW_AT_type, t)
+ fld := newdie(dwhk, DW_ABRV_ARRAYRANGE, "size", 0)
+ newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0)
+ newrefattr(fld, DW_AT_type, mustFind("uintptr"))
+ })
// Construct type to represent an array of BucketSize values
- dwhv := newdie(&dwtypes, DW_ABRV_ARRAYTYPE, mkinternaltypename("[]val", getattr(valtype, DW_AT_name).data.(string), ""))
-
- newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*int64(valsize), 0)
- t = valtype
- if indirect_val {
- t = defptrto(valtype)
- }
- newrefattr(dwhv, DW_AT_type, t)
- fld = newdie(dwhv, DW_ABRV_ARRAYRANGE, "size")
- newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0)
- newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr"))
+ valname := nameFromDIESym(valtype)
+ dwhvs := mkinternaltype(DW_ABRV_ARRAYTYPE, "[]val", valname, "", func(dwhv *DWDie) {
+ newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*valsize, 0)
+ t := valtype
+ if indirect_val {
+ t = defptrto(valtype)
+ }
+ newrefattr(dwhv, DW_AT_type, t)
+ fld := newdie(dwhv, DW_ABRV_ARRAYRANGE, "size", 0)
+ newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0)
+ newrefattr(fld, DW_AT_type, mustFind("uintptr"))
+ })
// Construct bucket<K,V>
- dwhb := newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("bucket", getattr(keytype, DW_AT_name).data.(string), getattr(valtype, DW_AT_name).data.(string)))
-
- // Copy over all fields except the field "data" from the generic bucket.
- // "data" will be replaced with keys/values below.
- copychildrenexcept(dwhb, bucket, find(bucket, "data"))
+ dwhbs := mkinternaltype(DW_ABRV_STRUCTTYPE, "bucket", keyname, valname, func(dwhb *DWDie) {
+ // Copy over all fields except the field "data" from the generic
+ // bucket. "data" will be replaced with keys/values below.
+ copychildrenexcept(dwhb, bucket, findchild(bucket, "data"))
- fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys")
- newrefattr(fld, DW_AT_type, dwhk)
- newmemberoffsetattr(fld, BucketSize)
- fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "values")
- newrefattr(fld, DW_AT_type, dwhv)
- newmemberoffsetattr(fld, BucketSize+BucketSize*int32(keysize))
- fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "overflow")
- newrefattr(fld, DW_AT_type, defptrto(dwhb))
- newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize)))
- if Thearch.Regsize > Thearch.Ptrsize {
- fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad")
- newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr"))
- newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(Thearch.Ptrsize))
- }
+ fld := newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys", 0)
+ newrefattr(fld, DW_AT_type, dwhks)
+ newmemberoffsetattr(fld, BucketSize)
+ fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "values", 0)
+ newrefattr(fld, DW_AT_type, dwhvs)
+ newmemberoffsetattr(fld, BucketSize+BucketSize*int32(keysize))
+ fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "overflow", 0)
+ newrefattr(fld, DW_AT_type, defptrto(dwhb.sym))
+ newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize)))
+ if SysArch.RegSize > SysArch.PtrSize {
+ fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad", 0)
+ newrefattr(fld, DW_AT_type, mustFind("uintptr"))
+ newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(SysArch.PtrSize))
+ }
- newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize+BucketSize*int64(keysize)+BucketSize*int64(valsize)+int64(Thearch.Regsize), 0)
+ newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize+BucketSize*keysize+BucketSize*valsize+int64(SysArch.RegSize), 0)
+ })
// Construct hash<K,V>
- dwh := newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("hash", getattr(keytype, DW_AT_name).data.(string), getattr(valtype, DW_AT_name).data.(string)))
-
- copychildren(dwh, hash)
- substitutetype(dwh, "buckets", defptrto(dwhb))
- substitutetype(dwh, "oldbuckets", defptrto(dwhb))
- newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hash, DW_AT_byte_size).value, nil)
+ dwhs := mkinternaltype(DW_ABRV_STRUCTTYPE, "hash", keyname, valname, func(dwh *DWDie) {
+ copychildren(dwh, hash)
+ substitutetype(dwh, "buckets", defptrto(dwhbs))
+ substitutetype(dwh, "oldbuckets", defptrto(dwhbs))
+ newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hash, DW_AT_byte_size).value, nil)
+ })
// make map type a pointer to hash<K,V>
- newrefattr(die, DW_AT_type, defptrto(dwh))
+ newrefattr(die, DW_AT_type, defptrto(dwhs))
}
}
func synthesizechantypes(die *DWDie) {
- sudog := walktypedef(defgotype(lookup_or_diag("type.runtime.sudog")))
- waitq := walktypedef(defgotype(lookup_or_diag("type.runtime.waitq")))
- hchan := walktypedef(defgotype(lookup_or_diag("type.runtime.hchan")))
+ sudog := walktypedef(findprotodie("type.runtime.sudog"))
+ waitq := walktypedef(findprotodie("type.runtime.waitq"))
+ hchan := walktypedef(findprotodie("type.runtime.hchan"))
if sudog == nil || waitq == nil || hchan == nil {
return
}
@@ -1276,42 +1255,41 @@ func synthesizechantypes(die *DWDie) {
if die.abbrev != DW_ABRV_CHANTYPE {
continue
}
- elemsize := Thearch.Ptrsize
- elemtype := getattr(die, DW_AT_go_elem).data.(*DWDie)
- a := getattr(elemtype, DW_AT_byte_size)
- if a != nil {
- elemsize = int(a.value)
- }
+ elemgotype := getattr(die, DW_AT_type).data.(*LSym)
+ elemsize := decodetype_size(elemgotype)
+ elemname := elemgotype.Name[5:]
+ elemtype := walksymtypedef(defgotype(elemgotype))
// sudog<T>
- dws := newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("sudog", getattr(elemtype, DW_AT_name).data.(string), ""))
-
- copychildren(dws, sudog)
- substitutetype(dws, "elem", elemtype)
- if elemsize > 8 {
- elemsize -= 8
- } else {
- elemsize = 0
- }
- newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT, int64(sudogsize)+int64(elemsize), nil)
+ dwss := mkinternaltype(DW_ABRV_STRUCTTYPE, "sudog", elemname, "", func(dws *DWDie) {
+ copychildren(dws, sudog)
+ substitutetype(dws, "elem", elemtype)
+ if elemsize > 8 {
+ elemsize -= 8
+ } else {
+ elemsize = 0
+ }
+ newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT, int64(sudogsize)+elemsize, nil)
+ })
// waitq<T>
- dww := newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("waitq", getattr(elemtype, DW_AT_name).data.(string), ""))
+ dwws := mkinternaltype(DW_ABRV_STRUCTTYPE, "waitq", elemname, "", func(dww *DWDie) {
- copychildren(dww, waitq)
- substitutetype(dww, "first", defptrto(dws))
- substitutetype(dww, "last", defptrto(dws))
- newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(waitq, DW_AT_byte_size).value, nil)
+ copychildren(dww, waitq)
+ substitutetype(dww, "first", defptrto(dwss))
+ substitutetype(dww, "last", defptrto(dwss))
+ newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(waitq, DW_AT_byte_size).value, nil)
+ })
// hchan<T>
- dwh := newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("hchan", getattr(elemtype, DW_AT_name).data.(string), ""))
+ dwhs := mkinternaltype(DW_ABRV_STRUCTTYPE, "hchan", elemname, "", func(dwh *DWDie) {
+ copychildren(dwh, hchan)
+ substitutetype(dwh, "recvq", dwws)
+ substitutetype(dwh, "sendq", dwws)
+ newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hchan, DW_AT_byte_size).value, nil)
+ })
- copychildren(dwh, hchan)
- substitutetype(dwh, "recvq", dww)
- substitutetype(dwh, "sendq", dww)
- newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hchan, DW_AT_byte_size).value, nil)
-
- newrefattr(die, DW_AT_type, defptrto(dwh))
+ newrefattr(die, DW_AT_type, defptrto(dwhs))
}
}
@@ -1331,13 +1309,13 @@ func defdwsymb(sym *LSym, s string, t int, v int64, size int64, ver int, gotype
var dv *DWDie
- var dt *DWDie
+ var dt *LSym
switch t {
default:
return
case 'd', 'b', 'D', 'B':
- dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s)
+ dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s, ver)
newabslocexprattr(dv, v, sym)
if ver == 0 {
newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0)
@@ -1367,8 +1345,8 @@ func finddebugruntimepath(s *LSym) {
return
}
- for i := range s.Pcln.File {
- f := s.Pcln.File[i]
+ for i := range s.FuncInfo.File {
+ f := s.FuncInfo.File[i]
if i := strings.Index(f.Name, "runtime/runtime.go"); i >= 0 {
gdbscript = f.Name[:i] + "runtime/runtime-gdb.py"
break
@@ -1386,23 +1364,23 @@ const (
OPCODE_BASE = 10
)
-func putpclcdelta(delta_pc int64, delta_lc int64) {
+func putpclcdelta(s *LSym, delta_pc int64, delta_lc int64) {
if LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE {
var opcode int64 = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc)
if OPCODE_BASE <= opcode && opcode < 256 {
- Cput(uint8(opcode))
+ Adduint8(Ctxt, s, uint8(opcode))
return
}
}
if delta_pc != 0 {
- Cput(DW_LNS_advance_pc)
- sleb128put(delta_pc)
+ Adduint8(Ctxt, s, DW_LNS_advance_pc)
+ sleb128put(s, delta_pc)
}
- Cput(DW_LNS_advance_line)
- sleb128put(delta_lc)
- Cput(DW_LNS_copy)
+ Adduint8(Ctxt, s, DW_LNS_advance_line)
+ sleb128put(s, delta_lc)
+ Adduint8(Ctxt, s, DW_LNS_copy)
}
func newcfaoffsetattr(die *DWDie, offs int32) {
@@ -1428,26 +1406,6 @@ func mkvarname(name string, da int) string {
* Walk prog table, emit line program and build DIE tree.
*/
-// flush previous compilation unit.
-func flushunit(dwinfo *DWDie, pc int64, pcsym *LSym, unitstart int64, header_length int32) {
- if dwinfo != nil && pc != 0 {
- newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, pcsym)
- }
-
- if unitstart >= 0 {
- Cput(0) // start extended opcode
- uleb128put(1)
- Cput(DW_LNE_end_sequence)
-
- here := Cpos()
- Cseek(unitstart)
- Thearch.Lput(uint32(here - unitstart - 4)) // unit_length
- Thearch.Wput(2) // dwarf version
- Thearch.Lput(uint32(header_length)) // header length starting here
- Cseek(here)
- }
-}
-
func getCompilationDir() string {
if dir, err := os.Getwd(); err == nil {
return dir
@@ -1455,28 +1413,30 @@ func getCompilationDir() string {
return "/"
}
-func writelines() {
+func writelines(prev *LSym) *LSym {
if linesec == nil {
- linesec = Linklookup(Ctxt, ".dwarfline", 0)
+ linesec = Linklookup(Ctxt, ".debug_line", 0)
}
+ linesec.Type = obj.SDWARFSECT
linesec.R = linesec.R[:0]
+ ls := linesec
+ prev.Next = ls
+
unitstart := int64(-1)
+ headerstart := int64(-1)
headerend := int64(-1)
epc := int64(0)
var epcs *LSym
- lineo = Cpos()
var dwinfo *DWDie
- flushunit(dwinfo, epc, epcs, unitstart, int32(headerend-unitstart-10))
- unitstart = Cpos()
lang := DW_LANG_Go
- s := Ctxt.Textp
+ s := Ctxt.Textp[0]
- dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, "go")
+ dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, "go", 0)
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_stmt_list, DW_CLS_PTR, 0, 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()
@@ -1484,61 +1444,62 @@ func writelines() {
// Write .debug_line Line Number Program Header (sec 6.2.4)
// Fields marked with (*) must be changed for 64-bit dwarf
- Thearch.Lput(0) // unit_length (*), will be filled in by flushunit.
- Thearch.Wput(2) // dwarf version (appendix F)
- Thearch.Lput(0) // header_length (*), filled in by flushunit.
+ unit_length_offset := ls.Size
+ Adduint32(Ctxt, ls, 0) // unit_length (*), filled in at end.
+ unitstart = ls.Size
+ Adduint16(Ctxt, ls, 2) // dwarf version (appendix F)
+ header_length_offset := ls.Size
+ Adduint32(Ctxt, ls, 0) // header_length (*), filled in at end.
+ headerstart = ls.Size
// cpos == unitstart + 4 + 2 + 4
- Cput(1) // minimum_instruction_length
- Cput(1) // default_is_stmt
- Cput(LINE_BASE & 0xFF) // line_base
- Cput(LINE_RANGE) // line_range
- Cput(OPCODE_BASE) // opcode_base
- Cput(0) // standard_opcode_lengths[1]
- Cput(1) // standard_opcode_lengths[2]
- Cput(1) // standard_opcode_lengths[3]
- Cput(1) // standard_opcode_lengths[4]
- Cput(1) // standard_opcode_lengths[5]
- Cput(0) // standard_opcode_lengths[6]
- Cput(0) // standard_opcode_lengths[7]
- Cput(0) // standard_opcode_lengths[8]
- Cput(1) // standard_opcode_lengths[9]
- Cput(0) // include_directories (empty)
-
- files := make([]*LSym, Ctxt.Nhistfile)
+ Adduint8(Ctxt, ls, 1) // minimum_instruction_length
+ Adduint8(Ctxt, ls, 1) // default_is_stmt
+ Adduint8(Ctxt, ls, LINE_BASE&0xFF) // line_base
+ Adduint8(Ctxt, ls, LINE_RANGE) // line_range
+ Adduint8(Ctxt, ls, OPCODE_BASE) // opcode_base
+ Adduint8(Ctxt, ls, 0) // standard_opcode_lengths[1]
+ Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[2]
+ Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[3]
+ Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[4]
+ Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[5]
+ Adduint8(Ctxt, ls, 0) // standard_opcode_lengths[6]
+ Adduint8(Ctxt, ls, 0) // standard_opcode_lengths[7]
+ Adduint8(Ctxt, ls, 0) // standard_opcode_lengths[8]
+ Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[9]
+ Adduint8(Ctxt, ls, 0) // include_directories (empty)
- for f := Ctxt.Filesyms; f != nil; f = f.Next {
- files[f.Value-1] = f
- }
-
- for i := 0; int32(i) < Ctxt.Nhistfile; i++ {
- strnput(files[i].Name, len(files[i].Name)+4)
+ for _, f := range Ctxt.Filesyms {
+ Addstring(ls, f.Name)
+ Adduint8(Ctxt, ls, 0)
+ Adduint8(Ctxt, ls, 0)
+ Adduint8(Ctxt, ls, 0)
}
// 4 zeros: the string termination + 3 fields.
- Cput(0)
+ Adduint8(Ctxt, ls, 0)
// terminate file_names.
- headerend = Cpos()
+ headerend = ls.Size
- Cput(0) // start extended opcode
- uleb128put(1 + int64(Thearch.Ptrsize))
- Cput(DW_LNE_set_address)
+ Adduint8(Ctxt, ls, 0) // start extended opcode
+ uleb128put(ls, 1+int64(SysArch.PtrSize))
+ Adduint8(Ctxt, ls, DW_LNE_set_address)
pc := s.Value
line := 1
file := 1
if Linkmode == LinkExternal {
- adddwarfrel(linesec, s, lineo, Thearch.Ptrsize, 0)
+ Addaddr(Ctxt, ls, s)
} else {
- addrput(pc)
+ addrput(ls, pc)
}
var pcfile Pciter
var pcline Pciter
- for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
- s = Ctxt.Cursym
+ for _, Ctxt.Cursym = range Ctxt.Textp {
+ s := Ctxt.Cursym
- dwfunc := newdie(dwinfo, DW_ABRV_FUNCTION, s.Name)
+ dwfunc := newdie(dwinfo, DW_ABRV_FUNCTION, s.Name, int(s.Version))
newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s)
epc = s.Value + s.Size
epcs = s
@@ -1547,14 +1508,14 @@ func writelines() {
newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0)
}
- if s.Pcln == nil {
+ if s.FuncInfo == nil {
continue
}
finddebugruntimepath(s)
- pciterinit(Ctxt, &pcfile, &s.Pcln.Pcfile)
- pciterinit(Ctxt, &pcline, &s.Pcln.Pcline)
+ pciterinit(Ctxt, &pcfile, &s.FuncInfo.Pcfile)
+ pciterinit(Ctxt, &pcline, &s.FuncInfo.Pcline)
epc = pc
for pcfile.done == 0 && pcline.done == 0 {
if epc-s.Value >= int64(pcfile.nextpc) {
@@ -1568,12 +1529,12 @@ func writelines() {
}
if int32(file) != pcfile.value {
- Cput(DW_LNS_set_file)
- uleb128put(int64(pcfile.value))
+ Adduint8(Ctxt, ls, DW_LNS_set_file)
+ uleb128put(ls, int64(pcfile.value))
file = int(pcfile.value)
}
- putpclcdelta(s.Value+int64(pcline.pc)-pc, int64(pcline.value)-int64(line))
+ putpclcdelta(ls, s.Value+int64(pcline.pc)-pc, int64(pcline.value)-int64(line))
pc = s.Value + int64(pcline.pc)
line = int(pcline.value)
@@ -1589,13 +1550,13 @@ func writelines() {
dt, da int
offs int64
)
- for _, a := range s.Autom {
+ for _, a := range s.FuncInfo.Autom {
switch a.Name {
case obj.A_AUTO:
dt = DW_ABRV_AUTO
offs = int64(a.Aoffset)
if !haslinkregister() {
- offs -= int64(Thearch.Ptrsize)
+ offs -= int64(SysArch.PtrSize)
}
case obj.A_PARAM:
@@ -1610,7 +1571,7 @@ func writelines() {
continue
}
var n string
- if find(dwfunc, a.Asym.Name) != nil {
+ if findchild(dwfunc, a.Asym.Name) != nil {
n = mkvarname(a.Asym.Name, da)
} else {
n = a.Asym.Name
@@ -1621,7 +1582,7 @@ func writelines() {
n = n[i+1:]
}
- dwvar := newdie(dwfunc, dt, n)
+ dwvar := newdie(dwfunc, dt, n, 0)
newcfaoffsetattr(dwvar, int32(offs))
newrefattr(dwvar, DW_AT_type, defgotype(a.Gotype))
@@ -1642,22 +1603,29 @@ func writelines() {
}
}
- flushunit(dwinfo, epc, epcs, unitstart, int32(headerend-unitstart-10))
- linesize = Cpos() - lineo
+ Adduint8(Ctxt, ls, 0) // start extended opcode
+ uleb128put(ls, 1)
+ Adduint8(Ctxt, ls, DW_LNE_end_sequence)
+
+ newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, epc+1, epcs)
+
+ setuint32(Ctxt, ls, unit_length_offset, uint32(ls.Size-unitstart))
+ setuint32(Ctxt, ls, header_length_offset, uint32(headerend-headerstart))
+
+ return ls
}
/*
* Emit .debug_frame
*/
const (
- CIERESERVE = 16
- DATAALIGNMENTFACTOR = -4
+ dataAlignmentFactor = -4
)
// appendPCDeltaCFA appends per-PC CFA deltas to b and returns the final slice.
func appendPCDeltaCFA(b []byte, deltapc, cfa int64) []byte {
b = append(b, DW_CFA_def_cfa_offset_sf)
- b = appendSleb128(b, cfa/DATAALIGNMENTFACTOR)
+ b = appendSleb128(b, cfa/dataAlignmentFactor)
switch {
case deltapc < 0x40:
@@ -1675,60 +1643,68 @@ func appendPCDeltaCFA(b []byte, deltapc, cfa int64) []byte {
return b
}
-func writeframes() {
+func writeframes(prev *LSym) *LSym {
if framesec == nil {
- framesec = Linklookup(Ctxt, ".dwarfframe", 0)
+ framesec = Linklookup(Ctxt, ".debug_frame", 0)
}
+ framesec.Type = obj.SDWARFSECT
framesec.R = framesec.R[:0]
- frameo = Cpos()
+ fs := framesec
+ prev.Next = fs
// 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(int64(Thearch.Dwarfreglr)) // return_address_register
-
- Cput(DW_CFA_def_cfa)
-
- uleb128put(int64(Thearch.Dwarfregsp)) // register SP (**ABI-dependent, defined in l.h)
+ cieReserve := uint32(16)
if haslinkregister() {
- uleb128put(int64(0)) // offset
- } else {
- uleb128put(int64(Thearch.Ptrsize)) // offset
+ cieReserve = 32
}
+ Adduint32(Ctxt, fs, cieReserve) // initial length, must be multiple of pointer size
+ Adduint32(Ctxt, fs, 0xffffffff) // cid.
+ Adduint8(Ctxt, fs, 3) // dwarf version (appendix F)
+ Adduint8(Ctxt, fs, 0) // augmentation ""
+ uleb128put(fs, 1) // code_alignment_factor
+ sleb128put(fs, dataAlignmentFactor) // all CFI offset calculations include multiplication with this factor
+ uleb128put(fs, int64(Thearch.Dwarfreglr)) // return_address_register
- Cput(DW_CFA_offset_extended)
- uleb128put(int64(Thearch.Dwarfreglr)) // return address
+ Adduint8(Ctxt, fs, DW_CFA_def_cfa) // Set the current frame address..
+ uleb128put(fs, int64(Thearch.Dwarfregsp)) // ...to use the value in the platform's SP register (defined in l.go)...
if haslinkregister() {
- uleb128put(int64(0) / DATAALIGNMENTFACTOR) // at cfa - 0
+ uleb128put(fs, int64(0)) // ...plus a 0 offset.
+
+ Adduint8(Ctxt, fs, DW_CFA_same_value) // The platform's link register is unchanged during the prologue.
+ uleb128put(fs, int64(Thearch.Dwarfreglr))
+
+ Adduint8(Ctxt, fs, DW_CFA_val_offset) // The previous value...
+ uleb128put(fs, int64(Thearch.Dwarfregsp)) // ...of the platform's SP register...
+ uleb128put(fs, int64(0)) // ...is CFA+0.
} else {
- uleb128put(int64(-Thearch.Ptrsize) / DATAALIGNMENTFACTOR) // at cfa - x*4
+ uleb128put(fs, int64(SysArch.PtrSize)) // ...plus the word size (because the call instruction implicitly adds one word to the frame).
+
+ Adduint8(Ctxt, fs, DW_CFA_offset_extended) // The previous value...
+ uleb128put(fs, int64(Thearch.Dwarfreglr)) // ...of the return address...
+ uleb128put(fs, int64(-SysArch.PtrSize)/dataAlignmentFactor) // ...is saved at [CFA - (PtrSize/4)].
}
// 4 is to exclude the length field.
- pad := CIERESERVE + frameo + 4 - Cpos()
+ pad := int64(cieReserve) + 4 - fs.Size
if pad < 0 {
- Exitf("dwarf: CIERESERVE too small by %d bytes.", -pad)
+ Exitf("dwarf: cieReserve too small by %d bytes.", -pad)
}
- strnput("", int(pad))
+ Addbytes(Ctxt, fs, zeros[:pad])
var deltaBuf []byte
var pcsp Pciter
- for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
+ for _, Ctxt.Cursym = range Ctxt.Textp {
s := Ctxt.Cursym
- if s.Pcln == nil {
+ if s.FuncInfo == nil {
continue
}
// Emit a FDE, Section 6.4.1.
// First build the section contents into a byte buffer.
deltaBuf = deltaBuf[:0]
- for pciterinit(Ctxt, &pcsp, &s.Pcln.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
+ for pciterinit(Ctxt, &pcsp, &s.FuncInfo.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
nextpc := pcsp.nextpc
// pciterinit goes up to the end of the function,
@@ -1741,12 +1717,27 @@ func writeframes() {
}
if haslinkregister() {
+ // TODO(bryanpkc): This is imprecise. In general, the instruction
+ // that stores the return address to the stack frame is not the
+ // same one that allocates the frame.
+ if pcsp.value > 0 {
+ // The return address is preserved at (CFA-frame_size)
+ // after a stack frame has been allocated.
+ deltaBuf = append(deltaBuf, DW_CFA_offset_extended_sf)
+ deltaBuf = appendUleb128(deltaBuf, uint64(Thearch.Dwarfreglr))
+ deltaBuf = appendSleb128(deltaBuf, -int64(pcsp.value)/dataAlignmentFactor)
+ } else {
+ // The return address is restored into the link register
+ // when a stack frame has been de-allocated.
+ deltaBuf = append(deltaBuf, DW_CFA_same_value)
+ deltaBuf = appendUleb128(deltaBuf, uint64(Thearch.Dwarfreglr))
+ }
deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(pcsp.value))
} else {
- deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(Thearch.Ptrsize)+int64(pcsp.value))
+ deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(SysArch.PtrSize)+int64(pcsp.value))
}
}
- pad := int(Rnd(int64(len(deltaBuf)), int64(Thearch.Ptrsize))) - len(deltaBuf)
+ pad := int(Rnd(int64(len(deltaBuf)), int64(SysArch.PtrSize))) - len(deltaBuf)
deltaBuf = append(deltaBuf, zeros[:pad]...)
// Emit the FDE header, Section 6.4.1.
@@ -1754,21 +1745,17 @@ func writeframes() {
// 4 bytes: Pointer to the CIE above, at offset 0
// ptrsize: initial location
// ptrsize: address range
- Thearch.Lput(uint32(4 + 2*Thearch.Ptrsize + len(deltaBuf))) // length (excludes itself)
+ Adduint32(Ctxt, fs, uint32(4+2*SysArch.PtrSize+len(deltaBuf))) // length (excludes itself)
if Linkmode == LinkExternal {
- adddwarfrel(framesec, framesym, frameo, 4, 0) // CIE offset
- adddwarfrel(framesec, s, frameo, Thearch.Ptrsize, 0) // initial location
+ adddwarfref(Ctxt, fs, framesec, 4)
} else {
- Thearch.Lput(0) // CIE offset
- addrput(s.Value) // initial location
+ Adduint32(Ctxt, fs, 0) // CIE offset
}
- addrput(s.Size) // address range
-
- Cwrite(deltaBuf)
+ Addaddr(Ctxt, fs, s)
+ addrput(fs, s.Size) // address range
+ Addbytes(Ctxt, fs, deltaBuf)
}
-
- Cflush()
- framesize = Cpos() - frameo
+ return fs
}
/*
@@ -1778,12 +1765,14 @@ const (
COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
)
-func writeinfo() {
- fwdcount = 0
+func writeinfo(prev *LSym) *LSym {
if infosec == nil {
- infosec = Linklookup(Ctxt, ".dwarfinfo", 0)
+ infosec = Linklookup(Ctxt, ".debug_info", 0)
}
infosec.R = infosec.R[:0]
+ infosec.Type = obj.SDWARFINFO
+ infosec.Attr |= AttrReachable
+ prev.Next, prev = infosec, infosec
if arangessec == nil {
arangessec = Linklookup(Ctxt, ".dwarfaranges", 0)
@@ -1791,32 +1780,30 @@ func writeinfo() {
arangessec.R = arangessec.R[:0]
for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
- unitstart := Cpos()
+ s := compunit.sym
+ prev.Next, prev = s, s
// Write .debug_info Compilation Unit Header (sec 7.5.1)
// Fields marked with (*) must be changed for 64-bit dwarf
// This must match COMPUNITHEADERSIZE above.
- Thearch.Lput(0) // unit_length (*), will be filled in later.
- Thearch.Wput(2) // dwarf version (appendix F)
+ Adduint32(Ctxt, s, 0) // unit_length (*), will be filled in later.
+ Adduint16(Ctxt, s, 2) // dwarf version (appendix F)
// debug_abbrev_offset (*)
- if Linkmode == LinkExternal {
- adddwarfrel(infosec, abbrevsym, infoo, 4, 0)
- } else {
- Thearch.Lput(0)
- }
+ adddwarfref(Ctxt, s, abbrevsym, 4)
- Cput(uint8(Thearch.Ptrsize)) // address_size
+ Adduint8(Ctxt, s, uint8(SysArch.PtrSize)) // address_size
- putdie(compunit)
+ prev = putdie(prev, compunit)
+ cusize := s.Size - 4 // exclude the length field.
+ for child := s.Next; child != nil; child = child.Next {
+ cusize += child.Size
+ }
- here := Cpos()
- Cseek(unitstart)
- Thearch.Lput(uint32(here - unitstart - 4)) // exclude the length field.
- Cseek(here)
+ setuint32(Ctxt, s, 0, uint32(cusize))
+ newattr(compunit, DW_AT_byte_size, DW_CLS_CONSTANT, cusize, 0)
}
-
- Cflush()
+ return prev
}
/*
@@ -1837,51 +1824,52 @@ func ispubtype(die *DWDie) bool {
return die.abbrev >= DW_ABRV_NULLTYPE
}
-func writepub(ispub func(*DWDie) bool) int64 {
- sectionstart := Cpos()
+func writepub(sname string, ispub func(*DWDie) bool, prev *LSym) *LSym {
+ s := Linklookup(Ctxt, sname, 0)
+ s.Type = obj.SDWARFSECT
+ prev.Next = s
for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
- unitend := infoo + infosize
- unitstart := compunit.offs - COMPUNITHEADERSIZE
- if compunit.link != nil {
- unitend = compunit.link.offs - COMPUNITHEADERSIZE
- }
+ sectionstart := s.Size
+ culength := uint32(getattr(compunit, DW_AT_byte_size).value) + 4
// Write .debug_pubnames/types Header (sec 6.1.1)
- Thearch.Lput(0) // unit_length (*), will be filled in later.
- Thearch.Wput(2) // dwarf version (appendix F)
- Thearch.Lput(uint32(unitstart)) // debug_info_offset (of the Comp unit Header)
- Thearch.Lput(uint32(unitend - unitstart)) // debug_info_length
+ Adduint32(Ctxt, s, 0) // unit_length (*), will be filled in later.
+ Adduint16(Ctxt, s, 2) // dwarf version (appendix F)
+ adddwarfref(Ctxt, s, compunit.sym, 4) // debug_info_offset (of the Comp unit Header)
+ Adduint32(Ctxt, s, culength) // debug_info_length
for die := compunit.child; die != nil; die = die.link {
if !ispub(die) {
continue
}
- Thearch.Lput(uint32(die.offs - unitstart))
dwa := getattr(die, DW_AT_name)
- strnput(dwa.data.(string), int(dwa.value+1))
+ name := dwa.data.(string)
+ if die.sym == nil {
+ fmt.Println("Missing sym for ", name)
+ }
+ adddwarfref(Ctxt, s, die.sym, 4)
+ Addstring(s, name)
}
- Thearch.Lput(0)
+ Adduint32(Ctxt, s, 0)
- here := Cpos()
- Cseek(sectionstart)
- Thearch.Lput(uint32(here - sectionstart - 4)) // exclude the length field.
- Cseek(here)
+ setuint32(Ctxt, s, sectionstart, uint32(s.Size-sectionstart)-4) // exclude the length field.
}
- return sectionstart
+ return s
}
/*
* emit .debug_aranges. _info must have been written before,
* because we need die->offs of dw_globals.
*/
-func writearanges() int64 {
- sectionstart := Cpos()
+func writearanges(prev *LSym) *LSym {
+ s := Linklookup(Ctxt, ".debug_aranges", 0)
+ s.Type = obj.SDWARFSECT
// The first tuple is aligned to a multiple of the size of a single tuple
// (twice the size of an address)
- headersize := int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize*2))) // don't count unit_length field itself
+ headersize := int(Rnd(4+2+4+1+1, int64(SysArch.PtrSize*2))) // don't count unit_length field itself
for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
b := getattr(compunit, DW_AT_low_pc)
@@ -1894,78 +1882,46 @@ func writearanges() int64 {
}
// Write .debug_aranges Header + entry (sec 6.1.2)
- Thearch.Lput(uint32(headersize) + 4*uint32(Thearch.Ptrsize) - 4) // unit_length (*)
- Thearch.Wput(2) // dwarf version (appendix F)
+ unitlength := uint32(headersize) + 4*uint32(SysArch.PtrSize) - 4
+ Adduint32(Ctxt, s, unitlength) // unit_length (*)
+ Adduint16(Ctxt, s, 2) // dwarf version (appendix F)
- value := compunit.offs - COMPUNITHEADERSIZE // debug_info_offset
- if Linkmode == LinkExternal {
- adddwarfrel(arangessec, infosym, sectionstart, 4, value)
- } else {
- Thearch.Lput(uint32(value))
- }
+ adddwarfref(Ctxt, s, compunit.sym, 4)
- Cput(uint8(Thearch.Ptrsize)) // address_size
- Cput(0) // segment_size
- strnput("", headersize-(4+2+4+1+1)) // align to thearch.ptrsize
-
- if Linkmode == LinkExternal {
- adddwarfrel(arangessec, b.data.(*LSym), sectionstart, Thearch.Ptrsize, b.value-(b.data.(*LSym)).Value)
- } else {
- addrput(b.value)
+ Adduint8(Ctxt, s, uint8(SysArch.PtrSize)) // address_size
+ Adduint8(Ctxt, s, 0) // segment_size
+ padding := headersize - (4 + 2 + 4 + 1 + 1)
+ for i := 0; i < padding; i++ {
+ Adduint8(Ctxt, s, 0)
}
- addrput(e.value - b.value)
- addrput(0)
- addrput(0)
+ Addaddrplus(Ctxt, s, b.data.(*LSym), b.value-(b.data.(*LSym)).Value)
+ addrput(s, e.value-b.value)
+ addrput(s, 0)
+ addrput(s, 0)
}
-
- Cflush()
- return sectionstart
-}
-
-func writegdbscript() int64 {
- sectionstart := Cpos()
-
- if gdbscript != "" {
- Cput(1) // magic 1 byte?
- strnput(gdbscript, len(gdbscript)+1)
- Cflush()
+ if s.Size > 0 {
+ prev.Next = s
+ prev = s
}
-
- return sectionstart
+ return prev
}
-func align(size int64) {
- if HEADTYPE == obj.Hwindows { // Only Windows PE need section align.
- strnput("", int(Rnd(size, PEFILEALIGN)-size))
- }
-}
+func writegdbscript(prev *LSym) *LSym {
-func writedwarfreloc(s *LSym) int64 {
- start := Cpos()
- for ri := 0; ri < len(s.R); ri++ {
- r := &s.R[ri]
- i := -1
- if Iself {
- i = Thearch.Elfreloc1(r, int64(r.Off))
- } else if HEADTYPE == obj.Hdarwin {
- i = Thearch.Machoreloc1(r, int64(r.Off))
- }
- if i < 0 {
- Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
- }
+ if gdbscript != "" {
+ s := Linklookup(Ctxt, ".debug_gdb_scripts", 0)
+ s.Type = obj.SDWARFSECT
+ prev.Next = s
+ prev = s
+ Adduint8(Ctxt, s, 1) // magic 1 byte?
+ Addstring(s, gdbscript)
}
- return start
+ return prev
}
-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
-}
+var prototypedies map[string]*DWDie
/*
* This is the main entry point for generating dwarf. After emitting
@@ -1976,58 +1932,52 @@ func addmachodwarfsect(prev *Section, name string) *Section {
* passes.
*
*/
-func Dwarfemitdebugsections() {
+func dwarfgeneratedebugsyms() {
if Debug['w'] != 0 { // disable dwarf
return
}
+ if Debug['s'] != 0 && HEADTYPE != obj.Hdarwin {
+ return
+ }
+ if HEADTYPE == obj.Hplan9 {
+ 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.Attr |= AttrHidden
-
- abbrevsym = Linklookup(Ctxt, ".debug_abbrev", 0)
- abbrevsym.Attr |= AttrHidden
-
- linesym = Linklookup(Ctxt, ".debug_line", 0)
- linesym.Attr |= AttrHidden
+ }
- framesym = Linklookup(Ctxt, ".debug_frame", 0)
- framesym.Attr |= AttrHidden
- }
+ if Debug['v'] != 0 {
+ fmt.Fprintf(Bso, "%5.2f dwarf\n", obj.Cputime())
}
// For diagnostic messages.
newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, int64(len("dwtypes")), "dwtypes")
- mkindex(&dwroot)
- mkindex(&dwtypes)
- mkindex(&dwglobals)
-
// Some types that must exist to define other ones.
- newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>")
+ newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>", 0)
- newdie(&dwtypes, DW_ABRV_NULLTYPE, "void")
- newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer")
+ newdie(&dwtypes, DW_ABRV_NULLTYPE, "void", 0)
+ newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer", 0)
- die := newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr") // needed for array size
+ die := newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr", 0) // needed for array size
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0)
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, int64(Thearch.Ptrsize), 0)
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, int64(SysArch.PtrSize), 0)
newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, obj.KindUintptr, 0)
+ // Prototypes needed for type synthesis.
+ prototypedies = map[string]*DWDie{
+ "type.runtime.stringStructDWARF": nil,
+ "type.runtime.slice": nil,
+ "type.runtime.hmap": nil,
+ "type.runtime.bmap": nil,
+ "type.runtime.sudog": nil,
+ "type.runtime.waitq": nil,
+ "type.runtime.hchan": nil,
+ }
+
// Needed by the prettyprinter code for interface inspection.
defgotype(lookup_or_diag("type.runtime._type"))
@@ -2036,12 +1986,10 @@ func Dwarfemitdebugsections() {
genasmsym(defdwsymb)
- writeabbrev()
- align(abbrevsize)
- writelines()
- align(linesize)
- writeframes()
- align(framesize)
+ dwarfp = writeabbrev()
+ last := dwarfp
+ last = writelines(last)
+ last = writeframes(last)
synthesizestringtypes(dwtypes.child)
synthesizeslicetypes(dwtypes.child)
@@ -2055,412 +2003,61 @@ func Dwarfemitdebugsections() {
movetomodule(&dwtypes)
movetomodule(&dwglobals)
- infoo = Cpos()
- writeinfo()
- infoe := Cpos()
- pubnameso = infoe
- pubtypeso = infoe
- arangeso = infoe
- gdbscripto = infoe
-
- if fwdcount > 0 {
- if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "%5.2f dwarf pass 2.\n", obj.Cputime())
- }
- Cseek(infoo)
- writeinfo()
- if fwdcount > 0 {
- Exitf("dwarf: unresolved references after first dwarf info pass")
- }
-
- if infoe != Cpos() {
- Exitf("dwarf: inconsistent second dwarf info pass")
- }
- }
-
- infosize = infoe - infoo
- align(infosize)
-
- pubnameso = writepub(ispubname)
- pubnamessize = Cpos() - pubnameso
- align(pubnamessize)
-
- pubtypeso = writepub(ispubtype)
- pubtypessize = Cpos() - pubtypeso
- align(pubtypessize)
-
- arangeso = writearanges()
- arangessize = Cpos() - arangeso
- align(arangessize)
-
- gdbscripto = writegdbscript()
- gdbscriptsize = Cpos() - gdbscripto
- align(gdbscriptsize)
+ // Need to reorder symbols so SDWARFINFO is after all SDWARFSECT
+ // (but we need to generate dies before writepub)
+ writeinfo(last)
+ infosyms := last.Next
- 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)
-
- arangesreloco = writedwarfreloc(arangessec)
- arangesrelocsize = Cpos() - arangesreloco
- align(arangesrelocsize)
-
- linereloco = writedwarfreloc(linesec)
- linerelocsize = Cpos() - linereloco
- align(linerelocsize)
-
- framereloco = writedwarfreloc(framesec)
- framerelocsize = Cpos() - framereloco
- align(framerelocsize)
+ last = writepub(".debug_pubnames", ispubname, last)
+ last = writepub(".debug_pubtypes", ispubtype, last)
+ last = writearanges(last)
+ last = writegdbscript(last)
+ last.Next = infosyms
}
/*
* Elf.
*/
-const (
- ElfStrDebugAbbrev = iota
- ElfStrDebugAranges
- ElfStrDebugFrame
- ElfStrDebugInfo
- ElfStrDebugLine
- ElfStrDebugLoc
- ElfStrDebugMacinfo
- ElfStrDebugPubNames
- ElfStrDebugPubTypes
- ElfStrDebugRanges
- ElfStrDebugStr
- ElfStrGDBScripts
- ElfStrRelDebugInfo
- ElfStrRelDebugAranges
- ElfStrRelDebugLine
- ElfStrRelDebugFrame
- NElfStrDbg
-)
-
-var elfstrdbg [NElfStrDbg]int64
-
func dwarfaddshstrings(shstrtab *LSym) {
if Debug['w'] != 0 { // disable dwarf
return
}
- elfstrdbg[ElfStrDebugAbbrev] = Addstring(shstrtab, ".debug_abbrev")
- elfstrdbg[ElfStrDebugAranges] = Addstring(shstrtab, ".debug_aranges")
- elfstrdbg[ElfStrDebugFrame] = Addstring(shstrtab, ".debug_frame")
- elfstrdbg[ElfStrDebugInfo] = Addstring(shstrtab, ".debug_info")
- elfstrdbg[ElfStrDebugLine] = Addstring(shstrtab, ".debug_line")
- elfstrdbg[ElfStrDebugLoc] = Addstring(shstrtab, ".debug_loc")
- elfstrdbg[ElfStrDebugMacinfo] = Addstring(shstrtab, ".debug_macinfo")
- elfstrdbg[ElfStrDebugPubNames] = Addstring(shstrtab, ".debug_pubnames")
- elfstrdbg[ElfStrDebugPubTypes] = Addstring(shstrtab, ".debug_pubtypes")
- elfstrdbg[ElfStrDebugRanges] = Addstring(shstrtab, ".debug_ranges")
- elfstrdbg[ElfStrDebugStr] = Addstring(shstrtab, ".debug_str")
- elfstrdbg[ElfStrGDBScripts] = Addstring(shstrtab, ".debug_gdb_scripts")
+ Addstring(shstrtab, ".debug_abbrev")
+ Addstring(shstrtab, ".debug_aranges")
+ Addstring(shstrtab, ".debug_frame")
+ Addstring(shstrtab, ".debug_info")
+ Addstring(shstrtab, ".debug_line")
+ Addstring(shstrtab, ".debug_pubnames")
+ Addstring(shstrtab, ".debug_pubtypes")
+ Addstring(shstrtab, ".debug_gdb_scripts")
if Linkmode == LinkExternal {
- switch Thearch.Thechar {
- case '0', '6', '7', '9', 'z':
- elfstrdbg[ElfStrRelDebugInfo] = Addstring(shstrtab, ".rela.debug_info")
- elfstrdbg[ElfStrRelDebugAranges] = Addstring(shstrtab, ".rela.debug_aranges")
- elfstrdbg[ElfStrRelDebugLine] = Addstring(shstrtab, ".rela.debug_line")
- elfstrdbg[ElfStrRelDebugFrame] = Addstring(shstrtab, ".rela.debug_frame")
- default:
- elfstrdbg[ElfStrRelDebugInfo] = Addstring(shstrtab, ".rel.debug_info")
- elfstrdbg[ElfStrRelDebugAranges] = Addstring(shstrtab, ".rel.debug_aranges")
- elfstrdbg[ElfStrRelDebugLine] = Addstring(shstrtab, ".rel.debug_line")
- elfstrdbg[ElfStrRelDebugFrame] = Addstring(shstrtab, ".rel.debug_frame")
- }
-
- infosym = Linklookup(Ctxt, ".debug_info", 0)
- infosym.Attr |= AttrHidden
-
- abbrevsym = Linklookup(Ctxt, ".debug_abbrev", 0)
- abbrevsym.Attr |= AttrHidden
-
- linesym = Linklookup(Ctxt, ".debug_line", 0)
- linesym.Attr |= AttrHidden
-
- framesym = Linklookup(Ctxt, ".debug_frame", 0)
- framesym.Attr |= AttrHidden
+ Addstring(shstrtab, elfRelType+".debug_info")
+ Addstring(shstrtab, elfRelType+".debug_aranges")
+ Addstring(shstrtab, elfRelType+".debug_line")
+ Addstring(shstrtab, elfRelType+".debug_frame")
+ Addstring(shstrtab, elfRelType+".debug_pubnames")
+ Addstring(shstrtab, elfRelType+".debug_pubtypes")
}
}
-// Add section symbols for DWARF debug info. This is called before
+// Add section symbols for DWARF debug info. This is called before
// dwarfaddelfheaders.
func dwarfaddelfsectionsyms() {
- if infosym != nil {
- infosympos = Cpos()
- putelfsectionsym(infosym, 0)
- }
-
- if abbrevsym != nil {
- abbrevsympos = Cpos()
- putelfsectionsym(abbrevsym, 0)
- }
-
- if linesym != nil {
- linesympos = Cpos()
- putelfsectionsym(linesym, 0)
- }
-
- if framesym != nil {
- framesympos = Cpos()
- putelfsectionsym(framesym, 0)
- }
-}
-
-func dwarfaddelfrelocheader(elfstr int, shdata *ElfShdr, off int64, size int64) {
- sh := newElfShdr(elfstrdbg[elfstr])
- switch Thearch.Thechar {
- case '0', '6', '7', '9', 'z':
- sh.type_ = SHT_RELA
- default:
- sh.type_ = SHT_REL
- }
-
- sh.entsize = uint64(Thearch.Ptrsize) * 2
- if sh.type_ == SHT_RELA {
- sh.entsize += uint64(Thearch.Ptrsize)
- }
- sh.link = uint32(elfshname(".symtab").shnum)
- sh.info = uint32(shdata.shnum)
- sh.off = uint64(off)
- sh.size = uint64(size)
- sh.addralign = uint64(Thearch.Ptrsize)
-}
-
-func dwarfaddelfheaders() {
- if Debug['w'] != 0 { // disable dwarf
- return
- }
-
- sh := newElfShdr(elfstrdbg[ElfStrDebugAbbrev])
- sh.type_ = SHT_PROGBITS
- sh.off = uint64(abbrevo)
- sh.size = uint64(abbrevsize)
- sh.addralign = 1
- if abbrevsympos > 0 {
- putelfsymshndx(abbrevsympos, sh.shnum)
- }
-
- sh = newElfShdr(elfstrdbg[ElfStrDebugLine])
- sh.type_ = SHT_PROGBITS
- sh.off = uint64(lineo)
- sh.size = uint64(linesize)
- sh.addralign = 1
- if linesympos > 0 {
- putelfsymshndx(linesympos, sh.shnum)
- }
- shline := sh
-
- sh = newElfShdr(elfstrdbg[ElfStrDebugFrame])
- sh.type_ = SHT_PROGBITS
- sh.off = uint64(frameo)
- sh.size = uint64(framesize)
- sh.addralign = 1
- if framesympos > 0 {
- putelfsymshndx(framesympos, sh.shnum)
- }
- shframe := sh
-
- sh = newElfShdr(elfstrdbg[ElfStrDebugInfo])
- sh.type_ = SHT_PROGBITS
- sh.off = uint64(infoo)
- sh.size = uint64(infosize)
- sh.addralign = 1
- if infosympos > 0 {
- putelfsymshndx(infosympos, sh.shnum)
- }
- shinfo := sh
-
- if pubnamessize > 0 {
- sh := newElfShdr(elfstrdbg[ElfStrDebugPubNames])
- sh.type_ = SHT_PROGBITS
- sh.off = uint64(pubnameso)
- sh.size = uint64(pubnamessize)
- sh.addralign = 1
- }
-
- if pubtypessize > 0 {
- sh := newElfShdr(elfstrdbg[ElfStrDebugPubTypes])
- sh.type_ = SHT_PROGBITS
- sh.off = uint64(pubtypeso)
- sh.size = uint64(pubtypessize)
- sh.addralign = 1
- }
-
- var sharanges *ElfShdr
- if arangessize != 0 {
- sh := newElfShdr(elfstrdbg[ElfStrDebugAranges])
- sh.type_ = SHT_PROGBITS
- sh.off = uint64(arangeso)
- sh.size = uint64(arangessize)
- sh.addralign = 1
- sharanges = sh
- }
-
- if gdbscriptsize != 0 {
- sh := newElfShdr(elfstrdbg[ElfStrGDBScripts])
- sh.type_ = SHT_PROGBITS
- sh.off = uint64(gdbscripto)
- sh.size = uint64(gdbscriptsize)
- sh.addralign = 1
- }
-
- if inforelocsize != 0 {
- dwarfaddelfrelocheader(ElfStrRelDebugInfo, shinfo, inforeloco, inforelocsize)
- }
-
- if arangesrelocsize != 0 {
- dwarfaddelfrelocheader(ElfStrRelDebugAranges, sharanges, arangesreloco, arangesrelocsize)
- }
-
- if linerelocsize != 0 {
- dwarfaddelfrelocheader(ElfStrRelDebugLine, shline, linereloco, linerelocsize)
- }
-
- if framerelocsize != 0 {
- dwarfaddelfrelocheader(ElfStrRelDebugFrame, shframe, framereloco, framerelocsize)
- }
-}
-
-/*
- * Macho
- */
-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 := Rnd(int64(Segdwarf.Fileoff), 0x1000)
- addr := Segdata.Vaddr + Segdata.Length
-
- nsect := 4
- if pubnamessize > 0 {
- nsect++
- }
- if pubtypessize > 0 {
- nsect++
- }
- if arangessize > 0 {
- nsect++
- }
- if gdbscriptsize > 0 {
- nsect++
- }
-
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 = 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 = 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 = 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 = 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 = 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 = 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 = 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)
- if gdbscriptsize > 0 {
- msect := newMachoSect(ms, "__debug_gdb_scripts", "__DWARF")
- msect.off = uint32(gdbscripto)
- msect.size = uint64(gdbscriptsize)
- msect.addr = addr
- addr += msect.size
- msect.flag = 0x02000000
+ return
}
+ sym := Linklookup(Ctxt, ".debug_info", 0)
+ putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
+ sym = Linklookup(Ctxt, ".debug_abbrev", 0)
+ putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
+ sym = Linklookup(Ctxt, ".debug_line", 0)
+ putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
+ sym = Linklookup(Ctxt, ".debug_frame", 0)
+ putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
}
/*
@@ -2470,13 +2067,12 @@ func dwarfaddpeheaders() {
if Debug['w'] != 0 { // disable dwarf
return
}
-
- newPEDWARFSection(".debug_abbrev", abbrevsize)
- newPEDWARFSection(".debug_line", linesize)
- newPEDWARFSection(".debug_frame", framesize)
- newPEDWARFSection(".debug_info", infosize)
- newPEDWARFSection(".debug_pubnames", pubnamessize)
- newPEDWARFSection(".debug_pubtypes", pubtypessize)
- newPEDWARFSection(".debug_aranges", arangessize)
- newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize)
+ for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+ h := newPEDWARFSection(sect.Name, int64(sect.Length))
+ fileoff := sect.Vaddr - Segdwarf.Vaddr + Segdwarf.Fileoff
+ if uint64(h.PointerToRawData) != fileoff {
+ Diag("%s.PointerToRawData = %#x, want %#x", sect.Name, h.PointerToRawData, fileoff)
+ errorexit()
+ }
+ }
}
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index ffb7c4bdde..15b8d7af93 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -6,6 +6,7 @@ package ld
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"crypto/sha1"
"encoding/binary"
"encoding/hex"
@@ -866,25 +867,23 @@ var buildinfo []byte
func Elfinit() {
Iself = true
- switch Thearch.Thechar {
- case '0', '6', '7', '9', 'z':
+ if SysArch.InFamily(sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.S390X) {
elfRelType = ".rela"
- default:
+ } else {
elfRelType = ".rel"
}
- switch Thearch.Thechar {
+ switch SysArch.Family {
// 64-bit architectures
- case '9', 'z':
+ case sys.PPC64, sys.S390X:
if Ctxt.Arch.ByteOrder == binary.BigEndian {
ehdr.flags = 1 /* Version 1 ABI */
} else {
ehdr.flags = 2 /* Version 2 ABI */
}
fallthrough
-
- case '0', '6', '7':
- if Thearch.Thechar == '0' {
+ case sys.AMD64, sys.ARM64, sys.MIPS64:
+ if SysArch.Family == sys.MIPS64 {
ehdr.flags = 0x20000000 /* MIPS 3 */
}
elf64 = true
@@ -897,7 +896,7 @@ func Elfinit() {
// we use EABI on both linux/arm and freebsd/arm.
// 32-bit architectures
- case '5':
+ case sys.ARM:
// we use EABI on both linux/arm and freebsd/arm.
if HEADTYPE == obj.Hlinux || HEADTYPE == obj.Hfreebsd {
// We set a value here that makes no indication of which
@@ -911,7 +910,6 @@ func Elfinit() {
ehdr.flags = 0x5000002 // has entry point, Version5 EABI
}
fallthrough
-
default:
ehdr.phoff = ELF32HDRSIZE
/* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */
@@ -1432,7 +1430,7 @@ func elfdynhash() {
}
// s390x (ELF64) hash table entries are 8 bytes
- if Thearch.Thechar == 'z' {
+ if SysArch.Family == sys.S390X {
Adduint64(Ctxt, s, uint64(nbucket))
Adduint64(Ctxt, s, uint64(nsym))
for i := 0; i < nbucket; i++ {
@@ -1622,6 +1620,9 @@ func elfshbits(sect *Section) *ElfShdr {
sh.flags |= SHF_TLS
sh.type_ = SHT_NOBITS
}
+ if strings.HasPrefix(sect.Name, ".debug") {
+ sh.flags = 0
+ }
if Linkmode != LinkExternal {
sh.addr = sect.Vaddr
@@ -1657,19 +1658,19 @@ func elfshreloc(sect *Section) *ElfShdr {
sh := elfshname(elfRelType + sect.Name)
sh.type_ = uint32(typ)
- sh.entsize = uint64(Thearch.Regsize) * 2
+ sh.entsize = uint64(SysArch.RegSize) * 2
if typ == SHT_RELA {
- sh.entsize += uint64(Thearch.Regsize)
+ sh.entsize += uint64(SysArch.RegSize)
}
sh.link = uint32(elfshname(".symtab").shnum)
sh.info = uint32(sect.Elfsect.shnum)
sh.off = sect.Reloff
sh.size = sect.Rellen
- sh.addralign = uint64(Thearch.Regsize)
+ sh.addralign = uint64(SysArch.RegSize)
return sh
}
-func elfrelocsect(sect *Section, first *LSym) {
+func elfrelocsect(sect *Section, syms []*LSym) {
// If main section is SHT_NOBITS, nothing to relocate.
// Also nothing to relocate in .shstrtab.
if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
@@ -1680,20 +1681,18 @@ func elfrelocsect(sect *Section, first *LSym) {
}
sect.Reloff = uint64(Cpos())
- var sym *LSym
- for sym = first; sym != nil; sym = sym.Next {
- if !sym.Attr.Reachable() {
+ for i, s := range syms {
+ if !s.Attr.Reachable() {
continue
}
- if uint64(sym.Value) >= sect.Vaddr {
+ if uint64(s.Value) >= sect.Vaddr {
+ syms = syms[i:]
break
}
}
eaddr := int32(sect.Vaddr + sect.Length)
- var r *Reloc
- var ri int
- for ; sym != nil; sym = sym.Next {
+ for _, sym := range syms {
if !sym.Attr.Reachable() {
continue
}
@@ -1702,8 +1701,8 @@ func elfrelocsect(sect *Section, first *LSym) {
}
Ctxt.Cursym = sym
- for ri = 0; ri < len(sym.R); ri++ {
- r = &sym.R[ri]
+ for ri := 0; ri < len(sym.R); ri++ {
+ r := &sym.R[ri]
if r.Done != 0 {
continue
}
@@ -1711,7 +1710,6 @@ func elfrelocsect(sect *Section, first *LSym) {
Diag("missing xsym in relocation")
continue
}
-
if r.Xsym.ElfsymForReloc() == 0 {
Diag("reloc %d to non-elf symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
}
@@ -1739,6 +1737,9 @@ func Elfemitreloc() {
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
elfrelocsect(sect, datap)
}
+ for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+ elfrelocsect(sect, list2slice(dwarfp))
+ }
}
func addgonote(sectionName string, tag uint32, desc []byte) {
@@ -1866,7 +1867,7 @@ func doelf() {
Addstring(shstrtab, ".interp")
Addstring(shstrtab, ".hash")
Addstring(shstrtab, ".got")
- if Thearch.Thechar == '9' {
+ if SysArch.Family == sys.PPC64 {
Addstring(shstrtab, ".glink")
}
Addstring(shstrtab, ".got.plt")
@@ -1885,10 +1886,9 @@ func doelf() {
s.Type = obj.SELFROSECT
s.Attr |= AttrReachable
- switch Thearch.Thechar {
- case '0', '6', '7', '9', 'z':
+ if elf64 {
s.Size += ELF64SYMSIZE
- default:
+ } else {
s.Size += ELF32SYMSIZE
}
@@ -1914,7 +1914,7 @@ func doelf() {
s.Type = obj.SELFGOT // writable
/* ppc64 glink resolver */
- if Thearch.Thechar == '9' {
+ if SysArch.Family == sys.PPC64 {
s := Linklookup(Ctxt, ".glink", 0)
s.Attr |= AttrReachable
s.Type = obj.SELFRXSECT
@@ -1933,7 +1933,7 @@ func doelf() {
s = Linklookup(Ctxt, ".plt", 0)
s.Attr |= AttrReachable
- if Thearch.Thechar == '9' {
+ if SysArch.Family == sys.PPC64 {
// In the ppc64 ABI, .plt is a data section
// written by the dynamic linker.
s.Type = obj.SELFSECT
@@ -1967,10 +1967,9 @@ func doelf() {
elfwritedynentsym(s, DT_HASH, Linklookup(Ctxt, ".hash", 0))
elfwritedynentsym(s, DT_SYMTAB, Linklookup(Ctxt, ".dynsym", 0))
- switch Thearch.Thechar {
- case '0', '6', '7', '9', 'z':
+ if elf64 {
Elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE)
- default:
+ } else {
Elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE)
}
elfwritedynentsym(s, DT_STRTAB, Linklookup(Ctxt, ".dynstr", 0))
@@ -1989,15 +1988,15 @@ func doelf() {
Elfwritedynent(s, DT_RUNPATH, uint64(Addstring(dynstr, rpath.val)))
}
- if Thearch.Thechar == '9' {
+ if SysArch.Family == sys.PPC64 {
elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".plt", 0))
- } else if Thearch.Thechar == 'z' {
+ } else if SysArch.Family == sys.S390X {
elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".got", 0))
} else {
elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".got.plt", 0))
}
- if Thearch.Thechar == '9' {
+ if SysArch.Family == sys.PPC64 {
Elfwritedynent(s, DT_PPC64_OPT, 0)
}
@@ -2024,7 +2023,7 @@ func doelf() {
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))
+ addgonote(".note.go.pkg-list", ELF_NOTE_GOPKGLIST_TAG, pkglistfornote)
var deplist []string
for _, shlib := range Ctxt.Shlibs {
deplist = append(deplist, filepath.Base(shlib.Path))
@@ -2069,26 +2068,29 @@ func Asmbelfsetup() {
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
elfshalloc(sect)
}
+ for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+ elfshalloc(sect)
+ }
}
func Asmbelf(symo int64) {
eh := getElfEhdr()
- switch Thearch.Thechar {
+ switch SysArch.Family {
default:
- Exitf("unknown architecture in asmbelf: %v", Thearch.Thechar)
- case '0':
+ Exitf("unknown architecture in asmbelf: %v", SysArch.Family)
+ case sys.MIPS64:
eh.machine = EM_MIPS
- case '5':
+ case sys.ARM:
eh.machine = EM_ARM
- case '6':
+ case sys.AMD64:
eh.machine = EM_X86_64
- case '7':
+ case sys.ARM64:
eh.machine = EM_AARCH64
- case '8':
+ case sys.I386:
eh.machine = EM_386
- case '9':
+ case sys.PPC64:
eh.machine = EM_PPC64
- case 'z':
+ case sys.S390X:
eh.machine = EM_S390
}
@@ -2244,7 +2246,7 @@ func Asmbelf(symo int64) {
} else {
sh.entsize = ELF32SYMSIZE
}
- sh.addralign = uint64(Thearch.Regsize)
+ sh.addralign = uint64(SysArch.RegSize)
sh.link = uint32(elfshname(".dynstr").shnum)
// sh->info = index of first non-local symbol (number of local symbols)
@@ -2268,7 +2270,7 @@ func Asmbelf(symo int64) {
sh = elfshname(".gnu.version_r")
sh.type_ = SHT_GNU_VERNEED
sh.flags = SHF_ALLOC
- sh.addralign = uint64(Thearch.Regsize)
+ sh.addralign = uint64(SysArch.RegSize)
sh.info = uint32(elfverneed)
sh.link = uint32(elfshname(".dynstr").shnum)
shsym(sh, Linklookup(Ctxt, ".gnu.version_r", 0))
@@ -2279,7 +2281,7 @@ func Asmbelf(symo int64) {
sh.type_ = SHT_RELA
sh.flags = SHF_ALLOC
sh.entsize = ELF64RELASIZE
- sh.addralign = uint64(Thearch.Regsize)
+ sh.addralign = uint64(SysArch.RegSize)
sh.link = uint32(elfshname(".dynsym").shnum)
sh.info = uint32(elfshname(".plt").shnum)
shsym(sh, Linklookup(Ctxt, ".rela.plt", 0))
@@ -2343,15 +2345,15 @@ func Asmbelf(symo int64) {
sh := elfshname(".got")
sh.type_ = SHT_PROGBITS
sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = uint64(Thearch.Regsize)
- sh.addralign = uint64(Thearch.Regsize)
+ sh.entsize = uint64(SysArch.RegSize)
+ sh.addralign = uint64(SysArch.RegSize)
shsym(sh, Linklookup(Ctxt, ".got", 0))
sh = elfshname(".got.plt")
sh.type_ = SHT_PROGBITS
sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = uint64(Thearch.Regsize)
- sh.addralign = uint64(Thearch.Regsize)
+ sh.entsize = uint64(SysArch.RegSize)
+ sh.addralign = uint64(SysArch.RegSize)
shsym(sh, Linklookup(Ctxt, ".got.plt", 0))
}
@@ -2359,7 +2361,7 @@ func Asmbelf(symo int64) {
sh.type_ = SHT_HASH
sh.flags = SHF_ALLOC
sh.entsize = 4
- sh.addralign = uint64(Thearch.Regsize)
+ sh.addralign = uint64(SysArch.RegSize)
sh.link = uint32(elfshname(".dynsym").shnum)
shsym(sh, Linklookup(Ctxt, ".hash", 0))
@@ -2368,8 +2370,8 @@ func Asmbelf(symo int64) {
sh.type_ = SHT_DYNAMIC
sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = 2 * uint64(Thearch.Regsize)
- sh.addralign = uint64(Thearch.Regsize)
+ sh.entsize = 2 * uint64(SysArch.RegSize)
+ sh.addralign = uint64(SysArch.RegSize)
sh.link = uint32(elfshname(".dynstr").shnum)
shsym(sh, Linklookup(Ctxt, ".dynamic", 0))
ph := newElfPhdr()
@@ -2395,7 +2397,7 @@ func Asmbelf(symo int64) {
ph.type_ = PT_TLS
ph.flags = PF_R
ph.memsz = tlssize
- ph.align = uint64(Thearch.Regsize)
+ ph.align = uint64(SysArch.RegSize)
}
}
}
@@ -2404,12 +2406,12 @@ func Asmbelf(symo int64) {
ph := newElfPhdr()
ph.type_ = PT_GNU_STACK
ph.flags = PF_W + PF_R
- ph.align = uint64(Thearch.Regsize)
+ ph.align = uint64(SysArch.RegSize)
ph = newElfPhdr()
ph.type_ = PT_PAX_FLAGS
ph.flags = 0x2a00 // mprotect, randexec, emutramp disabled
- ph.align = uint64(Thearch.Regsize)
+ ph.align = uint64(SysArch.RegSize)
}
elfobj:
@@ -2434,6 +2436,9 @@ elfobj:
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
elfshbits(sect)
}
+ for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+ elfshbits(sect)
+ }
if Linkmode == LinkExternal {
for sect := Segtext.Sect; sect != nil; sect = sect.Next {
@@ -2445,7 +2450,14 @@ elfobj:
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
elfshreloc(sect)
}
-
+ for s := dwarfp; s != nil; s = s.Next {
+ if len(s.R) > 0 || s.Type == obj.SDWARFINFO {
+ elfshreloc(s.Sect)
+ }
+ if s.Type == obj.SDWARFINFO {
+ break
+ }
+ }
// add a .note.GNU-stack section to mark the stack as non-executable
sh := elfshname(".note.GNU-stack")
@@ -2459,8 +2471,8 @@ elfobj:
sh.type_ = SHT_SYMTAB
sh.off = uint64(symo)
sh.size = uint64(Symsize)
- sh.addralign = uint64(Thearch.Regsize)
- sh.entsize = 8 + 2*uint64(Thearch.Regsize)
+ sh.addralign = uint64(SysArch.RegSize)
+ sh.entsize = 8 + 2*uint64(SysArch.RegSize)
sh.link = uint32(elfshname(".strtab").shnum)
sh.info = uint32(elfglobalsymndx)
@@ -2469,8 +2481,6 @@ elfobj:
sh.off = uint64(symo) + uint64(Symsize)
sh.size = uint64(len(Elfstrdat))
sh.addralign = 1
-
- dwarfaddelfheaders()
}
/* Main header */
@@ -2585,7 +2595,7 @@ func Elfadddynsym(ctxt *Link, s *LSym) {
/* size of object */
Adduint64(ctxt, d, uint64(s.Size))
- if Thearch.Thechar == '6' && !s.Attr.CgoExportDynamic() && s.Dynimplib != "" && !seenlib[s.Dynimplib] {
+ if SysArch.Family == sys.AMD64 && !s.Attr.CgoExportDynamic() && s.Dynimplib != "" && !seenlib[s.Dynimplib] {
Elfwritedynent(Linklookup(ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(Linklookup(ctxt, ".dynstr", 0), s.Dynimplib)))
}
} else {
@@ -2613,9 +2623,9 @@ func Elfadddynsym(ctxt *Link, s *LSym) {
t := STB_GLOBAL << 4
// TODO(mwhudson): presumably the behaviour should actually be the same on both arm and 386.
- if Thearch.Thechar == '8' && s.Attr.CgoExport() && s.Type&obj.SMASK == obj.STEXT {
+ if SysArch.Family == sys.I386 && s.Attr.CgoExport() && s.Type&obj.SMASK == obj.STEXT {
t |= STT_FUNC
- } else if Thearch.Thechar == '5' && s.Attr.CgoExportDynamic() && s.Type&obj.SMASK == obj.STEXT {
+ } else if SysArch.Family == sys.ARM && s.Attr.CgoExportDynamic() && s.Type&obj.SMASK == obj.STEXT {
t |= STT_FUNC
} else {
t |= STT_OBJECT
diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go
index 027e05d845..425c75571f 100644
--- a/src/cmd/link/internal/ld/go.go
+++ b/src/cmd/link/internal/ld/go.go
@@ -8,8 +8,10 @@ package ld
import (
"bytes"
+ "cmd/internal/bio"
"cmd/internal/obj"
"fmt"
+ "io"
"os"
"strings"
)
@@ -26,7 +28,7 @@ func expandpkg(t0 string, pkg string) string {
// once the dust settles, try to move some code to
// libmach, so that other linkers and ar can share.
-func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int) {
+func ldpkg(f *bio.Reader, pkg string, length int64, filename string, whence int) {
var p0, p1 int
if Debug['g'] != 0 {
@@ -48,7 +50,7 @@ func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int)
}
bdata := make([]byte, length)
- if int64(obj.Bread(f, bdata)) != length {
+ if _, err := io.ReadFull(f, bdata); err != nil {
fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
if Debug['u'] != 0 {
errorexit()
@@ -418,35 +420,7 @@ type Pkg struct {
impby []*Pkg
}
-var (
- // pkgmap records the imported-by relationship between packages.
- // Entries are keyed by package path (e.g., "runtime" or "net/url").
- pkgmap = map[string]*Pkg{}
-
- pkgall []*Pkg
-)
-
-func lookupPkg(path string) *Pkg {
- if p, ok := pkgmap[path]; ok {
- return p
- }
- p := &Pkg{path: path}
- pkgmap[path] = p
- pkgall = append(pkgall, p)
- return p
-}
-
-// imported records that package pkg imports package imp.
-func imported(pkg, imp string) {
- // everyone imports runtime, even runtime.
- if imp == "runtime" {
- return
- }
-
- p := lookupPkg(pkg)
- i := lookupPkg(imp)
- i.impby = append(i.impby, p)
-}
+var pkgall []*Pkg
func (p *Pkg) cycle() *Pkg {
if p.checked {
diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go
index 0255331ac6..af60a5c85b 100644
--- a/src/cmd/link/internal/ld/ldelf.go
+++ b/src/cmd/link/internal/ld/ldelf.go
@@ -2,7 +2,9 @@ package ld
import (
"bytes"
+ "cmd/internal/bio"
"cmd/internal/obj"
+ "cmd/internal/sys"
"encoding/binary"
"fmt"
"io"
@@ -266,7 +268,7 @@ type ElfSect struct {
}
type ElfObj struct {
- f *obj.Biobuf
+ f *bio.Reader
base int64 // offset in f where ELF begins
length int64 // length of ELF
is64 int
@@ -403,7 +405,7 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) {
ehdr.flags = 0x5000202
}
if data[0] != 'A' {
- fmt.Fprintf(&Bso, ".ARM.attributes has unexpected format %c\n", data[0])
+ fmt.Fprintf(Bso, ".ARM.attributes has unexpected format %c\n", data[0])
return
}
data = data[1:]
@@ -414,7 +416,7 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) {
nulIndex := bytes.IndexByte(sectiondata, 0)
if nulIndex < 0 {
- fmt.Fprintf(&Bso, "corrupt .ARM.attributes (section name not NUL-terminated)\n")
+ fmt.Fprintf(Bso, "corrupt .ARM.attributes (section name not NUL-terminated)\n")
return
}
name := string(sectiondata[:nulIndex])
@@ -438,20 +440,20 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) {
}
}
if attrList.err != nil {
- fmt.Fprintf(&Bso, "could not parse .ARM.attributes\n")
+ fmt.Fprintf(Bso, "could not parse .ARM.attributes\n")
}
}
}
}
}
-func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
+func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "%5.2f ldelf %s\n", obj.Cputime(), pn)
+ fmt.Fprintf(Bso, "%5.2f ldelf %s\n", obj.Cputime(), pn)
}
Ctxt.IncVersion()
- base := int32(obj.Boffset(f))
+ base := f.Offset()
var add uint64
var e binary.ByteOrder
@@ -474,7 +476,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
var sect *ElfSect
var sym ElfSym
var symbols []*LSym
- if obj.Bread(f, hdrbuf[:]) != len(hdrbuf) {
+ if _, err := io.ReadFull(f, hdrbuf[:]); err != nil {
goto bad
}
hdr = new(ElfHdrBytes)
@@ -498,7 +500,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
elfobj.e = e
elfobj.f = f
- elfobj.base = int64(base)
+ elfobj.base = base
elfobj.length = length
elfobj.name = pn
@@ -546,47 +548,48 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
return
}
- switch Thearch.Thechar {
+ switch SysArch.Family {
default:
- Diag("%s: elf %s unimplemented", pn, Thestring)
+ Diag("%s: elf %s unimplemented", pn, SysArch.Name)
return
- case '0':
+ case sys.MIPS64:
if elfobj.machine != ElfMachMips || hdr.Ident[4] != ElfClass64 {
Diag("%s: elf object but not mips64", pn)
return
}
- case '5':
+ case sys.ARM:
if e != binary.LittleEndian || elfobj.machine != ElfMachArm || hdr.Ident[4] != ElfClass32 {
Diag("%s: elf object but not arm", pn)
return
}
- case '6':
+ case sys.AMD64:
if e != binary.LittleEndian || elfobj.machine != ElfMachAmd64 || hdr.Ident[4] != ElfClass64 {
Diag("%s: elf object but not amd64", pn)
return
}
- case '7':
+ case sys.ARM64:
if e != binary.LittleEndian || elfobj.machine != ElfMachArm64 || hdr.Ident[4] != ElfClass64 {
Diag("%s: elf object but not arm64", pn)
return
}
- case '8':
+ case sys.I386:
if e != binary.LittleEndian || elfobj.machine != ElfMach386 || hdr.Ident[4] != ElfClass32 {
Diag("%s: elf object but not 386", pn)
return
}
- case '9':
+ case sys.PPC64:
if elfobj.machine != ElfMachPower64 || hdr.Ident[4] != ElfClass64 {
Diag("%s: elf object but not ppc64", pn)
return
}
- case 'z':
+
+ case sys.S390X:
if elfobj.machine != ElfMachS390 || hdr.Ident[4] != ElfClass64 {
Diag("%s: elf object but not s390x", pn)
return
@@ -598,7 +601,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
elfobj.nsect = uint(elfobj.shnum)
for i := 0; uint(i) < elfobj.nsect; i++ {
- if obj.Bseek(f, int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 {
+ if f.Seek(int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 {
goto bad
}
sect = &elfobj.sect[i]
@@ -609,7 +612,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
goto bad
}
- sect.nameoff = uint32(e.Uint32(b.Name[:]))
+ sect.nameoff = e.Uint32(b.Name[:])
sect.type_ = e.Uint32(b.Type[:])
sect.flags = e.Uint64(b.Flags[:])
sect.addr = e.Uint64(b.Addr[:])
@@ -626,7 +629,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
goto bad
}
- sect.nameoff = uint32(e.Uint32(b.Name[:]))
+ sect.nameoff = e.Uint32(b.Name[:])
sect.type_ = e.Uint32(b.Type[:])
sect.flags = uint64(e.Uint32(b.Flags[:]))
sect.addr = uint64(e.Uint32(b.Addr[:]))
@@ -771,7 +774,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
if sym.sym == nil {
continue
}
- sect = &elfobj.sect[sym.shndx:][0]
+ sect = &elfobj.sect[sym.shndx]
if sect.sym == nil {
if strings.HasPrefix(sym.name, ".Linfo_string") { // clang does this
continue
@@ -839,19 +842,13 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
- if Ctxt.Etextp != nil {
- Ctxt.Etextp.Next = s
- } else {
- Ctxt.Textp = s
- }
- Ctxt.Etextp = s
+ Ctxt.Textp = append(Ctxt.Textp, s)
for s = s.Sub; s != nil; s = s.Sub {
if s.Attr.OnList() {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
- Ctxt.Etextp.Next = s
- Ctxt.Etextp = s
+ Ctxt.Textp = append(Ctxt.Textp, s)
}
}
}
@@ -925,7 +922,8 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
rp.Sym = sym.sym
}
- rp.Type = int32(reltype(pn, int(uint32(info)), &rp.Siz))
+ rp.Type = 256 + int32(info)
+ rp.Siz = relSize(pn, uint32(info))
if rela != 0 {
rp.Add = int64(add)
} else {
@@ -982,9 +980,11 @@ func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) {
}
sect.base = make([]byte, sect.size)
- err = fmt.Errorf("short read")
- if obj.Bseek(elfobj.f, int64(uint64(elfobj.base)+sect.off), 0) < 0 || obj.Bread(elfobj.f, sect.base) != len(sect.base) {
- return err
+ if elfobj.f.Seek(int64(uint64(elfobj.base)+sect.off), 0) < 0 {
+ return fmt.Errorf("short read: seek not successful")
+ }
+ if _, err := io.ReadFull(elfobj.f, sect.base); err != nil {
+ return fmt.Errorf("short read: %v", err)
}
return nil
@@ -1056,7 +1056,7 @@ func readelfsym(elfobj *ElfObj, i int, sym *ElfSym, needSym int) (err error) {
}
case ElfSymBindLocal:
- if Thearch.Thechar == '5' && (strings.HasPrefix(sym.name, "$a") || strings.HasPrefix(sym.name, "$d")) {
+ if SysArch.Family == sys.ARM && (strings.HasPrefix(sym.name, "$a") || strings.HasPrefix(sym.name, "$d")) {
// binutils for arm generate these mapping
// symbols, ignore these
break
@@ -1126,79 +1126,89 @@ func (x rbyoff) Less(i, j int) bool {
return false
}
-func reltype(pn string, elftype int, siz *uint8) int {
- switch uint32(Thearch.Thechar) | uint32(elftype)<<24 {
+func relSize(pn string, elftype uint32) uint8 {
+ // TODO(mdempsky): Replace this with a struct-valued switch statement
+ // once golang.org/issue/15164 is fixed or found to not impair cmd/link
+ // performance.
+
+ const (
+ AMD64 = uint32(sys.AMD64)
+ ARM = uint32(sys.ARM)
+ I386 = uint32(sys.I386)
+ PPC64 = uint32(sys.PPC64)
+ S390X = uint32(sys.S390X)
+ )
+
+ switch uint32(SysArch.Family) | elftype<<24 {
default:
Diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype)
fallthrough
- case 'z' | R_390_8:
- *siz = 1
+ case S390X | R_390_8<<24:
+ return 1
- case '9' | R_PPC64_TOC16<<24,
- '9' | R_PPC64_TOC16_LO<<24,
- '9' | R_PPC64_TOC16_HI<<24,
- '9' | R_PPC64_TOC16_HA<<24,
- '9' | R_PPC64_TOC16_DS<<24,
- '9' | R_PPC64_TOC16_LO_DS<<24,
- '9' | R_PPC64_REL16_LO<<24,
- '9' | R_PPC64_REL16_HI<<24,
- '9' | R_PPC64_REL16_HA<<24,
- 'z' | R_390_16<<24,
- 'z' | R_390_GOT16<<24,
- 'z' | R_390_PC16<<24,
- 'z' | R_390_PC16DBL<<24,
- 'z' | R_390_PLT16DBL<<24:
- *siz = 2
+ case PPC64 | R_PPC64_TOC16<<24,
+ PPC64 | R_PPC64_TOC16_LO<<24,
+ PPC64 | R_PPC64_TOC16_HI<<24,
+ PPC64 | R_PPC64_TOC16_HA<<24,
+ PPC64 | R_PPC64_TOC16_DS<<24,
+ PPC64 | R_PPC64_TOC16_LO_DS<<24,
+ PPC64 | R_PPC64_REL16_LO<<24,
+ PPC64 | R_PPC64_REL16_HI<<24,
+ PPC64 | R_PPC64_REL16_HA<<24,
+ S390X | R_390_16<<24,
+ S390X | R_390_GOT16<<24,
+ S390X | R_390_PC16<<24,
+ S390X | R_390_PC16DBL<<24,
+ S390X | R_390_PLT16DBL<<24:
+ return 2
- case '5' | R_ARM_ABS32<<24,
- '5' | R_ARM_GOT32<<24,
- '5' | R_ARM_PLT32<<24,
- '5' | R_ARM_GOTOFF<<24,
- '5' | R_ARM_GOTPC<<24,
- '5' | R_ARM_THM_PC22<<24,
- '5' | R_ARM_REL32<<24,
- '5' | R_ARM_CALL<<24,
- '5' | R_ARM_V4BX<<24,
- '5' | R_ARM_GOT_PREL<<24,
- '5' | R_ARM_PC24<<24,
- '5' | R_ARM_JUMP24<<24,
- '6' | R_X86_64_PC32<<24,
- '6' | R_X86_64_PLT32<<24,
- '6' | R_X86_64_GOTPCREL<<24,
- '6' | R_X86_64_GOTPCRELX<<24,
- '6' | R_X86_64_REX_GOTPCRELX<<24,
- '8' | R_386_32<<24,
- '8' | R_386_PC32<<24,
- '8' | R_386_GOT32<<24,
- '8' | R_386_PLT32<<24,
- '8' | R_386_GOTOFF<<24,
- '8' | R_386_GOTPC<<24,
- '8' | R_386_GOT32X<<24,
- '9' | R_PPC64_REL24<<24,
- '9' | R_PPC_REL32<<24,
- 'z' | R_390_32<<24,
- 'z' | R_390_PC32<<24,
- 'z' | R_390_GOT32<<24,
- 'z' | R_390_PLT32<<24,
- 'z' | R_390_PC32DBL<<24,
- 'z' | R_390_PLT32DBL<<24,
- 'z' | R_390_GOTPCDBL<<24,
- 'z' | R_390_GOTENT<<24:
- *siz = 4
+ case ARM | R_ARM_ABS32<<24,
+ ARM | R_ARM_GOT32<<24,
+ ARM | R_ARM_PLT32<<24,
+ ARM | R_ARM_GOTOFF<<24,
+ ARM | R_ARM_GOTPC<<24,
+ ARM | R_ARM_THM_PC22<<24,
+ ARM | R_ARM_REL32<<24,
+ ARM | R_ARM_CALL<<24,
+ ARM | R_ARM_V4BX<<24,
+ ARM | R_ARM_GOT_PREL<<24,
+ ARM | R_ARM_PC24<<24,
+ ARM | R_ARM_JUMP24<<24,
+ AMD64 | R_X86_64_PC32<<24,
+ AMD64 | R_X86_64_PLT32<<24,
+ AMD64 | R_X86_64_GOTPCREL<<24,
+ AMD64 | R_X86_64_GOTPCRELX<<24,
+ AMD64 | R_X86_64_REX_GOTPCRELX<<24,
+ I386 | R_386_32<<24,
+ I386 | R_386_PC32<<24,
+ I386 | R_386_GOT32<<24,
+ I386 | R_386_PLT32<<24,
+ I386 | R_386_GOTOFF<<24,
+ I386 | R_386_GOTPC<<24,
+ I386 | R_386_GOT32X<<24,
+ PPC64 | R_PPC64_REL24<<24,
+ PPC64 | R_PPC_REL32<<24,
+ S390X | R_390_32<<24,
+ S390X | R_390_PC32<<24,
+ S390X | R_390_GOT32<<24,
+ S390X | R_390_PLT32<<24,
+ S390X | R_390_PC32DBL<<24,
+ S390X | R_390_PLT32DBL<<24,
+ S390X | R_390_GOTPCDBL<<24,
+ S390X | R_390_GOTENT<<24:
+ return 4
- case '6' | R_X86_64_64<<24,
- '9' | R_PPC64_ADDR64<<24,
- 'z' | R_390_GLOB_DAT<<24,
- 'z' | R_390_RELATIVE<<24,
- 'z' | R_390_GOTOFF<<24,
- 'z' | R_390_GOTPC<<24,
- 'z' | R_390_64<<24,
- 'z' | R_390_PC64<<24,
- 'z' | R_390_GOT64<<24,
- 'z' | R_390_PLT64<<24:
- *siz = 8
+ case AMD64 | R_X86_64_64<<24,
+ PPC64 | R_PPC64_ADDR64<<24,
+ S390X | R_390_GLOB_DAT<<24,
+ S390X | R_390_RELATIVE<<24,
+ S390X | R_390_GOTOFF<<24,
+ S390X | R_390_GOTPC<<24,
+ S390X | R_390_64<<24,
+ S390X | R_390_PC64<<24,
+ S390X | R_390_GOT64<<24,
+ S390X | R_390_PLT64<<24:
+ return 8
}
-
- return 256 + elftype
}
diff --git a/src/cmd/link/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go
index c4c13f13b9..a10124907c 100644
--- a/src/cmd/link/internal/ld/ldmacho.go
+++ b/src/cmd/link/internal/ld/ldmacho.go
@@ -1,9 +1,12 @@
package ld
import (
+ "cmd/internal/bio"
"cmd/internal/obj"
+ "cmd/internal/sys"
"encoding/binary"
"fmt"
+ "io"
"log"
"sort"
)
@@ -41,7 +44,7 @@ const (
)
type LdMachoObj struct {
- f *obj.Biobuf
+ f *bio.Reader
base int64 // off in f where Mach-O begins
length int64 // length of Mach-O
is64 bool
@@ -297,7 +300,10 @@ func macholoadrel(m *LdMachoObj, sect *LdMachoSect) int {
rel := make([]LdMachoRel, sect.nreloc)
n := int(sect.nreloc * 8)
buf := make([]byte, n)
- if obj.Bseek(m.f, m.base+int64(sect.reloff), 0) < 0 || obj.Bread(m.f, buf) != n {
+ if m.f.Seek(m.base+int64(sect.reloff), 0) < 0 {
+ return -1
+ }
+ if _, err := io.ReadFull(m.f, buf); err != nil {
return -1
}
var p []byte
@@ -343,7 +349,10 @@ func macholoaddsym(m *LdMachoObj, d *LdMachoDysymtab) int {
n := int(d.nindirectsyms)
p := make([]byte, n*4)
- if obj.Bseek(m.f, m.base+int64(d.indirectsymoff), 0) < 0 || obj.Bread(m.f, p) != len(p) {
+ if m.f.Seek(m.base+int64(d.indirectsymoff), 0) < 0 {
+ return -1
+ }
+ if _, err := io.ReadFull(m.f, p); err != nil {
return -1
}
@@ -360,7 +369,10 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
}
strbuf := make([]byte, symtab.strsize)
- if obj.Bseek(m.f, m.base+int64(symtab.stroff), 0) < 0 || obj.Bread(m.f, strbuf) != len(strbuf) {
+ if m.f.Seek(m.base+int64(symtab.stroff), 0) < 0 {
+ return -1
+ }
+ if _, err := io.ReadFull(m.f, strbuf); err != nil {
return -1
}
@@ -370,7 +382,10 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
}
n := int(symtab.nsym * uint32(symsize))
symbuf := make([]byte, n)
- if obj.Bseek(m.f, m.base+int64(symtab.symoff), 0) < 0 || obj.Bread(m.f, symbuf) != len(symbuf) {
+ if m.f.Seek(m.base+int64(symtab.symoff), 0) < 0 {
+ return -1
+ }
+ if _, err := io.ReadFull(m.f, symbuf); err != nil {
return -1
}
sym := make([]LdMachoSym, symtab.nsym)
@@ -384,8 +399,8 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
return -1
}
s.name = cstring(strbuf[v:])
- s.type_ = uint8(p[4])
- s.sectnum = uint8(p[5])
+ s.type_ = p[4]
+ s.sectnum = p[5]
s.desc = m.e.Uint16(p[6:])
if m.is64 {
s.value = m.e.Uint64(p[8:])
@@ -400,7 +415,7 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
return 0
}
-func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
+func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
var err error
var j int
var is64 bool
@@ -430,8 +445,8 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
var name string
Ctxt.IncVersion()
- base := obj.Boffset(f)
- if obj.Bread(f, hdr[:]) != len(hdr) {
+ base := f.Offset()
+ if _, err := io.ReadFull(f, hdr[:]); err != nil {
goto bad
}
@@ -445,44 +460,43 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
}
is64 = e.Uint32(hdr[:]) == 0xFEEDFACF
- ncmd = e.Uint32([]byte(hdr[4*4:]))
- cmdsz = e.Uint32([]byte(hdr[5*4:]))
+ ncmd = e.Uint32(hdr[4*4:])
+ cmdsz = e.Uint32(hdr[5*4:])
if ncmd > 0x10000 || cmdsz >= 0x01000000 {
err = fmt.Errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz)
goto bad
}
if is64 {
- var tmp [4]uint8
- obj.Bread(f, tmp[:4]) // skip reserved word in header
+ f.Seek(4, 1) // skip reserved word in header
}
m = new(LdMachoObj)
m.f = f
m.e = e
- m.cputype = uint(e.Uint32([]byte(hdr[1*4:])))
- m.subcputype = uint(e.Uint32([]byte(hdr[2*4:])))
- m.filetype = e.Uint32([]byte(hdr[3*4:]))
+ m.cputype = uint(e.Uint32(hdr[1*4:]))
+ m.subcputype = uint(e.Uint32(hdr[2*4:]))
+ m.filetype = e.Uint32(hdr[3*4:])
m.ncmd = uint(ncmd)
- m.flags = e.Uint32([]byte(hdr[6*4:]))
+ m.flags = e.Uint32(hdr[6*4:])
m.is64 = is64
m.base = base
m.length = length
m.name = pn
- switch Thearch.Thechar {
+ switch SysArch.Family {
default:
- Diag("%s: mach-o %s unimplemented", pn, Thestring)
+ Diag("%s: mach-o %s unimplemented", pn, SysArch.Name)
return
- case '6':
+ case sys.AMD64:
if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
Diag("%s: mach-o object but not amd64", pn)
return
}
- case '8':
+ case sys.I386:
if e != binary.LittleEndian || m.cputype != LdMachoCpu386 {
Diag("%s: mach-o object but not 386", pn)
return
@@ -492,7 +506,7 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
m.cmd = make([]LdMachoCmd, ncmd)
off = uint32(len(hdr))
cmdp = make([]byte, cmdsz)
- if obj.Bread(f, cmdp) != len(cmdp) {
+ if _, err2 := io.ReadFull(f, cmdp); err2 != nil {
err = fmt.Errorf("reading cmds: %v", err)
goto bad
}
@@ -555,7 +569,11 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
}
dat = make([]byte, c.seg.filesz)
- if obj.Bseek(f, m.base+int64(c.seg.fileoff), 0) < 0 || obj.Bread(f, dat) != len(dat) {
+ if f.Seek(m.base+int64(c.seg.fileoff), 0) < 0 {
+ err = fmt.Errorf("cannot load object data: %v", err)
+ goto bad
+ }
+ if _, err2 := io.ReadFull(f, dat); err2 != nil {
err = fmt.Errorf("cannot load object data: %v", err)
goto bad
}
@@ -689,19 +707,13 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
- if Ctxt.Etextp != nil {
- Ctxt.Etextp.Next = s
- } else {
- Ctxt.Textp = s
- }
- Ctxt.Etextp = s
+ Ctxt.Textp = append(Ctxt.Textp, s)
for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
if s1.Attr.OnList() {
log.Fatalf("symbol %s listed multiple times", s1.Name)
}
s1.Attr |= AttrOnList
- Ctxt.Etextp.Next = s1
- Ctxt.Etextp = s1
+ Ctxt.Textp = append(Ctxt.Textp, s1)
}
}
}
@@ -724,10 +736,9 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
rp = &r[rpi]
rel = &sect.rel[j]
if rel.scattered != 0 {
- if Thearch.Thechar != '8' {
+ if SysArch.Family != sys.I386 {
// mach-o only uses scattered relocation on 32-bit platforms
Diag("unexpected scattered relocation")
-
continue
}
@@ -821,7 +832,7 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
rp.Off = int32(rel.addr)
// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
- if Thearch.Thechar == '6' && rel.extrn == 0 && rel.type_ == 1 {
+ if SysArch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == 1 {
// Calculate the addend as the offset into the section.
//
// The rip-relative offset stored in the object file is encoded
@@ -847,7 +858,7 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
// For i386 Mach-O PC-relative, the addend is written such that
// it *is* the PC being subtracted. Use that to make
// it match our version of PC-relative.
- if rel.pcrel != 0 && Thearch.Thechar == '8' {
+ if rel.pcrel != 0 && SysArch.Family == sys.I386 {
rp.Add += int64(rp.Off) + int64(rp.Siz)
}
if rel.extrn == 0 {
@@ -866,7 +877,7 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
// include that information in the addend.
// We only care about the delta from the
// section base.
- if Thearch.Thechar == '8' {
+ if SysArch.Family == sys.I386 {
rp.Add -= int64(c.seg.sect[rel.symnum-1].addr)
}
} else {
diff --git a/src/cmd/link/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go
index 5c3e99c44f..7eb26bcbe8 100644
--- a/src/cmd/link/internal/ld/ldpe.go
+++ b/src/cmd/link/internal/ld/ldpe.go
@@ -5,9 +5,12 @@
package ld
import (
+ "cmd/internal/bio"
"cmd/internal/obj"
+ "cmd/internal/sys"
"encoding/binary"
"fmt"
+ "io"
"log"
"sort"
"strconv"
@@ -116,7 +119,7 @@ type PeSect struct {
}
type PeObj struct {
- f *obj.Biobuf
+ f *bio.Reader
name string
base uint32
sect []PeSect
@@ -127,14 +130,14 @@ type PeObj struct {
snames []byte
}
-func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
+func ldpe(f *bio.Reader, pkg string, length int64, pn string) {
if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn)
+ fmt.Fprintf(Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn)
}
var sect *PeSect
Ctxt.IncVersion()
- base := int32(obj.Boffset(f))
+ base := f.Offset()
peobj := new(PeObj)
peobj.f = f
@@ -172,15 +175,15 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
// TODO return error if found .cormeta
// load string table
- obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
+ f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
- if obj.Bread(f, symbuf[:4]) != 4 {
+ if _, err := io.ReadFull(f, symbuf[:4]); err != nil {
goto bad
}
l = Le32(symbuf[:])
peobj.snames = make([]byte, l)
- obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
- if obj.Bread(f, peobj.snames) != len(peobj.snames) {
+ f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
+ if _, err := io.ReadFull(f, peobj.snames); err != nil {
goto bad
}
@@ -200,10 +203,10 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
peobj.pesym = make([]PeSym, peobj.fh.NumberOfSymbols)
peobj.npesym = uint(peobj.fh.NumberOfSymbols)
- obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable), 0)
+ f.Seek(base+int64(peobj.fh.PointerToSymbolTable), 0)
for i := 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 {
- obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0)
- if obj.Bread(f, symbuf[:]) != len(symbuf) {
+ f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0)
+ if _, err := io.ReadFull(f, symbuf[:]); err != nil {
goto bad
}
@@ -288,10 +291,10 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
}
r = make([]Reloc, rsect.sh.NumberOfRelocations)
- obj.Bseek(f, int64(peobj.base)+int64(rsect.sh.PointerToRelocations), 0)
+ f.Seek(int64(peobj.base)+int64(rsect.sh.PointerToRelocations), 0)
for j = 0; j < int(rsect.sh.NumberOfRelocations); j++ {
rp = &r[j]
- if obj.Bread(f, symbuf[:10]) != 10 {
+ if _, err := io.ReadFull(f, symbuf[:10]); err != nil {
goto bad
}
rva := Le32(symbuf[0:])
@@ -432,19 +435,13 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
- if Ctxt.Etextp != nil {
- Ctxt.Etextp.Next = s
- } else {
- Ctxt.Textp = s
- }
- Ctxt.Etextp = s
+ Ctxt.Textp = append(Ctxt.Textp, s)
for s = s.Sub; s != nil; s = s.Sub {
if s.Attr.OnList() {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
- Ctxt.Etextp.Next = s
- Ctxt.Etextp = s
+ Ctxt.Textp = append(Ctxt.Textp, s)
}
}
}
@@ -464,7 +461,10 @@ func pemap(peobj *PeObj, sect *PeSect) int {
if sect.sh.PointerToRawData == 0 { // .bss doesn't have data in object file
return 0
}
- if obj.Bseek(peobj.f, int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 || obj.Bread(peobj.f, sect.base) != len(sect.base) {
+ if peobj.f.Seek(int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 {
+ return -1
+ }
+ if _, err := io.ReadFull(peobj.f, sect.base); err != nil {
return -1
}
@@ -492,7 +492,7 @@ func readpesym(peobj *PeObj, i int, y **PeSym) (err error) {
if strings.HasPrefix(name, "__imp_") {
name = name[6:] // __imp_Name => Name
}
- if Thearch.Thechar == '8' && name[0] == '_' {
+ if SysArch.Family == sys.I386 && name[0] == '_' {
name = name[1:] // _Name => Name
}
}
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 5616700445..53428bb1c6 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -33,7 +33,9 @@ package ld
import (
"bufio"
"bytes"
+ "cmd/internal/bio"
"cmd/internal/obj"
+ "cmd/internal/sys"
"crypto/sha1"
"debug/elf"
"encoding/binary"
@@ -82,14 +84,9 @@ import (
// THE SOFTWARE.
type Arch struct {
- Thechar int
- Ptrsize int
- Intsize int
- Regsize int
Funcalign int
Maxalign int
Minalign int
- Minlc int
Dwarfregsp int
Dwarfreglr int
Linuxdynld string
@@ -133,7 +130,6 @@ func (r *Rpath) String() string {
var (
Thearch Arch
- datap *LSym
Debug [128]int
Lcsize int32
rpath Rpath
@@ -191,8 +187,7 @@ func UseRelro() bool {
}
var (
- Thestring string
- Thelinkarch *LinkArch
+ SysArch *sys.Arch
outfile string
dynexp []*LSym
dynlib []string
@@ -201,6 +196,7 @@ var (
Funcalign int
iscgo bool
elfglobalsymndx int
+ flag_dumpdep bool
flag_installsuffix string
flag_race int
flag_msan int
@@ -245,9 +241,10 @@ const (
var (
headstring string
// buffered output
- Bso obj.Biobuf
+ Bso *bufio.Writer
)
+// TODO(dfc) outBuf duplicates bio.Writer
type outBuf struct {
w *bufio.Writer
f *os.File
@@ -472,7 +469,7 @@ func loadinternal(name string) {
if Linkshared {
shlibname := filepath.Join(Ctxt.Libdir[i], name+".shlibname")
if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, shlibname)
+ fmt.Fprintf(Bso, "searching for %s.a in %s\n", name, shlibname)
}
if _, err := os.Stat(shlibname); err == nil {
addlibpath(Ctxt, "internal", "internal", "", name, shlibname)
@@ -482,7 +479,7 @@ func loadinternal(name string) {
}
pname := filepath.Join(Ctxt.Libdir[i], name+".a")
if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, pname)
+ fmt.Fprintf(Bso, "searching for %s.a in %s\n", name, pname)
}
if _, err := os.Stat(pname); err == nil {
addlibpath(Ctxt, "internal", "internal", pname, name, "")
@@ -492,7 +489,7 @@ func loadinternal(name string) {
}
if found == 0 {
- fmt.Fprintf(&Bso, "warning: unable to find %s.a\n", name)
+ fmt.Fprintf(Bso, "warning: unable to find %s.a\n", name)
}
}
@@ -509,7 +506,7 @@ func loadlib() {
}
loadinternal("runtime")
- if Thearch.Thechar == '5' {
+ if SysArch.Family == sys.ARM {
loadinternal("math")
}
if flag_race != 0 {
@@ -524,7 +521,7 @@ func loadlib() {
iscgo = iscgo || Ctxt.Library[i].Pkg == "runtime/cgo"
if Ctxt.Library[i].Shlib == "" {
if Debug['v'] > 1 {
- fmt.Fprintf(&Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].File, Ctxt.Library[i].Objref)
+ fmt.Fprintf(Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].File, Ctxt.Library[i].Objref)
}
objfile(Ctxt.Library[i])
}
@@ -533,7 +530,7 @@ func loadlib() {
for i = 0; i < len(Ctxt.Library); i++ {
if Ctxt.Library[i].Shlib != "" {
if Debug['v'] > 1 {
- fmt.Fprintf(&Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].Shlib, Ctxt.Library[i].Objref)
+ fmt.Fprintf(Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].Shlib, Ctxt.Library[i].Objref)
}
ldshlibsyms(Ctxt.Library[i].Shlib)
}
@@ -562,7 +559,7 @@ func loadlib() {
// dependency problems when compiling natively (external linking requires
// runtime/cgo, runtime/cgo requires cmd/cgo, but cmd/cgo needs to be
// compiled using external linking.)
- if (Thearch.Thechar == '5' || Thearch.Thechar == '7') && HEADTYPE == obj.Hdarwin && iscgo {
+ if SysArch.InFamily(sys.ARM, sys.ARM64) && HEADTYPE == obj.Hdarwin && iscgo {
Linkmode = LinkExternal
}
@@ -621,7 +618,7 @@ func loadlib() {
// a variable to hold g in assembly (currently only intel).
if tlsg.Type == 0 {
tlsg.Type = obj.STLSBSS
- tlsg.Size = int64(Thearch.Ptrsize)
+ tlsg.Size = int64(SysArch.PtrSize)
} else if tlsg.Type != obj.SDYNIMPORT {
Diag("internal error: runtime declared tlsg variable %d", tlsg.Type)
}
@@ -639,7 +636,7 @@ func loadlib() {
// In addition, on ARM, the runtime depends on the linker
// recording the value of GOARM.
- if Thearch.Thechar == '5' {
+ if SysArch.Family == sys.ARM {
s := Linklookup(Ctxt, "runtime.goarm", 0)
s.Type = obj.SRODATA
@@ -696,13 +693,13 @@ func loadlib() {
args := hostlinkArchArgs()
args = append(args, "--print-libgcc-file-name")
if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "%s %v\n", extld, args)
+ fmt.Fprintf(Bso, "%s %v\n", extld, args)
}
out, err := exec.Command(extld, args...).Output()
if err != nil {
if Debug['v'] != 0 {
- fmt.Fprintln(&Bso, "not using a libgcc file because compiler failed")
- fmt.Fprintf(&Bso, "%v\n%s\n", err, out)
+ fmt.Fprintln(Bso, "not using a libgcc file because compiler failed")
+ fmt.Fprintf(Bso, "%v\n%s\n", err, out)
}
libgccfile = "none"
} else {
@@ -743,17 +740,17 @@ func loadlib() {
* look for the next file in an archive.
* adapted from libmach.
*/
-func nextar(bp *obj.Biobuf, off int64, a *ArHdr) int64 {
+func nextar(bp *bio.Reader, off int64, a *ArHdr) int64 {
if off&1 != 0 {
off++
}
- obj.Bseek(bp, off, 0)
- buf := make([]byte, SAR_HDR)
- if n := obj.Bread(bp, buf); n < len(buf) {
- if n >= 0 {
- return 0
+ bp.Seek(off, 0)
+ var buf [SAR_HDR]byte
+ if n, err := io.ReadFull(bp, buf[:]); err != nil {
+ if n == 0 && err != io.EOF {
+ return -1
}
- return -1
+ return 0
}
a.name = artrim(buf[0:16])
@@ -768,35 +765,38 @@ func nextar(bp *obj.Biobuf, off int64, a *ArHdr) int64 {
if arsize&1 != 0 {
arsize++
}
- return int64(arsize) + SAR_HDR
+ return arsize + SAR_HDR
}
func objfile(lib *Library) {
pkg := pathtoprefix(lib.Pkg)
if Debug['v'] > 1 {
- fmt.Fprintf(&Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), lib.File, pkg)
+ fmt.Fprintf(Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), lib.File, pkg)
}
Bso.Flush()
- f, err := obj.Bopenr(lib.File)
+ f, err := bio.Open(lib.File)
if err != nil {
Exitf("cannot open file %s: %v", lib.File, err)
}
- magbuf := make([]byte, len(ARMAG))
- if obj.Bread(f, magbuf) != len(magbuf) || !strings.HasPrefix(string(magbuf), ARMAG) {
+ for i := 0; i < len(ARMAG); i++ {
+ if c, err := f.ReadByte(); err == nil && c == ARMAG[i] {
+ continue
+ }
+
/* load it as a regular file */
- l := obj.Bseek(f, 0, 2)
+ l := f.Seek(0, 2)
- obj.Bseek(f, 0, 0)
+ f.Seek(0, 0)
ldobj(f, pkg, l, lib.File, lib.File, FileObj)
- obj.Bterm(f)
+ f.Close()
return
}
/* process __.PKGDEF */
- off := obj.Boffset(f)
+ off := f.Offset()
var arhdr ArHdr
l := nextar(f, off, &arhdr)
@@ -812,12 +812,14 @@ func objfile(lib *Library) {
}
if Buildmode == BuildmodeShared {
- before := obj.Boffset(f)
+ before := f.Offset()
pkgdefBytes := make([]byte, atolwhex(arhdr.size))
- obj.Bread(f, pkgdefBytes)
+ if _, err := io.ReadFull(f, pkgdefBytes); err != nil {
+ Diag("%s: short read on archive file symbol header: %v", lib.File, err)
+ }
hash := sha1.Sum(pkgdefBytes)
lib.hash = hash[:]
- obj.Bseek(f, before, 0)
+ f.Seek(before, 0)
}
off += l
@@ -853,11 +855,11 @@ func objfile(lib *Library) {
}
out:
- obj.Bterm(f)
+ f.Close()
}
type Hostobj struct {
- ld func(*obj.Biobuf, string, int64, string)
+ ld func(*bio.Reader, string, int64, string)
pkg string
pn string
file string
@@ -878,7 +880,7 @@ var internalpkg = []string{
"runtime/msan",
}
-func ldhostobj(ld func(*obj.Biobuf, string, int64, string), f *obj.Biobuf, pkg string, length int64, pn string, file string) *Hostobj {
+func ldhostobj(ld func(*bio.Reader, string, int64, string), f *bio.Reader, pkg string, length int64, pn string, file string) *Hostobj {
isinternal := false
for i := 0; i < len(internalpkg); i++ {
if pkg == internalpkg[i] {
@@ -909,26 +911,24 @@ func ldhostobj(ld func(*obj.Biobuf, string, int64, string), f *obj.Biobuf, pkg s
h.pkg = pkg
h.pn = pn
h.file = file
- h.off = obj.Boffset(f)
+ h.off = f.Offset()
h.length = length
return h
}
func hostobjs() {
- var f *obj.Biobuf
var h *Hostobj
for i := 0; i < len(hostobj); i++ {
h = &hostobj[i]
- var err error
- f, err = obj.Bopenr(h.file)
- if f == nil {
+ f, err := bio.Open(h.file)
+ if err != nil {
Exitf("cannot reopen %s: %v", h.pn, err)
}
- obj.Bseek(f, h.off, 0)
+ f.Seek(h.off, 0)
h.ld(f, h.pkg, h.length, h.pn)
- obj.Bterm(f)
+ f.Close()
}
}
@@ -1040,7 +1040,7 @@ func archive() {
argv = append(argv, hostobjCopy()...)
if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "archive: %s\n", strings.Join(argv, " "))
+ fmt.Fprintf(Bso, "archive: %s\n", strings.Join(argv, " "))
Bso.Flush()
}
@@ -1117,6 +1117,23 @@ func hostlink() {
// because lazy PLT resolution can use large amounts of stack at
// times we cannot allow it to do so.
argv = append(argv, "-Wl,-znow")
+
+ // Do not let the host linker generate COPY relocations. These
+ // can move symbols out of sections that rely on stable offsets
+ // from the beginning of the section (like STYPE).
+ argv = append(argv, "-Wl,-znocopyreloc")
+
+ if SysArch.InFamily(sys.ARM, sys.ARM64) {
+ // On ARM, the GNU linker will generate COPY relocations
+ // even with -znocopyreloc set.
+ // https://sourceware.org/bugzilla/show_bug.cgi?id=19962
+ //
+ // On ARM64, the GNU linker will fail instead of
+ // generating COPY relocations.
+ //
+ // In both cases, switch to gold.
+ argv = append(argv, "-fuse-ld=gold")
+ }
}
if Iself && len(buildinfo) > 0 {
@@ -1187,6 +1204,24 @@ func hostlink() {
argv = append(argv, ldflag...)
+ if flag_race != 0 {
+ // On a system where the toolchain creates position independent
+ // executables by default, tsan initialization can fail. So we pass
+ // -no-pie here, but support for that flag is quite new and we test
+ // for its support first.
+ src := filepath.Join(tmpdir, "trivial.c")
+ if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
+ Ctxt.Diag("WriteFile trivial.c failed: %v", err)
+ }
+ cmd := exec.Command(argv[0], "-no-pie", "trivial.c")
+ cmd.Dir = tmpdir
+ out, err := cmd.CombinedOutput()
+ supported := err == nil && !bytes.Contains(out, []byte("unrecognized"))
+ if supported {
+ argv = append(argv, "-no-pie")
+ }
+ }
+
for _, p := range strings.Fields(extldflags) {
argv = append(argv, p)
@@ -1209,24 +1244,24 @@ func hostlink() {
}
if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "host link:")
+ fmt.Fprintf(Bso, "host link:")
for _, v := range argv {
- fmt.Fprintf(&Bso, " %q", v)
+ fmt.Fprintf(Bso, " %q", v)
}
- fmt.Fprintf(&Bso, "\n")
+ fmt.Fprintf(Bso, "\n")
Bso.Flush()
}
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)
+ 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' {
+ if !SysArch.InFamily(sys.ARM, sys.ARM64) {
dsym := filepath.Join(tmpdir, "go.dwarf")
if out, err := exec.Command("dsymutil", "-f", outfile, "-o", dsym).CombinedOutput(); err != nil {
Ctxt.Cursym = nil
@@ -1254,14 +1289,14 @@ func hostlink() {
// hostlinkArchArgs returns arguments to pass to the external linker
// based on the architecture.
func hostlinkArchArgs() []string {
- switch Thearch.Thechar {
- case '8':
+ switch SysArch.Family {
+ case sys.I386:
return []string{"-m32"}
- case '6', '9', 'z':
+ case sys.AMD64, sys.PPC64, sys.S390X:
return []string{"-m64"}
- case '5':
+ case sys.ARM:
return []string{"-marm"}
- case '7':
+ case sys.ARM64:
// nothing needed
}
return nil
@@ -1270,15 +1305,15 @@ func hostlinkArchArgs() []string {
// ldobj loads an input object. If it is a host object (an object
// compiled by a non-Go compiler) it returns the Hostobj pointer. If
// it is a Go object, it returns nil.
-func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, whence int) *Hostobj {
- eof := obj.Boffset(f) + length
+func ldobj(f *bio.Reader, pkg string, length int64, pn string, file string, whence int) *Hostobj {
+ eof := f.Offset() + length
- start := obj.Boffset(f)
- c1 := obj.Bgetc(f)
- c2 := obj.Bgetc(f)
- c3 := obj.Bgetc(f)
- c4 := obj.Bgetc(f)
- obj.Bseek(f, start, 0)
+ start := f.Offset()
+ c1 := bgetc(f)
+ c2 := bgetc(f)
+ c3 := bgetc(f)
+ c4 := bgetc(f)
+ f.Seek(start, 0)
magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
if magic == 0x7f454c46 { // \x7F E L F
@@ -1294,22 +1329,19 @@ func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, when
}
/* check the header */
- line := obj.Brdline(f, '\n')
- if line == "" {
- if obj.Blinelen(f) > 0 {
- Diag("%s: not an object file", pn)
- return nil
- }
- Diag("truncated object file: %s", pn)
+ line, err := f.ReadString('\n')
+ if err != nil {
+ Diag("truncated object file: %s: %v", pn, err)
return nil
}
if !strings.HasPrefix(line, "go object ") {
if strings.HasSuffix(pn, ".go") {
- Exitf("%cl: input %s is not .%c file (use %cg to compile .go files)", Thearch.Thechar, pn, Thearch.Thechar, Thearch.Thechar)
+ Exitf("%s: uncompiled .go source file", pn)
+ return nil
}
- if line == Thestring {
+ if line == SysArch.Name {
// old header format: just $GOOS
Diag("%s: stale object file", pn)
return nil
@@ -1341,28 +1373,28 @@ func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, when
}
/* skip over exports and other info -- ends with \n!\n */
- import0 := obj.Boffset(f)
+ import0 := f.Offset()
c1 = '\n' // the last line ended in \n
- c2 = obj.Bgetc(f)
- c3 = obj.Bgetc(f)
+ c2 = bgetc(f)
+ c3 = bgetc(f)
for c1 != '\n' || c2 != '!' || c3 != '\n' {
c1 = c2
c2 = c3
- c3 = obj.Bgetc(f)
- if c3 == obj.Beof {
+ c3 = bgetc(f)
+ if c3 == -1 {
Diag("truncated object file: %s", pn)
return nil
}
}
- import1 := obj.Boffset(f)
+ import1 := f.Offset()
- obj.Bseek(f, import0, 0)
+ f.Seek(import0, 0)
ldpkg(f, pkg, import1-import0-2, pn, whence) // -2 for !\n
- obj.Bseek(f, import1, 0)
+ f.Seek(import1, 0)
- LoadObjFile(Ctxt, f, pkg, eof-obj.Boffset(f), pn)
+ LoadObjFile(Ctxt, f, pkg, eof-f.Offset(), pn)
return nil
}
@@ -1500,12 +1532,12 @@ func ldshlibsyms(shlib string) {
// the type data.
if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") {
lsym.P = readelfsymboldata(f, &elfsym)
- gcdata_locations[elfsym.Value+2*uint64(Thearch.Ptrsize)+8+1*uint64(Thearch.Ptrsize)] = lsym
+ gcdata_locations[elfsym.Value+2*uint64(SysArch.PtrSize)+8+1*uint64(SysArch.PtrSize)] = lsym
}
}
}
gcdata_addresses := make(map[*LSym]uint64)
- if Thearch.Thechar == '7' {
+ if SysArch.Family == sys.ARM64 {
for _, sect := range f.Sections {
if sect.Type == elf.SHT_RELA {
var rela elf.Rela64
@@ -1532,30 +1564,14 @@ func ldshlibsyms(shlib string) {
// 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
- // list.
- var last *LSym
-
- for s := Ctxt.Textp; s != nil; s = s.Next {
- if s.Type == obj.SDYNIMPORT {
- continue
- }
-
- if last == nil {
- Ctxt.Textp = s
- } else {
- last.Next = s
+ // pcln table entries for these any more so remove them from Textp.
+ textp := make([]*LSym, 0, len(Ctxt.Textp))
+ for _, s := range Ctxt.Textp {
+ if s.Type != obj.SDYNIMPORT {
+ textp = append(textp, s)
}
- last = s
- }
-
- if last == nil {
- Ctxt.Textp = nil
- Ctxt.Etextp = nil
- } else {
- last.Next = nil
- Ctxt.Etextp = last
}
+ Ctxt.Textp = textp
Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, gcdata_addresses: gcdata_addresses})
}
@@ -1564,10 +1580,6 @@ func mywhatsys() {
goroot = obj.Getgoroot()
goos = obj.Getgoos()
goarch = obj.Getgoarch()
-
- if !strings.HasPrefix(goarch, Thestring) {
- log.Fatalf("cannot use %cc with GOARCH=%s", Thearch.Thechar, goarch)
- }
}
// Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync.
@@ -1608,7 +1620,7 @@ func addsection(seg *Segment, name string, rwx int) *Section {
sect.Rwx = uint8(rwx)
sect.Name = name
sect.Seg = seg
- sect.Align = int32(Thearch.Ptrsize) // everything is at least pointer-aligned
+ sect.Align = int32(SysArch.PtrSize) // everything is at least pointer-aligned
*l = sect
return sect
}
@@ -1652,7 +1664,7 @@ func callsize() int {
if haslinkregister() {
return 0
}
- return Thearch.Regsize
+ return SysArch.RegSize
}
func dostkcheck() {
@@ -1673,7 +1685,7 @@ func dostkcheck() {
// Check every function, but do the nosplit functions in a first pass,
// to make the printed failure chains as short as possible.
- for s := Ctxt.Textp; s != nil; s = s.Next {
+ for _, s := range Ctxt.Textp {
// runtime.racesymbolizethunk is called from gcc-compiled C
// code running on the operating system thread stack.
// It uses more than the usual amount of stack but that's okay.
@@ -1688,7 +1700,7 @@ func dostkcheck() {
}
}
- for s := Ctxt.Textp; s != nil; s = s.Next {
+ for _, s := range Ctxt.Textp {
if !s.Attr.NoSplit() {
Ctxt.Cursym = s
ch.sym = s
@@ -1717,7 +1729,7 @@ func stkcheck(up *Chain, depth int) int {
return -1
}
- if s.Attr.External() || s.Pcln == nil {
+ if s.Attr.External() || s.FuncInfo == nil {
// external function.
// should never be called directly.
// only diagnose the direct caller.
@@ -1754,7 +1766,11 @@ func stkcheck(up *Chain, depth int) int {
return 0
}
// Raise limit to allow frame.
- limit = int(obj.StackLimit+s.Locals) + int(Ctxt.FixedFrameSize())
+ locals := int32(0)
+ if s.FuncInfo != nil {
+ locals = s.FuncInfo.Locals
+ }
+ limit = int(obj.StackLimit+locals) + int(Ctxt.FixedFrameSize())
}
// Walk through sp adjustments in function, consuming relocs.
@@ -1764,7 +1780,7 @@ func stkcheck(up *Chain, depth int) int {
var ch1 Chain
var pcsp Pciter
var r *Reloc
- for pciterinit(Ctxt, &pcsp, &s.Pcln.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
+ for pciterinit(Ctxt, &pcsp, &s.FuncInfo.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
// pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
// Check stack size in effect for this span.
@@ -1956,7 +1972,7 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
continue
}
if len(s.P) > 0 {
- Diag("%s should not be bss (size=%d type=%d special=%v)", s.Name, int(len(s.P)), s.Type, s.Attr.Special())
+ Diag("%s should not be bss (size=%d type=%d special=%v)", s.Name, len(s.P), s.Type, s.Attr.Special())
}
put(s, s.Name, 'B', Symaddr(s), s.Size, int(s.Version), s.Gotype)
@@ -1982,13 +1998,20 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
}
var off int32
- for s := Ctxt.Textp; s != nil; s = s.Next {
+ for _, s := range Ctxt.Textp {
put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), s.Gotype)
+ locals := int32(0)
+ if s.FuncInfo != nil {
+ locals = s.FuncInfo.Locals
+ }
// NOTE(ality): acid can't produce a stack trace without .frame symbols
- put(nil, ".frame", 'm', int64(s.Locals)+int64(Thearch.Ptrsize), 0, 0, nil)
+ put(nil, ".frame", 'm', int64(locals)+int64(SysArch.PtrSize), 0, 0, nil)
- for _, a := range s.Autom {
+ if s.FuncInfo == nil {
+ continue
+ }
+ for _, a := range s.FuncInfo.Autom {
// Emit a or p according to actual offset, even if label is wrong.
// This avoids negative offsets, which cannot be encoded.
if a.Name != obj.A_AUTO && a.Name != obj.A_PARAM {
@@ -1999,7 +2022,7 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
if a.Name == obj.A_PARAM {
off = a.Aoffset
} else {
- off = a.Aoffset - int32(Thearch.Ptrsize)
+ off = a.Aoffset - int32(SysArch.PtrSize)
}
// FP
@@ -2009,8 +2032,8 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
}
// SP
- if off <= int32(-Thearch.Ptrsize) {
- put(nil, a.Asym.Name, 'a', -(int64(off) + int64(Thearch.Ptrsize)), 0, 0, a.Gotype)
+ if off <= int32(-SysArch.PtrSize) {
+ put(nil, a.Asym.Name, 'a', -(int64(off) + int64(SysArch.PtrSize)), 0, 0, a.Gotype)
continue
}
}
@@ -2019,7 +2042,7 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
// Otherwise, off is addressing the saved program counter.
// Something underhanded is going on. Say nothing.
if Debug['v'] != 0 || Debug['n'] != 0 {
- fmt.Fprintf(&Bso, "%5.2f symsize = %d\n", obj.Cputime(), uint32(Symsize))
+ fmt.Fprintf(Bso, "%5.2f symsize = %d\n", obj.Cputime(), uint32(Symsize))
}
Bso.Flush()
}
@@ -2085,10 +2108,10 @@ func undefsym(s *LSym) {
}
func undef() {
- for s := Ctxt.Textp; s != nil; s = s.Next {
+ for _, s := range Ctxt.Textp {
undefsym(s)
}
- for s := datap; s != nil; s = s.Next {
+ for _, s := range datap {
undefsym(s)
}
if nerrors > 0 {
@@ -2103,14 +2126,14 @@ func callgraph() {
var i int
var r *Reloc
- for s := Ctxt.Textp; s != nil; s = s.Next {
+ for _, s := range Ctxt.Textp {
for i = 0; i < len(s.R); i++ {
r = &s.R[i]
if r.Sym == nil {
continue
}
if (r.Type == obj.R_CALL || r.Type == obj.R_CALLARM || r.Type == obj.R_CALLPOWER || r.Type == obj.R_CALLMIPS) && r.Sym.Type == obj.STEXT {
- fmt.Fprintf(&Bso, "%s calls %s\n", s.Name, r.Sym.Name)
+ fmt.Fprintf(Bso, "%s calls %s\n", s.Name, r.Sym.Name)
}
}
}
@@ -2145,3 +2168,14 @@ func Rnd(v int64, r int64) int64 {
v -= c
return v
}
+
+func bgetc(r *bio.Reader) int {
+ c, err := r.ReadByte()
+ if err != nil {
+ if err != io.EOF {
+ log.Fatalf("reading input: %v", err)
+ }
+ return -1
+ }
+ return int(c)
+}
diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go
index 67a855933e..d0515d4617 100644
--- a/src/cmd/link/internal/ld/link.go
+++ b/src/cmd/link/internal/ld/link.go
@@ -31,9 +31,9 @@
package ld
import (
- "cmd/internal/obj"
+ "bufio"
+ "cmd/internal/sys"
"debug/elf"
- "encoding/binary"
"fmt"
)
@@ -50,8 +50,6 @@ type LSym struct {
Align int32
Elfsym int32
LocalElfsym int32
- Args int32
- Locals int32
Value int64
Size int64
// ElfType is set for symbols read from shared libraries by ldshlibsyms. It
@@ -67,8 +65,7 @@ type LSym struct {
Dynimplib string
Dynimpvers string
Sect *Section
- Autom []Auto
- Pcln *Pcln
+ FuncInfo *FuncInfo
P []byte
R []Reloc
}
@@ -161,13 +158,11 @@ type Shlib struct {
}
type Link struct {
- Thechar int32
- Thestring string
Goarm int32
Headtype int
- Arch *LinkArch
+ Arch *sys.Arch
Debugvlog int32
- Bso *obj.Biobuf
+ Bso *bufio.Writer
Windows int32
Goroot string
@@ -183,10 +178,8 @@ type Link struct {
Diag func(string, ...interface{})
Cursym *LSym
Version int
- Textp *LSym
- Etextp *LSym
- Nhistfile int32
- Filesyms *LSym
+ Textp []*LSym
+ Filesyms []*LSym
Moduledata *LSym
LSymBatch []LSym
}
@@ -196,15 +189,15 @@ type Link struct {
// on the stack in the function prologue and so always have a pointer between
// the hardware stack pointer and the local variable area.
func (ctxt *Link) FixedFrameSize() int64 {
- switch ctxt.Arch.Thechar {
- case '6', '8':
+ switch ctxt.Arch.Family {
+ case sys.AMD64, sys.I386:
return 0
- case '9':
+ case sys.PPC64:
// PIC code on ppc64le requires 32 bytes of stack, and it's easier to
// just use that much stack always on ppc64x.
- return int64(4 * ctxt.Arch.Ptrsize)
+ return int64(4 * ctxt.Arch.PtrSize)
default:
- return int64(ctxt.Arch.Ptrsize)
+ return int64(ctxt.Arch.PtrSize)
}
}
@@ -213,15 +206,6 @@ func (l *Link) IncVersion() {
l.Hash = append(l.Hash, make(map[string]*LSym))
}
-type LinkArch struct {
- ByteOrder binary.ByteOrder
- Name string
- Thechar int
- Minlc int
- Ptrsize int
- Regsize int
-}
-
type Library struct {
Objref string
Srcref string
@@ -231,7 +215,10 @@ type Library struct {
hash []byte
}
-type Pcln struct {
+type FuncInfo struct {
+ Args int32
+ Locals int32
+ Autom []Auto
Pcsp Pcdata
Pcfile Pcdata
Pcline Pcdata
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index d60203fb91..53cc96275d 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -6,6 +6,7 @@ package ld
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"sort"
"strings"
)
@@ -78,6 +79,8 @@ const (
MACHO_X86_64_RELOC_SIGNED_2 = 7
MACHO_X86_64_RELOC_SIGNED_4 = 8
MACHO_ARM_RELOC_VANILLA = 0
+ MACHO_ARM_RELOC_PAIR = 1
+ MACHO_ARM_RELOC_SECTDIFF = 2
MACHO_ARM_RELOC_BR24 = 5
MACHO_ARM64_RELOC_UNSIGNED = 0
MACHO_ARM64_RELOC_BRANCH26 = 2
@@ -131,15 +134,7 @@ var nsortsym int
var load_budget int = INITIAL_MACHO_HEADR - 2*1024
func Machoinit() {
- switch Thearch.Thechar {
- // 64-bit architectures
- case '6', '7', '9':
- macho64 = true
-
- // 32-bit architectures
- default:
- break
- }
+ macho64 = SysArch.RegSize == 8
}
func getMachoHdr() *MachoHdr {
@@ -356,9 +351,10 @@ func machoshbits(mseg *MachoSeg, sect *Section, segname string) {
buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
var msect *MachoSect
- if sect.Rwx&1 == 0 && (Thearch.Thechar == '7' || // arm64
- (Thearch.Thechar == '6' && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive))) { // amd64
- // Darwin external linker on arm64 and on amd64 in c-shared/c-archive buildmode
+ if sect.Rwx&1 == 0 && segname != "__DWARF" && (SysArch.Family == sys.ARM64 ||
+ (SysArch.Family == sys.AMD64 && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive)) ||
+ (SysArch.Family == sys.ARM && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive))) {
+ // Darwin external linker on arm64 and on amd64 and arm in c-shared/c-archive buildmode
// complains about absolute relocs in __TEXT, so if the section is not
// executable, put it in __DATA segment.
msect = newMachoSect(mseg, buf, "__DATA")
@@ -411,6 +407,10 @@ func machoshbits(mseg *MachoSeg, sect *Section, segname string) {
msect.name = "__mod_init_func"
msect.flag = 9 // S_MOD_INIT_FUNC_POINTERS
}
+
+ if segname == "__DWARF" {
+ msect.flag |= 0x02000000
+ }
}
func Asmbmacho() {
@@ -418,23 +418,23 @@ func Asmbmacho() {
va := INITTEXT - int64(HEADR)
mh := getMachoHdr()
- switch Thearch.Thechar {
+ switch SysArch.Family {
default:
- Exitf("unknown macho architecture: %v", Thearch.Thechar)
+ Exitf("unknown macho architecture: %v", SysArch.Family)
- case '5':
+ case sys.ARM:
mh.cpu = MACHO_CPU_ARM
mh.subcpu = MACHO_SUBCPU_ARMV7
- case '6':
+ case sys.AMD64:
mh.cpu = MACHO_CPU_AMD64
mh.subcpu = MACHO_SUBCPU_X86
- case '7':
+ case sys.ARM64:
mh.cpu = MACHO_CPU_ARM64
mh.subcpu = MACHO_SUBCPU_ARM64_ALL
- case '8':
+ case sys.I386:
mh.cpu = MACHO_CPU_386
mh.subcpu = MACHO_SUBCPU_X86
}
@@ -445,7 +445,7 @@ func Asmbmacho() {
ms = newMachoSeg("", 40)
ms.fileoffset = Segtext.Fileoff
- if Thearch.Thechar == '5' || Buildmode == BuildmodeCArchive {
+ if SysArch.Family == sys.ARM || Buildmode == BuildmodeCArchive {
ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff
} else {
ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
@@ -492,32 +492,46 @@ func Asmbmacho() {
machoshbits(ms, sect, "__DATA")
}
+ /* dwarf */
+ if Debug['w'] == 0 {
+ if Linkmode != LinkExternal {
+ ms = newMachoSeg("__DWARF", 20)
+ ms.vaddr = Segdwarf.Vaddr
+ ms.vsize = 0
+ ms.fileoffset = Segdwarf.Fileoff
+ ms.filesize = Segdwarf.Filelen
+ }
+ for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+ machoshbits(ms, sect, "__DWARF")
+ }
+ }
+
if Linkmode != LinkExternal {
- switch Thearch.Thechar {
+ switch SysArch.Family {
default:
- Exitf("unknown macho architecture: %v", Thearch.Thechar)
+ Exitf("unknown macho architecture: %v", SysArch.Family)
- case '5':
+ case sys.ARM:
ml := newMachoLoad(5, 17+2) /* unix thread */
ml.data[0] = 1 /* thread type */
ml.data[1] = 17 /* word count */
ml.data[2+15] = uint32(Entryvalue()) /* start pc */
- case '6':
+ case sys.AMD64:
ml := newMachoLoad(5, 42+2) /* unix thread */
ml.data[0] = 4 /* thread type */
ml.data[1] = 42 /* word count */
ml.data[2+32] = uint32(Entryvalue()) /* start pc */
ml.data[2+32+1] = uint32(Entryvalue() >> 32)
- case '7':
+ case sys.ARM64:
ml := newMachoLoad(5, 68+2) /* unix thread */
ml.data[0] = 6 /* thread type */
ml.data[1] = 68 /* word count */
ml.data[2+64] = uint32(Entryvalue()) /* start pc */
ml.data[2+64+1] = uint32(Entryvalue() >> 32)
- case '8':
+ case sys.I386:
ml := newMachoLoad(5, 16+2) /* unix thread */
ml.data[0] = 1 /* thread type */
ml.data[1] = 16 /* word count */
@@ -528,7 +542,6 @@ func Asmbmacho() {
if Debug['d'] == 0 {
// must match domacholink below
s1 := Linklookup(Ctxt, ".machosymtab", 0)
-
s2 := Linklookup(Ctxt, ".linkedit.plt", 0)
s3 := Linklookup(Ctxt, ".linkedit.got", 0)
s4 := Linklookup(Ctxt, ".machosymstr", 0)
@@ -576,21 +589,13 @@ func Asmbmacho() {
// and we can assume OS X.
//
// See golang.org/issues/12941.
- const (
- LC_VERSION_MIN_MACOSX = 0x24
- LC_VERSION_MIN_IPHONEOS = 0x25
- LC_VERSION_MIN_WATCHOS = 0x30
- )
+ const LC_VERSION_MIN_MACOSX = 0x24
+
ml := newMachoLoad(LC_VERSION_MIN_MACOSX, 2)
ml.data[0] = 10<<16 | 7<<8 | 0<<0 // OS X version 10.7.0
ml.data[1] = 10<<16 | 7<<8 | 0<<0 // SDK 10.7.0
}
- // TODO: dwarf headers go in ms too
- if Debug['s'] == 0 {
- dwarfaddmachoheaders(ms)
- }
-
a := machowrite()
if int32(a) > HEADR {
Exitf("HEADR too small: %d > %d", a, HEADR)
@@ -680,15 +685,11 @@ func machosymorder() {
}
func machosymtab() {
- var s *LSym
- var o *LSym
- var p string
-
symtab := Linklookup(Ctxt, ".machosymtab", 0)
symstr := Linklookup(Ctxt, ".machosymstr", 0)
for i := 0; i < nsortsym; i++ {
- s = sortsym[i]
+ s := sortsym[i]
Adduint32(Ctxt, symtab, uint32(symstr.Size))
// Only add _ to C symbols. Go symbols have dot in the name.
@@ -697,33 +698,20 @@ func machosymtab() {
}
// replace "·" as ".", because DTrace cannot handle it.
- if !strings.Contains(s.Extname, "·") {
- Addstring(symstr, s.Extname)
- } else {
- for p = s.Extname; p != ""; p = p[1:] {
- if uint8(p[0]) == 0xc2 && uint8((p[1:])[0]) == 0xb7 {
- Adduint8(Ctxt, symstr, '.')
- p = p[1:]
- } else {
- Adduint8(Ctxt, symstr, uint8(p[0]))
- }
- }
-
- Adduint8(Ctxt, symstr, '\x00')
- }
+ Addstring(symstr, strings.Replace(s.Extname, "·", ".", -1))
if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ {
Adduint8(Ctxt, symtab, 0x01) // type N_EXT, external symbol
Adduint8(Ctxt, symtab, 0) // no section
Adduint16(Ctxt, symtab, 0) // desc
- adduintxx(Ctxt, symtab, 0, Thearch.Ptrsize) // no value
+ adduintxx(Ctxt, symtab, 0, SysArch.PtrSize) // no value
} else {
if s.Attr.CgoExport() {
Adduint8(Ctxt, symtab, 0x0f)
} else {
Adduint8(Ctxt, symtab, 0x0e)
}
- o = s
+ o := s
for o.Outer != nil {
o = o.Outer
}
@@ -734,7 +722,7 @@ func machosymtab() {
Adduint8(Ctxt, symtab, uint8(o.Sect.Extnum))
}
Adduint16(Ctxt, symtab, 0) // desc
- adduintxx(Ctxt, symtab, uint64(Symaddr(s)), Thearch.Ptrsize)
+ adduintxx(Ctxt, symtab, uint64(Symaddr(s)), SysArch.PtrSize)
}
}
}
@@ -821,27 +809,25 @@ func Domacholink() int64 {
return Rnd(int64(size), int64(INITRND))
}
-func machorelocsect(sect *Section, first *LSym) {
+func machorelocsect(sect *Section, syms []*LSym) {
// If main section has no bits, nothing to relocate.
if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
return
}
sect.Reloff = uint64(Cpos())
- var sym *LSym
- for sym = first; sym != nil; sym = sym.Next {
- if !sym.Attr.Reachable() {
+ for i, s := range syms {
+ if !s.Attr.Reachable() {
continue
}
- if uint64(sym.Value) >= sect.Vaddr {
+ if uint64(s.Value) >= sect.Vaddr {
+ syms = syms[i:]
break
}
}
eaddr := int32(sect.Vaddr + sect.Length)
- var r *Reloc
- var ri int
- for ; sym != nil; sym = sym.Next {
+ for _, sym := range syms {
if !sym.Attr.Reachable() {
continue
}
@@ -850,8 +836,8 @@ func machorelocsect(sect *Section, first *LSym) {
}
Ctxt.Cursym = sym
- for ri = 0; ri < len(sym.R); ri++ {
- r = &sym.R[ri]
+ for ri := 0; ri < len(sym.R); ri++ {
+ r := &sym.R[ri]
if r.Done != 0 {
continue
}
@@ -876,5 +862,7 @@ func Machoemitreloc() {
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
machorelocsect(sect, datap)
}
- dwarfemitreloc()
+ for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+ machorelocsect(sect, list2slice(dwarfp))
+ }
}
diff --git a/src/cmd/link/internal/ld/macho_combine_dwarf.go b/src/cmd/link/internal/ld/macho_combine_dwarf.go
index b5a5a8d429..dcc371ec05 100644
--- a/src/cmd/link/internal/ld/macho_combine_dwarf.go
+++ b/src/cmd/link/internal/ld/macho_combine_dwarf.go
@@ -15,11 +15,9 @@ import (
"unsafe"
)
-var fakedwarf, realdwarf, linkseg *macho.Segment
+var realdwarf, linkseg *macho.Segment
var dwarfstart, linkstart int64
var linkoffset uint32
-var machHeader *macho.FileHeader
-var mappedHeader []byte
const (
LC_ID_DYLIB = 0xd
diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go
index 8a406d17a6..bcfe52585f 100644
--- a/src/cmd/link/internal/ld/objfile.go
+++ b/src/cmd/link/internal/ld/objfile.go
@@ -110,7 +110,10 @@ package ld
import (
"bufio"
"bytes"
+ "cmd/internal/bio"
"cmd/internal/obj"
+ "crypto/sha1"
+ "encoding/base64"
"io"
"log"
"strconv"
@@ -146,18 +149,18 @@ type objReader struct {
file []*LSym
}
-func LoadObjFile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) {
- start := obj.Boffset(f)
+func LoadObjFile(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
+ start := f.Offset()
r := &objReader{
- rd: f.Reader(),
+ rd: f.Reader,
pkg: pkg,
ctxt: ctxt,
pn: pn,
dupSym: &LSym{Name: ".dup"},
}
r.loadObjFile()
- if obj.Boffset(f) != start+length {
- log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(obj.Boffset(f)), int64(start+length))
+ if f.Offset() != start+length {
+ log.Fatalf("%s: unexpected end at %d, want %d", pn, f.Offset(), start+length)
}
}
@@ -330,8 +333,11 @@ overwrite:
}
if s.Type == obj.STEXT {
- s.Args = r.readInt32()
- s.Locals = r.readInt32()
+ s.FuncInfo = new(FuncInfo)
+ pc := s.FuncInfo
+
+ pc.Args = r.readInt32()
+ pc.Locals = r.readInt32()
if r.readUint8() != 0 {
s.Attr |= AttrNoSplit
}
@@ -340,13 +346,13 @@ overwrite:
s.Attr |= AttrReflectMethod
}
n := r.readInt()
- s.Autom = r.autom[:n:n]
+ pc.Autom = r.autom[:n:n]
if !isdup {
r.autom = r.autom[n:]
}
for i := 0; i < n; i++ {
- s.Autom[i] = Auto{
+ pc.Autom[i] = Auto{
Asym: r.readSymIndex(),
Aoffset: r.readInt32(),
Name: r.readInt16(),
@@ -354,8 +360,6 @@ overwrite:
}
}
- s.Pcln = new(Pcln)
- pc := s.Pcln
pc.Pcsp.P = r.readData()
pc.Pcfile.P = r.readData()
pc.Pcline.P = r.readData()
@@ -394,12 +398,7 @@ overwrite:
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
- if r.ctxt.Etextp != nil {
- r.ctxt.Etextp.Next = s
- } else {
- r.ctxt.Textp = s
- }
- r.ctxt.Etextp = s
+ r.ctxt.Textp = append(r.ctxt.Textp, s)
}
}
}
@@ -470,7 +469,7 @@ func (r *objReader) readInt64() int64 {
}
}
- return int64(uv>>1) ^ (int64(uint64(uv)<<63) >> 63)
+ return int64(uv>>1) ^ (int64(uv<<63) >> 63)
}
func (r *objReader) readInt() int {
@@ -529,13 +528,18 @@ func (r *objReader) readSymName() string {
r.readInt64()
return ""
}
- origName, err := r.rd.Peek(n)
- if err != nil {
- log.Fatalf("%s: unexpectedly long symbol name", r.pn)
- }
if cap(r.rdBuf) < n {
r.rdBuf = make([]byte, 2*n)
}
+ origName, err := r.rd.Peek(n)
+ if err == bufio.ErrBufferFull {
+ // Long symbol names are rare but exist. One source is type
+ // symbols for types with long string forms. See #15104.
+ origName = make([]byte, n)
+ r.readFull(origName)
+ } else if err != nil {
+ log.Fatalf("%s: error reading symbol: %v", err)
+ }
adjName := r.rdBuf[:0]
for {
i := bytes.Index(origName, emptyPkg)
@@ -544,8 +548,32 @@ func (r *objReader) readSymName() string {
// Read past the peeked origName, now that we're done with it,
// using the rfBuf (also no longer used) as the scratch space.
// TODO: use bufio.Reader.Discard if available instead?
- r.readFull(r.rdBuf[:n])
+ if err == nil {
+ r.readFull(r.rdBuf[:n])
+ }
r.rdBuf = adjName[:0] // in case 2*n wasn't enough
+
+ if DynlinkingGo() {
+ // These types are included in the symbol
+ // table when dynamically linking. To keep
+ // binary size down, we replace the names
+ // with SHA-1 prefixes.
+ //
+ // Keep the type.. prefix, which parts of the
+ // linker (like the DWARF generator) know means
+ // the symbol is not decodable.
+ //
+ // Leave type.runtime. symbols alone, because
+ // other parts of the linker manipulates them.
+ if strings.HasPrefix(s, "type.") && !strings.HasPrefix(s, "type.runtime.") {
+ hash := sha1.Sum([]byte(s))
+ prefix := "type."
+ if s[5] == '.' {
+ prefix = "type.."
+ }
+ s = prefix + base64.StdEncoding.EncodeToString(hash[:6])
+ }
+ }
return s
}
adjName = append(adjName, origName[:i]...)
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index ff29ce2d70..991b9ef2cd 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -93,7 +93,7 @@ func pciterinit(ctxt *Link, it *Pciter, d *Pcdata) {
it.value = -1
it.start = 1
it.done = 0
- it.pcscale = uint32(ctxt.Arch.Minlc)
+ it.pcscale = uint32(ctxt.Arch.MinLC)
pciternext(it)
}
@@ -127,8 +127,7 @@ func addpctab(ftab *LSym, off int32, d *Pcdata) int32 {
var start int32
if len(d.P) > 0 {
start = int32(len(ftab.P))
- Symgrow(Ctxt, ftab, int64(start)+int64(len(d.P)))
- copy(ftab.P[start:], d.P)
+ Addbytes(Ctxt, ftab, d.P)
}
return int32(setuint32(Ctxt, ftab, int64(off), uint32(start)))
}
@@ -148,27 +147,21 @@ func renumberfiles(ctxt *Link, files []*LSym, d *Pcdata) {
for i := 0; i < len(files); i++ {
f = files[i]
if f.Type != obj.SFILEPATH {
- ctxt.Nhistfile++
- f.Value = int64(ctxt.Nhistfile)
+ ctxt.Filesyms = append(ctxt.Filesyms, f)
+ f.Value = int64(len(ctxt.Filesyms))
f.Type = obj.SFILEPATH
- f.Next = ctxt.Filesyms
f.Name = expandGoroot(f.Name)
- ctxt.Filesyms = f
}
}
newval := int32(-1)
var out Pcdata
-
- var dv int32
var it Pciter
- var oldval int32
- var v uint32
- var val int32
for pciterinit(ctxt, &it, d); it.done == 0; pciternext(&it) {
// value delta
- oldval = it.value
+ oldval := it.value
+ var val int32
if oldval == -1 {
val = -1
} else {
@@ -178,9 +171,9 @@ func renumberfiles(ctxt *Link, files []*LSym, d *Pcdata) {
val = int32(files[oldval].Value)
}
- dv = val - newval
+ dv := val - newval
newval = val
- v = (uint32(dv) << 1) ^ uint32(int32(dv>>31))
+ v := (uint32(dv) << 1) ^ uint32(dv>>31)
addvarint(&out, v)
// pc delta
@@ -205,7 +198,7 @@ func container(s *LSym) int {
// pclntab initializes the pclntab symbol with
// runtime function and file name information.
-var pclntab_zpcln Pcln
+var pclntab_zpcln FuncInfo
// These variables are used to initialize runtime.firstmoduledata, see symtab.go:symtab.
var pclntabNfunc int32
@@ -229,40 +222,34 @@ func pclntab() {
nfunc := int32(0)
// Find container symbols, mark them with SCONTAINER
- for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
- if Ctxt.Cursym.Outer != nil {
- Ctxt.Cursym.Outer.Type |= obj.SCONTAINER
+ for _, s := range Ctxt.Textp {
+ if s.Outer != nil {
+ s.Outer.Type |= obj.SCONTAINER
}
}
- for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
- if container(Ctxt.Cursym) == 0 {
+ for _, s := range Ctxt.Textp {
+ if container(s) == 0 {
nfunc++
}
}
pclntabNfunc = nfunc
- Symgrow(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize)+4)
+ Symgrow(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize)+4)
setuint32(Ctxt, ftab, 0, 0xfffffffb)
- setuint8(Ctxt, ftab, 6, uint8(Thearch.Minlc))
- setuint8(Ctxt, ftab, 7, uint8(Thearch.Ptrsize))
- setuintxx(Ctxt, ftab, 8, uint64(nfunc), int64(Thearch.Ptrsize))
- pclntabPclntabOffset = int32(8 + Thearch.Ptrsize)
+ setuint8(Ctxt, ftab, 6, uint8(SysArch.MinLC))
+ setuint8(Ctxt, ftab, 7, uint8(SysArch.PtrSize))
+ setuintxx(Ctxt, ftab, 8, uint64(nfunc), int64(SysArch.PtrSize))
+ pclntabPclntabOffset = int32(8 + SysArch.PtrSize)
nfunc = 0
var last *LSym
- var end int32
- var funcstart int32
- var i int32
- var it Pciter
- var off int32
- var pcln *Pcln
- for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
+ for _, Ctxt.Cursym = range Ctxt.Textp {
last = Ctxt.Cursym
if container(Ctxt.Cursym) != 0 {
continue
}
- pcln = Ctxt.Cursym.Pcln
+ pcln := Ctxt.Cursym.FuncInfo
if pcln == nil {
pcln = &pclntab_zpcln
}
@@ -271,17 +258,17 @@ func pclntab() {
pclntabFirstFunc = Ctxt.Cursym
}
- funcstart = int32(len(ftab.P))
- funcstart += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
+ funcstart := int32(len(ftab.P))
+ funcstart += int32(-len(ftab.P)) & (int32(SysArch.PtrSize) - 1)
- setaddr(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), Ctxt.Cursym)
- setuintxx(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint64(funcstart), int64(Thearch.Ptrsize))
+ setaddr(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize), Ctxt.Cursym)
+ setuintxx(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize), uint64(funcstart), int64(SysArch.PtrSize))
// fixed size of struct, checked below
- off = funcstart
+ off := funcstart
- end = funcstart + int32(Thearch.Ptrsize) + 3*4 + 5*4 + int32(len(pcln.Pcdata))*4 + int32(len(pcln.Funcdata))*int32(Thearch.Ptrsize)
- if len(pcln.Funcdata) > 0 && (end&int32(Thearch.Ptrsize-1) != 0) {
+ end := funcstart + int32(SysArch.PtrSize) + 3*4 + 5*4 + int32(len(pcln.Pcdata))*4 + int32(len(pcln.Funcdata))*int32(SysArch.PtrSize)
+ if len(pcln.Funcdata) > 0 && (end&int32(SysArch.PtrSize-1) != 0) {
end += 4
}
Symgrow(Ctxt, ftab, int64(end))
@@ -294,7 +281,11 @@ func pclntab() {
// args int32
// TODO: Move into funcinfo.
- off = int32(setuint32(Ctxt, ftab, int64(off), uint32(Ctxt.Cursym.Args)))
+ args := uint32(0)
+ if Ctxt.Cursym.FuncInfo != nil {
+ args = uint32(Ctxt.Cursym.FuncInfo.Args)
+ }
+ off = int32(setuint32(Ctxt, ftab, int64(off), args))
// frame int32
// This has been removed (it was never set quite correctly anyway).
@@ -307,9 +298,10 @@ func pclntab() {
renumberfiles(Ctxt, pcln.File, &pcln.Pcfile)
if false {
// Sanity check the new numbering
+ var it Pciter
for pciterinit(Ctxt, &it, &pcln.Pcfile); it.done == 0; pciternext(&it) {
- if it.value < 1 || it.value > Ctxt.Nhistfile {
- Diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, Ctxt.Nhistfile)
+ if it.value < 1 || it.value > int32(len(Ctxt.Filesyms)) {
+ Diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, len(Ctxt.Filesyms))
errorexit()
}
}
@@ -323,32 +315,32 @@ func pclntab() {
off = addpctab(ftab, off, &pcln.Pcline)
off = int32(setuint32(Ctxt, ftab, int64(off), uint32(len(pcln.Pcdata))))
off = int32(setuint32(Ctxt, ftab, int64(off), uint32(len(pcln.Funcdata))))
- for i = 0; i < int32(len(pcln.Pcdata)); i++ {
+ for i := 0; i < len(pcln.Pcdata); i++ {
off = addpctab(ftab, off, &pcln.Pcdata[i])
}
// funcdata, must be pointer-aligned and we're only int32-aligned.
// Missing funcdata will be 0 (nil pointer).
if len(pcln.Funcdata) > 0 {
- if off&int32(Thearch.Ptrsize-1) != 0 {
+ if off&int32(SysArch.PtrSize-1) != 0 {
off += 4
}
- for i = 0; i < int32(len(pcln.Funcdata)); i++ {
+ for i := 0; i < len(pcln.Funcdata); i++ {
if pcln.Funcdata[i] == nil {
- setuintxx(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(Thearch.Ptrsize))
+ setuintxx(Ctxt, ftab, int64(off)+int64(SysArch.PtrSize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(SysArch.PtrSize))
} else {
// TODO: Dedup.
funcdata_bytes += pcln.Funcdata[i].Size
- setaddrplus(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i])
+ setaddrplus(Ctxt, ftab, int64(off)+int64(SysArch.PtrSize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i])
}
}
- off += int32(len(pcln.Funcdata)) * int32(Thearch.Ptrsize)
+ off += int32(len(pcln.Funcdata)) * int32(SysArch.PtrSize)
}
if off != end {
- Diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcln.Pcdata), len(pcln.Funcdata), Thearch.Ptrsize)
+ Diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcln.Pcdata), len(pcln.Funcdata), SysArch.PtrSize)
errorexit()
}
@@ -357,25 +349,26 @@ func pclntab() {
pclntabLastFunc = last
// Final entry of table is just end pc.
- setaddrplus(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), last, last.Size)
+ setaddrplus(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize), last, last.Size)
// Start file table.
start := int32(len(ftab.P))
- start += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
+ start += int32(-len(ftab.P)) & (int32(SysArch.PtrSize) - 1)
pclntabFiletabOffset = start
- setuint32(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint32(start))
+ setuint32(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize), uint32(start))
- Symgrow(Ctxt, ftab, int64(start)+(int64(Ctxt.Nhistfile)+1)*4)
- setuint32(Ctxt, ftab, int64(start), uint32(Ctxt.Nhistfile))
- for s := Ctxt.Filesyms; s != nil; s = s.Next {
+ Symgrow(Ctxt, ftab, int64(start)+(int64(len(Ctxt.Filesyms))+1)*4)
+ setuint32(Ctxt, ftab, int64(start), uint32(len(Ctxt.Filesyms)))
+ for i := len(Ctxt.Filesyms) - 1; i >= 0; i-- {
+ s := Ctxt.Filesyms[i]
setuint32(Ctxt, ftab, int64(start)+s.Value*4, uint32(ftabaddstring(ftab, s.Name)))
}
ftab.Size = int64(len(ftab.P))
if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "%5.2f pclntab=%d bytes, funcdata total %d bytes\n", obj.Cputime(), int64(ftab.Size), int64(funcdata_bytes))
+ fmt.Fprintf(Bso, "%5.2f pclntab=%d bytes, funcdata total %d bytes\n", obj.Cputime(), ftab.Size, funcdata_bytes)
}
}
@@ -407,10 +400,9 @@ func findfunctab() {
t.Attr |= AttrLocal
// find min and max address
- min := Ctxt.Textp.Value
-
+ min := Ctxt.Textp[0].Value
max := int64(0)
- for s := Ctxt.Textp; s != nil; s = s.Next {
+ for _, s := range Ctxt.Textp {
max = s.Value + s.Size
}
@@ -423,34 +415,34 @@ func findfunctab() {
indexes[i] = NOIDX
}
idx := int32(0)
- var e *LSym
- var i int32
- var p int64
- var q int64
- for s := Ctxt.Textp; s != nil; s = s.Next {
+ for i, s := range Ctxt.Textp {
if container(s) != 0 {
continue
}
- p = s.Value
- e = s.Next
- for container(e) != 0 {
- e = e.Next
+ p := s.Value
+ var e *LSym
+ i++
+ if i < len(Ctxt.Textp) {
+ e = Ctxt.Textp[i]
+ }
+ for container(e) != 0 && i < len(Ctxt.Textp) {
+ e = Ctxt.Textp[i]
+ i++
}
+ q := max
if e != nil {
q = e.Value
- } else {
- q = max
}
//print("%d: [%lld %lld] %s\n", idx, p, q, s->name);
for ; p < q; p += SUBBUCKETSIZE {
- i = int32((p - min) / SUBBUCKETSIZE)
+ i = int((p - min) / SUBBUCKETSIZE)
if indexes[i] > idx {
indexes[i] = idx
}
}
- i = int32((q - 1 - min) / SUBBUCKETSIZE)
+ i = int((q - 1 - min) / SUBBUCKETSIZE)
if indexes[i] > idx {
indexes[i] = idx
}
@@ -463,15 +455,13 @@ func findfunctab() {
Symgrow(Ctxt, t, 4*int64(nbuckets)+int64(n))
// fill in table
- var base int32
- var j int32
for i := int32(0); i < nbuckets; i++ {
- base = indexes[i*SUBBUCKETS]
+ base := indexes[i*SUBBUCKETS]
if base == NOIDX {
Diag("hole in findfunctab")
}
setuint32(Ctxt, t, int64(i)*(4+SUBBUCKETS), uint32(base))
- for j = 0; j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
+ for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
idx = indexes[i*SUBBUCKETS+j]
if idx == NOIDX {
Diag("hole in findfunctab")
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index 56698361d0..839aa6cca7 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -6,6 +6,7 @@ package ld
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"encoding/binary"
"fmt"
"os"
@@ -419,9 +420,9 @@ func chksectseg(h *IMAGE_SECTION_HEADER, s *Segment) {
func Peinit() {
var l int
- switch Thearch.Thechar {
+ switch SysArch.Family {
// 64-bit architectures
- case '6':
+ case sys.AMD64:
pe64 = 1
l = binary.Size(&oh64)
@@ -506,7 +507,7 @@ func initdynimport() *Dll {
if err != nil {
Diag("failed to parse stdcall decoration: %v", err)
}
- m.argsize *= Thearch.Ptrsize
+ m.argsize *= SysArch.PtrSize
s.Extname = s.Extname[:i]
}
@@ -520,10 +521,10 @@ func initdynimport() *Dll {
for d := dr; d != nil; d = d.next {
for m = d.ms; m != nil; m = m.next {
m.s.Type = obj.SDATA
- Symgrow(Ctxt, m.s, int64(Thearch.Ptrsize))
+ Symgrow(Ctxt, m.s, int64(SysArch.PtrSize))
dynName := m.s.Extname
// only windows/386 requires stdcall decoration
- if Thearch.Thechar == '8' && m.argsize >= 0 {
+ if SysArch.Family == sys.I386 && m.argsize >= 0 {
dynName += fmt.Sprintf("@%d", m.argsize)
}
dynSym := Linklookup(Ctxt, dynName, 0)
@@ -532,7 +533,7 @@ func initdynimport() *Dll {
r := Addrel(m.s)
r.Sym = dynSym
r.Off = 0
- r.Siz = uint8(Thearch.Ptrsize)
+ r.Siz = uint8(SysArch.PtrSize)
r.Type = obj.R_ADDR
}
}
@@ -546,10 +547,10 @@ func initdynimport() *Dll {
m.s.Sub = dynamic.Sub
dynamic.Sub = m.s
m.s.Value = dynamic.Size
- dynamic.Size += int64(Thearch.Ptrsize)
+ dynamic.Size += int64(SysArch.PtrSize)
}
- dynamic.Size += int64(Thearch.Ptrsize)
+ dynamic.Size += int64(SysArch.PtrSize)
}
}
@@ -763,7 +764,7 @@ func addexports() {
// perelocsect relocates symbols from first in section sect, and returns
// the total number of relocations emitted.
-func perelocsect(sect *Section, first *LSym) int {
+func perelocsect(sect *Section, syms []*LSym) int {
// If main section has no bits, nothing to relocate.
if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
return 0
@@ -772,20 +773,18 @@ func perelocsect(sect *Section, first *LSym) int {
relocs := 0
sect.Reloff = uint64(Cpos())
- var sym *LSym
- for sym = first; sym != nil; sym = sym.Next {
- if !sym.Attr.Reachable() {
+ for i, s := range syms {
+ if !s.Attr.Reachable() {
continue
}
- if uint64(sym.Value) >= sect.Vaddr {
+ if uint64(s.Value) >= sect.Vaddr {
+ syms = syms[i:]
break
}
}
eaddr := int32(sect.Vaddr + sect.Length)
- var r *Reloc
- var ri int
- for ; sym != nil; sym = sym.Next {
+ for _, sym := range syms {
if !sym.Attr.Reachable() {
continue
}
@@ -794,8 +793,8 @@ func perelocsect(sect *Section, first *LSym) int {
}
Ctxt.Cursym = sym
- for ri = 0; ri < len(sym.R); ri++ {
- r = &sym.R[ri]
+ for ri := 0; ri < len(sym.R); ri++ {
+ r := &sym.R[ri]
if r.Done != 0 {
continue
}
@@ -876,7 +875,7 @@ func peemitreloc(text, data, ctors *IMAGE_SECTION_HEADER) {
ctors.NumberOfRelocations = 1
ctors.PointerToRelocations = uint32(Cpos())
sectoff := ctors.VirtualAddress
- Lputl(uint32(sectoff))
+ Lputl(sectoff)
Lputl(uint32(dottext.Dynid))
switch obj.Getgoarch() {
default:
@@ -946,7 +945,7 @@ func writePESymTableRecords() int {
}
// only windows/386 requires underscore prefix on external symbols
- if Thearch.Thechar == '8' &&
+ if SysArch.Family == sys.I386 &&
Linkmode == LinkExternal &&
(s.Type != obj.SDYNIMPORT || s.Attr.CgoExport()) &&
s.Name == s.Extname &&
@@ -1002,7 +1001,7 @@ func writePESymTableRecords() int {
for d := dr; d != nil; d = d.next {
for m := d.ms; m != nil; m = m.next {
s := m.s.R[0].Xsym
- put(s, s.Name, 'U', 0, int64(Thearch.Ptrsize), 0, nil)
+ put(s, s.Name, 'U', 0, int64(SysArch.PtrSize), 0, nil)
}
}
@@ -1042,7 +1041,7 @@ func addpesymtable() {
// write COFF string table
Lputl(uint32(len(strtbl)) + 4)
for i := 0; i < len(strtbl); i++ {
- Cput(uint8(strtbl[i]))
+ Cput(strtbl[i])
}
if Linkmode != LinkExternal {
strnput("", int(h.SizeOfRawData-uint32(size)))
@@ -1129,12 +1128,12 @@ func addinitarray() (c *IMAGE_SECTION_HEADER) {
}
func Asmbpe() {
- switch Thearch.Thechar {
+ switch SysArch.Family {
default:
- Exitf("unknown PE architecture: %v", Thearch.Thechar)
- case '6':
+ Exitf("unknown PE architecture: %v", SysArch.Family)
+ case sys.AMD64:
fh.Machine = IMAGE_FILE_MACHINE_AMD64
- case '8':
+ case sys.I386:
fh.Machine = IMAGE_FILE_MACHINE_I386
}
diff --git a/src/cmd/link/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go
index f48b54efda..b64bb5deaf 100644
--- a/src/cmd/link/internal/ld/pobj.go
+++ b/src/cmd/link/internal/ld/pobj.go
@@ -31,7 +31,9 @@
package ld
import (
+ "bufio"
"cmd/internal/obj"
+ "cmd/internal/sys"
"flag"
"fmt"
"os"
@@ -44,13 +46,12 @@ var (
)
func Ldmain() {
- Ctxt = linknew(Thelinkarch)
- Ctxt.Thechar = int32(Thearch.Thechar)
- Ctxt.Thestring = Thestring
+ Bso = bufio.NewWriter(os.Stdout)
+
+ Ctxt = linknew(SysArch)
Ctxt.Diag = Diag
- Ctxt.Bso = &Bso
+ Ctxt.Bso = Bso
- Bso = *obj.Binitw(os.Stdout)
Debug = [128]int{}
nerrors = 0
outfile = ""
@@ -70,7 +71,7 @@ func Ldmain() {
}
}
- if Thearch.Thechar == '6' && obj.Getgoos() == "plan9" {
+ if SysArch.Family == sys.AMD64 && obj.Getgoos() == "plan9" {
obj.Flagcount("8", "use 64-bit addresses in symbol table", &Debug['8'])
}
obj.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF", addbuildinfo)
@@ -89,6 +90,7 @@ func Ldmain() {
flag.Var(&Buildmode, "buildmode", "set build `mode`")
obj.Flagcount("c", "dump call graph", &Debug['c'])
obj.Flagcount("d", "disable dynamic executable", &Debug['d'])
+ flag.BoolVar(&flag_dumpdep, "dumpdep", false, "dump symbol dependency graph")
obj.Flagstr("extar", "archive program for buildmode=c-archive", &extar)
obj.Flagstr("extld", "use `linker` when linking in external mode", &extld)
obj.Flagstr("extldflags", "pass `flags` to external linker", &extldflags)
@@ -107,7 +109,7 @@ func Ldmain() {
obj.Flagcount("race", "enable race detector", &flag_race)
obj.Flagcount("s", "disable symbol table", &Debug['s'])
var flagShared int
- if Thearch.Thechar == '5' || Thearch.Thechar == '6' {
+ if SysArch.InFamily(sys.ARM, sys.AMD64) {
obj.Flagcount("shared", "generate shared object (implies -linkmode external)", &flagShared)
}
obj.Flagstr("tmpdir", "use `directory` for temporary files", &tmpdir)
@@ -122,7 +124,7 @@ func Ldmain() {
obj.Flagparse(usage)
startProfile()
- Ctxt.Bso = &Bso
+ Ctxt.Bso = Bso
Ctxt.Debugvlog = int32(Debug['v'])
if flagShared != 0 {
if Buildmode == BuildmodeUnset {
@@ -163,7 +165,7 @@ func Ldmain() {
}
if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", HEADTYPE, uint64(INITTEXT), uint64(INITDAT), uint32(INITRND))
+ fmt.Fprintf(Bso, "HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", HEADTYPE, uint64(INITTEXT), uint64(INITDAT), uint32(INITRND))
}
Bso.Flush()
@@ -214,9 +216,9 @@ func Ldmain() {
hostlink()
archive()
if Debug['v'] != 0 {
- fmt.Fprintf(&Bso, "%5.2f cpu time\n", obj.Cputime())
- fmt.Fprintf(&Bso, "%d symbols\n", len(Ctxt.Allsym))
- fmt.Fprintf(&Bso, "%d liveness data\n", liveness)
+ fmt.Fprintf(Bso, "%5.2f cpu time\n", obj.Cputime())
+ fmt.Fprintf(Bso, "%d symbols\n", len(Ctxt.Allsym))
+ fmt.Fprintf(Bso, "%d liveness data\n", liveness)
}
Bso.Flush()
diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go
index 3deb94644e..76fe7dab79 100644
--- a/src/cmd/link/internal/ld/sym.go
+++ b/src/cmd/link/internal/ld/sym.go
@@ -33,6 +33,7 @@ package ld
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"log"
"strconv"
)
@@ -55,7 +56,7 @@ var headers = []struct {
{"windowsgui", obj.Hwindows},
}
-func linknew(arch *LinkArch) *Link {
+func linknew(arch *sys.Arch) *Link {
ctxt := &Link{
Hash: []map[string]*LSym{
// preallocate about 2mb for hash of
@@ -98,33 +99,33 @@ func linknew(arch *LinkArch) *Link {
obj.Hdragonfly,
obj.Hsolaris:
if obj.Getgoos() == "android" {
- switch ctxt.Arch.Thechar {
- case '6':
+ switch ctxt.Arch.Family {
+ case sys.AMD64:
// Android/amd64 constant - offset from 0(FS) to our TLS slot.
// Explained in src/runtime/cgo/gcc_android_*.c
ctxt.Tlsoffset = 0x1d0
- case '8':
+ case sys.I386:
// Android/386 constant - offset from 0(GS) to our TLS slot.
ctxt.Tlsoffset = 0xf8
default:
- ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
+ ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize
}
} else {
- ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
+ ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize
}
case obj.Hnacl:
- switch ctxt.Arch.Thechar {
+ switch ctxt.Arch.Family {
default:
log.Fatalf("unknown thread-local storage offset for nacl/%s", ctxt.Arch.Name)
- case '5':
+ case sys.ARM:
ctxt.Tlsoffset = 0
- case '6':
+ case sys.AMD64:
ctxt.Tlsoffset = 0
- case '8':
+ case sys.I386:
ctxt.Tlsoffset = -8
}
@@ -133,26 +134,26 @@ func linknew(arch *LinkArch) *Link {
* Explained in src/runtime/cgo/gcc_darwin_*.c.
*/
case obj.Hdarwin:
- switch ctxt.Arch.Thechar {
+ switch ctxt.Arch.Family {
default:
log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name)
- case '5':
+ case sys.ARM:
ctxt.Tlsoffset = 0 // dummy value, not needed
- case '6':
+ case sys.AMD64:
ctxt.Tlsoffset = 0x8a0
- case '7':
+ case sys.ARM64:
ctxt.Tlsoffset = 0 // dummy value, not needed
- case '8':
+ case sys.I386:
ctxt.Tlsoffset = 0x468
}
}
// On arm, record goarm.
- if ctxt.Arch.Thechar == '5' {
+ if ctxt.Arch.Family == sys.ARM {
ctxt.Goarm = obj.Getgoarm()
}
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index 3258bc1ff9..94a6d0ab29 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -32,6 +32,7 @@ package ld
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"fmt"
"path/filepath"
"strings"
@@ -53,21 +54,14 @@ func putelfstr(s string) int {
s = strings.Replace(s, "·", ".", -1)
}
- n := len(s) + 1
- for len(Elfstrdat)+n > cap(Elfstrdat) {
- Elfstrdat = append(Elfstrdat[:cap(Elfstrdat)], 0)[:len(Elfstrdat)]
- }
-
off := len(Elfstrdat)
- Elfstrdat = Elfstrdat[:off+n]
- copy(Elfstrdat[off:], s)
-
+ Elfstrdat = append(Elfstrdat, s...)
+ Elfstrdat = append(Elfstrdat, 0)
return off
}
func putelfsyment(off int, addr int64, size int64, info int, shndx int, other int) {
- switch Thearch.Thechar {
- case '0', '6', '7', '9', 'z':
+ if elf64 {
Thearch.Lput(uint32(off))
Cput(uint8(info))
Cput(uint8(other))
@@ -75,8 +69,7 @@ func putelfsyment(off int, addr int64, size int64, info int, shndx int, other in
Thearch.Vput(uint64(addr))
Thearch.Vput(uint64(size))
Symsize += ELF64SYMSIZE
-
- default:
+ } else {
Thearch.Lput(uint32(off))
Thearch.Lput(uint32(addr))
Thearch.Lput(uint32(size))
@@ -162,7 +155,7 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
if x.Type&obj.SHIDDEN != 0 {
other = STV_HIDDEN
}
- if (Buildmode == BuildmodePIE || DynlinkingGo()) && Thearch.Thechar == '9' && type_ == STT_FUNC && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" {
+ if (Buildmode == BuildmodePIE || DynlinkingGo()) && SysArch.Family == sys.PPC64 && type_ == STT_FUNC && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" {
// On ppc64 the top three bits of the st_other field indicate how
// many instructions separate the global and local entry points. In
// our case it is two instructions, indicated by the value 3.
@@ -197,18 +190,6 @@ func putelfsectionsym(s *LSym, shndx int) {
numelfsym++
}
-func putelfsymshndx(sympos int64, shndx int) {
- here := Cpos()
- if elf64 {
- Cseek(sympos + 6)
- } else {
- Cseek(sympos + 14)
- }
-
- Thearch.Wput(uint16(shndx))
- Cseek(here)
-}
-
func Asmelfsym() {
// the first symbol entry is reserved
putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0)
@@ -217,7 +198,9 @@ func Asmelfsym() {
// Some linkers will add a FILE sym if one is not present.
// Avoid having the working directory inserted into the symbol table.
- putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_FILE, SHN_ABS, 0)
+ // It is added with a name to avoid problems with external linking
+ // encountered on some versions of Solaris. See issue #14957.
+ putelfsyment(putelfstr("go.go"), 0, 0, STB_LOCAL<<4|STT_FILE, SHN_ABS, 0)
numelfsym++
elfbind = STB_LOCAL
@@ -243,7 +226,7 @@ func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_
'Z',
'm':
l := 4
- if HEADTYPE == obj.Hplan9 && Thearch.Thechar == '6' && Debug['8'] == 0 {
+ if HEADTYPE == obj.Hplan9 && SysArch.Family == sys.AMD64 && Debug['8'] == 0 {
Lputb(uint32(addr >> 32))
l = 8
}
@@ -253,10 +236,10 @@ func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_
var i int
if t == 'z' || t == 'Z' {
- Cput(uint8(s[0]))
+ Cput(s[0])
for i = 1; s[i] != 0 || s[i+1] != 0; i += 2 {
- Cput(uint8(s[i]))
- Cput(uint8(s[i+1]))
+ Cput(s[i])
+ Cput(s[i+1])
}
Cput(0)
@@ -268,7 +251,7 @@ func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_
s = s[1:]
}
for i = 0; i < len(s); i++ {
- Cput(uint8(s[i]))
+ Cput(s[i])
}
Cput(0)
}
@@ -346,6 +329,8 @@ func symtab() {
xdefine("runtime.eitablink", obj.SRODATA, 0)
xdefine("runtime.rodata", obj.SRODATA, 0)
xdefine("runtime.erodata", obj.SRODATA, 0)
+ xdefine("runtime.types", obj.SRODATA, 0)
+ xdefine("runtime.etypes", obj.SRODATA, 0)
xdefine("runtime.noptrdata", obj.SNOPTRDATA, 0)
xdefine("runtime.enoptrdata", obj.SNOPTRDATA, 0)
xdefine("runtime.data", obj.SDATA, 0)
@@ -399,33 +384,19 @@ func symtab() {
symtyperel = s
}
- s = Linklookup(Ctxt, "go.string.*", 0)
- s.Type = obj.SGOSTRING
- s.Attr |= AttrLocal
- s.Size = 0
- s.Attr |= AttrReachable
- symgostring := s
-
- s = Linklookup(Ctxt, "go.string.hdr.*", 0)
- s.Type = obj.SGOSTRINGHDR
- s.Attr |= AttrLocal
- s.Size = 0
- s.Attr |= AttrReachable
- symgostringhdr := s
-
- s = Linklookup(Ctxt, "go.func.*", 0)
- s.Type = obj.SGOFUNC
- s.Attr |= AttrLocal
- s.Size = 0
- s.Attr |= AttrReachable
- symgofunc := s
-
- s = Linklookup(Ctxt, "runtime.gcbits.*", 0)
- s.Type = obj.SGCBITS
- s.Attr |= AttrLocal
- s.Size = 0
- s.Attr |= AttrReachable
- symgcbits := s
+ groupSym := func(name string, t int16) *LSym {
+ s := Linklookup(Ctxt, name, 0)
+ s.Type = t
+ s.Size = 0
+ s.Attr |= AttrLocal | AttrReachable
+ return s
+ }
+ var (
+ symgostring = groupSym("go.string.*", obj.SGOSTRING)
+ symgostringhdr = groupSym("go.string.hdr.*", obj.SGOSTRINGHDR)
+ symgofunc = groupSym("go.func.*", obj.SGOFUNC)
+ symgcbits = groupSym("runtime.gcbits.*", obj.SGCBITS)
+ )
symtypelink := Linklookup(Ctxt, "runtime.typelink", 0)
symtypelink.Type = obj.STYPELINK
@@ -451,34 +422,37 @@ func symtab() {
continue
}
- if strings.HasPrefix(s.Name, "type.") {
+ switch {
+ case strings.HasPrefix(s.Name, "type."):
if !DynlinkingGo() {
s.Attr |= AttrHidden
}
- if UseRelro() && len(s.R) > 0 {
+ if UseRelro() {
s.Type = obj.STYPERELRO
s.Outer = symtyperel
} else {
s.Type = obj.STYPE
s.Outer = symtype
}
- }
- if strings.HasPrefix(s.Name, "go.typelink.") {
+ case strings.HasPrefix(s.Name, "go.importpath.") && UseRelro():
+ // Keep go.importpath symbols in the same section as types and
+ // names, as they can be referred to by a section offset.
+ s.Type = obj.STYPERELRO
+
+ case strings.HasPrefix(s.Name, "go.typelink."):
ntypelinks++
s.Type = obj.STYPELINK
s.Attr |= AttrHidden
s.Outer = symtypelink
- }
- if strings.HasPrefix(s.Name, "go.itablink.") {
+ case strings.HasPrefix(s.Name, "go.itablink."):
nitablinks++
s.Type = obj.SITABLINK
s.Attr |= AttrHidden
s.Outer = symitablink
- }
- if strings.HasPrefix(s.Name, "go.string.") {
+ case strings.HasPrefix(s.Name, "go.string."):
s.Type = obj.SGOSTRING
s.Attr |= AttrHidden
s.Outer = symgostring
@@ -486,21 +460,18 @@ func symtab() {
s.Type = obj.SGOSTRINGHDR
s.Outer = symgostringhdr
}
- }
- if strings.HasPrefix(s.Name, "runtime.gcbits.") {
+ case strings.HasPrefix(s.Name, "runtime.gcbits."):
s.Type = obj.SGCBITS
s.Attr |= AttrHidden
s.Outer = symgcbits
- }
- if strings.HasPrefix(s.Name, "go.func.") {
+ case strings.HasPrefix(s.Name, "go.func."):
s.Type = obj.SGOFUNC
s.Attr |= AttrHidden
s.Outer = symgofunc
- }
- if strings.HasPrefix(s.Name, "gcargs.") || strings.HasPrefix(s.Name, "gclocals.") || strings.HasPrefix(s.Name, "gclocals·") {
+ case strings.HasPrefix(s.Name, "gcargs."), strings.HasPrefix(s.Name, "gclocals."), strings.HasPrefix(s.Name, "gclocals·"):
s.Type = obj.SGOFUNC
s.Attr |= AttrHidden
s.Outer = symgofunc
@@ -533,8 +504,8 @@ func symtab() {
adduint(Ctxt, moduledata, uint64(pclntabNfunc+1))
// The filetab slice
Addaddrplus(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0), int64(pclntabFiletabOffset))
- adduint(Ctxt, moduledata, uint64(Ctxt.Nhistfile)+1)
- adduint(Ctxt, moduledata, uint64(Ctxt.Nhistfile)+1)
+ adduint(Ctxt, moduledata, uint64(len(Ctxt.Filesyms))+1)
+ adduint(Ctxt, moduledata, uint64(len(Ctxt.Filesyms))+1)
// findfunctab
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.findfunctab", 0))
// minpc, maxpc
@@ -554,6 +525,8 @@ func symtab() {
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.end", 0))
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcdata", 0))
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcbss", 0))
+ Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.types", 0))
+ Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.etypes", 0))
// The typelinks slice
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0))
adduint(Ctxt, moduledata, uint64(ntypelinks))
diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go
index 8249c54e45..785002b02c 100644
--- a/src/cmd/link/internal/mips64/asm.go
+++ b/src/cmd/link/internal/mips64/asm.go
@@ -32,6 +32,7 @@ package mips64
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"cmd/link/internal/ld"
"encoding/binary"
"fmt"
@@ -40,10 +41,6 @@ import (
func gentext() {}
-func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
- log.Fatalf("adddynrela not implemented")
-}
-
func adddynrel(s *ld.LSym, r *ld.Reloc) {
log.Fatalf("adddynrel not implemented")
}
@@ -82,8 +79,8 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
// the first instruction is always at the lower address, this is endian neutral;
// but note that o1 and o2 should still use the target endian.
- o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off:])
- o2 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4:])
+ o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
+ o2 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off+4:])
o1 = o1&0xffff0000 | uint32(t>>16)&0xffff
o2 = o2&0xffff0000 | uint32(t)&0xffff
@@ -99,7 +96,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
obj.R_JMPMIPS:
// Low 26 bits = (S + A) >> 2
t := ld.Symaddr(r.Sym) + r.Add
- o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off:])
+ o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
*val = int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000)
return 0
}
@@ -113,7 +110,7 @@ func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
func asmb() {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
}
ld.Bso.Flush()
@@ -131,7 +128,7 @@ func asmb() {
if ld.Segrodata.Filelen > 0 {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
}
ld.Bso.Flush()
@@ -140,13 +137,16 @@ func asmb() {
}
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
}
ld.Bso.Flush()
ld.Cseek(int64(ld.Segdata.Fileoff))
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.Cseek(int64(ld.Segdwarf.Fileoff))
+ ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+
/* output symbol table */
ld.Symsize = 0
@@ -155,13 +155,13 @@ func asmb() {
if ld.Debug['s'] == 0 {
// TODO: rationalize
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
}
ld.Bso.Flush()
switch ld.HEADTYPE {
default:
if ld.Iself {
- symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+ symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
}
@@ -174,17 +174,12 @@ func asmb() {
default:
if ld.Iself {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime())
}
ld.Asmelfsym()
ld.Cflush()
ld.Cwrite(ld.Elfstrdat)
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
- }
- ld.Dwarfemitdebugsections()
-
if ld.Linkmode == ld.LinkExternal {
ld.Elfemitreloc()
}
@@ -198,7 +193,7 @@ func asmb() {
if sym != nil {
ld.Lcsize = int32(len(sym.P))
for i := 0; int32(i) < ld.Lcsize; i++ {
- ld.Cput(uint8(sym.P[i]))
+ ld.Cput(sym.P[i])
}
ld.Cflush()
@@ -208,7 +203,7 @@ func asmb() {
ld.Ctxt.Cursym = nil
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime())
}
ld.Bso.Flush()
ld.Cseek(0)
@@ -216,10 +211,10 @@ func asmb() {
default:
case obj.Hplan9: /* plan 9 */
magic := uint32(4*18*18 + 7)
- if ld.Thestring == "mips64le" {
+ if ld.SysArch == sys.ArchMIPS64LE {
magic = uint32(4*26*26 + 7)
}
- ld.Thearch.Lput(uint32(magic)) /* magic */
+ ld.Thearch.Lput(magic) /* magic */
ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
diff --git a/src/cmd/link/internal/mips64/l.go b/src/cmd/link/internal/mips64/l.go
index 003ee5ce71..f4191e69ab 100644
--- a/src/cmd/link/internal/mips64/l.go
+++ b/src/cmd/link/internal/mips64/l.go
@@ -62,11 +62,9 @@ package mips64
// THE SOFTWARE.
const (
- thechar = '0'
MaxAlign = 32 // max data alignment
MinAlign = 1 // min data alignment
FuncAlign = 8
- MINLC = 4
)
/* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/mips64/obj.go b/src/cmd/link/internal/mips64/obj.go
index 57a1b2ab14..87bb3a079b 100644
--- a/src/cmd/link/internal/mips64/obj.go
+++ b/src/cmd/link/internal/mips64/obj.go
@@ -32,6 +32,7 @@ package mips64
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
"log"
@@ -45,21 +46,15 @@ func Main() {
}
func linkarchinit() {
- ld.Thestring = obj.Getgoarch()
- if ld.Thestring == "mips64le" {
- ld.Thelinkarch = &ld.Linkmips64le
+ if obj.Getgoarch() == "mips64le" {
+ ld.SysArch = sys.ArchMIPS64LE
} else {
- ld.Thelinkarch = &ld.Linkmips64
+ ld.SysArch = sys.ArchMIPS64
}
- ld.Thearch.Thechar = thechar
- ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
- ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
- ld.Thearch.Regsize = ld.Thelinkarch.Regsize
ld.Thearch.Funcalign = FuncAlign
ld.Thearch.Maxalign = MaxAlign
ld.Thearch.Minalign = MinAlign
- ld.Thearch.Minlc = MINLC
ld.Thearch.Dwarfregsp = DWARFREGSP
ld.Thearch.Dwarfreglr = DWARFREGLR
@@ -72,7 +67,7 @@ func linkarchinit() {
ld.Thearch.Elfsetupplt = elfsetupplt
ld.Thearch.Gentext = gentext
ld.Thearch.Machoreloc1 = machoreloc1
- if ld.Thelinkarch == &ld.Linkmips64le {
+ if ld.SysArch == sys.ArchMIPS64LE {
ld.Thearch.Lput = ld.Lputl
ld.Thearch.Wput = ld.Wputl
ld.Thearch.Vput = ld.Vputl
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index ae69799abf..dbf5fac0de 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -39,14 +39,6 @@ import (
)
func genplt() {
- var s *ld.LSym
- var stub *ld.LSym
- var pprevtextp **ld.LSym
- var r *ld.Reloc
- var n string
- var o1 uint32
- var i int
-
// The ppc64 ABI PLT has similar concepts to other
// architectures, but is laid out quite differently. When we
// see an R_PPC64_REL24 relocation to a dynamic symbol
@@ -95,11 +87,9 @@ func genplt() {
//
// This assumes "case 1" from the ABI, where the caller needs
// us to save and restore the TOC pointer.
- pprevtextp = &ld.Ctxt.Textp
-
- for s = *pprevtextp; s != nil; pprevtextp, s = &s.Next, s.Next {
- for i = range s.R {
- r = &s.R[i]
+ for _, s := range ld.Ctxt.Textp {
+ for i := range s.R {
+ r := &s.R[i]
if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != obj.SDYNIMPORT {
continue
}
@@ -109,24 +99,16 @@ func genplt() {
addpltsym(ld.Ctxt, r.Sym)
// Generate call stub
- n = fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
+ n := fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
- stub = ld.Linklookup(ld.Ctxt, n, 0)
+ stub := ld.Linklookup(ld.Ctxt, n, 0)
if s.Attr.Reachable() {
stub.Attr |= ld.AttrReachable
}
if stub.Size == 0 {
// Need outer to resolve .TOC.
stub.Outer = s
-
- // Link in to textp before s (we could
- // do it after, but would have to skip
- // the subsymbols)
- *pprevtextp = stub
-
- stub.Next = s
- pprevtextp = &stub.Next
-
+ ld.Ctxt.Textp = append(ld.Ctxt.Textp, stub)
gencallstub(1, stub, r.Sym)
}
@@ -135,11 +117,10 @@ func genplt() {
// Restore TOC after bl. The compiler put a
// nop here for us to overwrite.
- o1 = 0xe8410018 // ld r2,24(r1)
+ const o1 = 0xe8410018 // ld r2,24(r1)
ld.Ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off+4:], o1)
}
}
-
}
func genaddmoduledata() {
@@ -195,13 +176,7 @@ func genaddmoduledata() {
// blr
o(0x4e800020)
- if ld.Ctxt.Etextp != nil {
- ld.Ctxt.Etextp.Next = initfunc
- } else {
- ld.Ctxt.Textp = initfunc
- }
- ld.Ctxt.Etextp = initfunc
-
+ ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
initarray_entry.Attr |= ld.AttrReachable
initarray_entry.Attr |= ld.AttrLocal
@@ -265,10 +240,6 @@ func gencallstub(abicase int, stub *ld.LSym, targ *ld.LSym) {
ld.Adduint32(ld.Ctxt, stub, 0x4e800420) // bctr
}
-func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
- log.Fatalf("adddynrela not implemented")
-}
-
func adddynrel(s *ld.LSym, r *ld.Reloc) {
targ := r.Sym
ld.Ctxt.Cursym = s
@@ -834,7 +805,7 @@ func ensureglinkresolver() *ld.LSym {
func asmb() {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
}
ld.Bso.Flush()
@@ -852,7 +823,7 @@ func asmb() {
if ld.Segrodata.Filelen > 0 {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
}
ld.Bso.Flush()
@@ -861,13 +832,16 @@ func asmb() {
}
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
}
ld.Bso.Flush()
ld.Cseek(int64(ld.Segdata.Fileoff))
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.Cseek(int64(ld.Segdwarf.Fileoff))
+ ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+
/* output symbol table */
ld.Symsize = 0
@@ -876,13 +850,13 @@ func asmb() {
if ld.Debug['s'] == 0 {
// TODO: rationalize
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
}
ld.Bso.Flush()
switch ld.HEADTYPE {
default:
if ld.Iself {
- symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+ symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
}
@@ -895,17 +869,12 @@ func asmb() {
default:
if ld.Iself {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime())
}
ld.Asmelfsym()
ld.Cflush()
ld.Cwrite(ld.Elfstrdat)
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
- }
- ld.Dwarfemitdebugsections()
-
if ld.Linkmode == ld.LinkExternal {
ld.Elfemitreloc()
}
@@ -919,7 +888,7 @@ func asmb() {
if sym != nil {
ld.Lcsize = int32(len(sym.P))
for i := 0; int32(i) < ld.Lcsize; i++ {
- ld.Cput(uint8(sym.P[i]))
+ ld.Cput(sym.P[i])
}
ld.Cflush()
@@ -929,7 +898,7 @@ func asmb() {
ld.Ctxt.Cursym = nil
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime())
}
ld.Bso.Flush()
ld.Cseek(0)
diff --git a/src/cmd/link/internal/ppc64/l.go b/src/cmd/link/internal/ppc64/l.go
index 622d6bb12e..a720993fbc 100644
--- a/src/cmd/link/internal/ppc64/l.go
+++ b/src/cmd/link/internal/ppc64/l.go
@@ -62,11 +62,9 @@ package ppc64
// THE SOFTWARE.
const (
- thechar = '9'
MaxAlign = 32 // max data alignment
MinAlign = 1 // min data alignment
FuncAlign = 8
- MINLC = 4
)
/* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/ppc64/obj.go b/src/cmd/link/internal/ppc64/obj.go
index 539ab1ac02..a540ab85b5 100644
--- a/src/cmd/link/internal/ppc64/obj.go
+++ b/src/cmd/link/internal/ppc64/obj.go
@@ -32,6 +32,7 @@ package ppc64
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
"log"
@@ -45,21 +46,15 @@ func Main() {
}
func linkarchinit() {
- ld.Thestring = obj.Getgoarch()
- if ld.Thestring == "ppc64le" {
- ld.Thelinkarch = &ld.Linkppc64le
+ if obj.Getgoarch() == "ppc64le" {
+ ld.SysArch = sys.ArchPPC64LE
} else {
- ld.Thelinkarch = &ld.Linkppc64
+ ld.SysArch = sys.ArchPPC64
}
- ld.Thearch.Thechar = thechar
- ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
- ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
- ld.Thearch.Regsize = ld.Thelinkarch.Regsize
ld.Thearch.Funcalign = FuncAlign
ld.Thearch.Maxalign = MaxAlign
ld.Thearch.Minalign = MinAlign
- ld.Thearch.Minlc = MINLC
ld.Thearch.Dwarfregsp = DWARFREGSP
ld.Thearch.Dwarfreglr = DWARFREGLR
@@ -72,7 +67,7 @@ func linkarchinit() {
ld.Thearch.Elfsetupplt = elfsetupplt
ld.Thearch.Gentext = gentext
ld.Thearch.Machoreloc1 = machoreloc1
- if ld.Thelinkarch == &ld.Linkppc64le {
+ if ld.SysArch == sys.ArchPPC64LE {
ld.Thearch.Lput = ld.Lputl
ld.Thearch.Wput = ld.Wputl
ld.Thearch.Vput = ld.Vputl
@@ -150,7 +145,7 @@ func archinit() {
}
case obj.Hlinux: /* ppc64 elf */
- if ld.Thestring == "ppc64" {
+ if ld.SysArch == sys.ArchPPC64 {
ld.Debug['d'] = 1 // TODO(austin): ELF ABI v1 not supported yet
}
ld.Elfinit()
diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go
index 75a8206174..7c2e3358ff 100644
--- a/src/cmd/link/internal/s390x/asm.go
+++ b/src/cmd/link/internal/s390x/asm.go
@@ -90,12 +90,7 @@ func gentext() {
// undef (for debugging)
ld.Adduint32(ld.Ctxt, initfunc, 0)
- if ld.Ctxt.Etextp != nil {
- ld.Ctxt.Etextp.Next = initfunc
- } else {
- ld.Ctxt.Textp = initfunc
- }
- ld.Ctxt.Etextp = initfunc
+ ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
initarray_entry.Attr |= ld.AttrLocal
initarray_entry.Attr |= ld.AttrReachable
@@ -505,7 +500,7 @@ func addgotsym(s *ld.LSym) {
func asmb() {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
}
ld.Bso.Flush()
@@ -523,7 +518,7 @@ func asmb() {
if ld.Segrodata.Filelen > 0 {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
}
ld.Bso.Flush()
@@ -532,13 +527,16 @@ func asmb() {
}
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
}
ld.Bso.Flush()
ld.Cseek(int64(ld.Segdata.Fileoff))
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.Cseek(int64(ld.Segdwarf.Fileoff))
+ ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+
/* output symbol table */
ld.Symsize = 0
@@ -549,24 +547,23 @@ func asmb() {
ld.Diag("unsupported executable format")
}
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
}
ld.Bso.Flush()
- symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+ symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
ld.Cseek(int64(symo))
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime())
}
ld.Asmelfsym()
ld.Cflush()
ld.Cwrite(ld.Elfstrdat)
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime())
}
- ld.Dwarfemitdebugsections()
if ld.Linkmode == ld.LinkExternal {
ld.Elfemitreloc()
@@ -575,7 +572,7 @@ func asmb() {
ld.Ctxt.Cursym = nil
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime())
}
ld.Bso.Flush()
ld.Cseek(0)
diff --git a/src/cmd/link/internal/s390x/l.go b/src/cmd/link/internal/s390x/l.go
index 839a9849c8..42cf15ee85 100644
--- a/src/cmd/link/internal/s390x/l.go
+++ b/src/cmd/link/internal/s390x/l.go
@@ -62,14 +62,9 @@ package s390x
// THE SOFTWARE.
const (
- thechar = 'z'
- PtrSize = 8
- IntSize = 8
- RegSize = 8
MaxAlign = 32 // max data alignment
MinAlign = 2 // min data alignment
FuncAlign = 16
- MINLC = 2
)
/* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/s390x/obj.go b/src/cmd/link/internal/s390x/obj.go
index ef88d22bbd..fdb9898181 100644
--- a/src/cmd/link/internal/s390x/obj.go
+++ b/src/cmd/link/internal/s390x/obj.go
@@ -32,6 +32,7 @@ package s390x
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
)
@@ -44,17 +45,11 @@ func Main() {
}
func linkarchinit() {
- ld.Thestring = obj.Getgoarch()
- ld.Thelinkarch = &ld.Links390x
+ ld.SysArch = sys.ArchS390X
- ld.Thearch.Thechar = thechar
- ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
- ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
- ld.Thearch.Regsize = ld.Thelinkarch.Regsize
ld.Thearch.Funcalign = FuncAlign
ld.Thearch.Maxalign = MaxAlign
ld.Thearch.Minalign = MinAlign
- ld.Thearch.Minlc = MINLC
ld.Thearch.Dwarfregsp = DWARFREGSP
ld.Thearch.Dwarfreglr = DWARFREGLR
diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go
index 97fccf3ee6..4a55b535ac 100644
--- a/src/cmd/link/internal/x86/asm.go
+++ b/src/cmd/link/internal/x86/asm.go
@@ -69,12 +69,7 @@ func gentext() {
// c3 ret
o(0xc3)
- if ld.Ctxt.Etextp != nil {
- ld.Ctxt.Etextp.Next = thunkfunc
- } else {
- ld.Ctxt.Textp = thunkfunc
- }
- ld.Ctxt.Etextp = thunkfunc
+ ld.Ctxt.Textp = append(ld.Ctxt.Textp, thunkfunc)
addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
if addmoduledata.Type == obj.STEXT {
@@ -130,8 +125,7 @@ func gentext() {
o(0xc3)
- ld.Ctxt.Etextp.Next = initfunc
- ld.Ctxt.Etextp = initfunc
+ ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
initarray_entry.Attr |= ld.AttrReachable
initarray_entry.Attr |= ld.AttrLocal
@@ -139,10 +133,6 @@ func gentext() {
ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
}
-func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) {
- log.Fatalf("adddynrela not implemented")
-}
-
func adddynrel(s *ld.LSym, r *ld.Reloc) {
targ := r.Sym
ld.Ctxt.Cursym = s
@@ -292,7 +282,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
return
}
- if ld.HEADTYPE == obj.Hdarwin && s.Size == PtrSize && r.Off == 0 {
+ if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 {
// Mach-O relocations are a royal pain to lay out.
// They use a compact stateful bytecode representation
// that is too much bother to deal with.
@@ -317,7 +307,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
return
}
- if ld.HEADTYPE == obj.Hwindows && s.Size == PtrSize {
+ if ld.HEADTYPE == obj.Hwindows && s.Size == int64(ld.SysArch.PtrSize) {
// nothing to do, the relocation will be laid out in pereloc1
return
}
@@ -609,7 +599,7 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) {
func asmb() {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
}
ld.Bso.Flush()
@@ -627,7 +617,7 @@ func asmb() {
if ld.Segrodata.Filelen > 0 {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
}
ld.Bso.Flush()
@@ -636,26 +626,18 @@ func asmb() {
}
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
}
ld.Bso.Flush()
ld.Cseek(int64(ld.Segdata.Fileoff))
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.Cseek(int64(ld.Segdwarf.Fileoff))
+ ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+
machlink := uint32(0)
if ld.HEADTYPE == obj.Hdarwin {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
- }
-
- 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
-
machlink = uint32(ld.Domacholink())
}
@@ -666,13 +648,13 @@ func asmb() {
if ld.Debug['s'] == 0 {
// TODO: rationalize
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
}
ld.Bso.Flush()
switch ld.HEADTYPE {
default:
if ld.Iself {
- symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+ symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
}
@@ -683,7 +665,7 @@ func asmb() {
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)
+ symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
}
@@ -692,17 +674,12 @@ func asmb() {
default:
if ld.Iself {
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime())
}
ld.Asmelfsym()
ld.Cflush()
ld.Cwrite(ld.Elfstrdat)
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
- }
- ld.Dwarfemitdebugsections()
-
if ld.Linkmode == ld.LinkExternal {
ld.Elfemitreloc()
}
@@ -716,7 +693,7 @@ func asmb() {
if sym != nil {
ld.Lcsize = int32(len(sym.P))
for i := 0; int32(i) < ld.Lcsize; i++ {
- ld.Cput(uint8(sym.P[i]))
+ ld.Cput(sym.P[i])
}
ld.Cflush()
@@ -724,9 +701,8 @@ func asmb() {
case obj.Hwindows:
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime())
}
- ld.Dwarfemitdebugsections()
case obj.Hdarwin:
if ld.Linkmode == ld.LinkExternal {
@@ -736,7 +712,7 @@ func asmb() {
}
if ld.Debug['v'] != 0 {
- fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
+ fmt.Fprintf(ld.Bso, "%5.2f headr\n", obj.Cputime())
}
ld.Bso.Flush()
ld.Cseek(0)
diff --git a/src/cmd/link/internal/x86/l.go b/src/cmd/link/internal/x86/l.go
index 068fed9c8d..2043f9bb4e 100644
--- a/src/cmd/link/internal/x86/l.go
+++ b/src/cmd/link/internal/x86/l.go
@@ -31,12 +31,9 @@
package x86
const (
- thechar = '8'
- PtrSize = 4
MaxAlign = 32 // max data alignment
MinAlign = 1 // min data alignment
FuncAlign = 16
- MINLC = 1
)
/* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/x86/obj.go b/src/cmd/link/internal/x86/obj.go
index 4380c41ebb..574c0dad2d 100644
--- a/src/cmd/link/internal/x86/obj.go
+++ b/src/cmd/link/internal/x86/obj.go
@@ -32,6 +32,7 @@ package x86
import (
"cmd/internal/obj"
+ "cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
"log"
@@ -45,17 +46,11 @@ func Main() {
}
func linkarchinit() {
- ld.Thestring = "386"
- ld.Thelinkarch = &ld.Link386
+ ld.SysArch = sys.Arch386
- ld.Thearch.Thechar = thechar
- ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
- ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
- ld.Thearch.Regsize = ld.Thelinkarch.Regsize
ld.Thearch.Funcalign = FuncAlign
ld.Thearch.Maxalign = MaxAlign
ld.Thearch.Minalign = MinAlign
- ld.Thearch.Minlc = MINLC
ld.Thearch.Dwarfregsp = DWARFREGSP
ld.Thearch.Dwarfreglr = DWARFREGLR
diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go
new file mode 100644
index 0000000000..4ef184518e
--- /dev/null
+++ b/src/cmd/link/link_test.go
@@ -0,0 +1,30 @@
+package main
+
+import "testing"
+
+var AuthorPaidByTheColumnInch struct {
+ fog int `
+ London. Michaelmas term lately over, and the Lord Chancellor sitting in Lincoln’s Inn Hall. Implacable November weather. As much mud in the streets as if the waters had but newly retired from the face of the earth, and it would not be wonderful to meet a Megalosaurus, forty feet long or so, waddling like an elephantine lizard up Holborn Hill. Smoke lowering down from chimney-pots, making a soft black drizzle, with flakes of soot in it as big as full-grown snowflakes—gone into mourning, one might imagine, for the death of the sun. Dogs, undistinguishable in mire. Horses, scarcely better; splashed to their very blinkers. Foot passengers, jostling one another’s umbrellas in a general infection of ill temper, and losing their foot-hold at street-corners, where tens of thousands of other foot passengers have been slipping and sliding since the day broke (if this day ever broke), adding new deposits to the crust upon crust of mud, sticking at those points tenaciously to the pavement, and accumulating at compound interest.
+
+ Fog everywhere. Fog up the river, where it flows among green aits and meadows; fog down the river, where it rolls defiled among the tiers of shipping and the waterside pollutions of a great (and dirty) city. Fog on the Essex marshes, fog on the Kentish heights. Fog creeping into the cabooses of collier-brigs; fog lying out on the yards and hovering in the rigging of great ships; fog drooping on the gunwales of barges and small boats. Fog in the eyes and throats of ancient Greenwich pensioners, wheezing by the firesides of their wards; fog in the stem and bowl of the afternoon pipe of the wrathful skipper, down in his close cabin; fog cruelly pinching the toes and fingers of his shivering little ‘prentice boy on deck. Chance people on the bridges peeping over the parapets into a nether sky of fog, with fog all round them, as if they were up in a balloon and hanging in the misty clouds.
+
+ Gas looming through the fog in divers places in the streets, much as the sun may, from the spongey fields, be seen to loom by husbandman and ploughboy. Most of the shops lighted two hours before their time—as the gas seems to know, for it has a haggard and unwilling look.
+
+ The raw afternoon is rawest, and the dense fog is densest, and the muddy streets are muddiest near that leaden-headed old obstruction, appropriate ornament for the threshold of a leaden-headed old corporation, Temple Bar. And hard by Temple Bar, in Lincoln’s Inn Hall, at the very heart of the fog, sits the Lord High Chancellor in his High Court of Chancery.`
+
+ wind int `
+ It was grand to see how the wind awoke, and bent the trees, and drove the rain before it like a cloud of smoke; and to hear the solemn thunder, and to see the lightning; and while thinking with awe of the tremendous powers by which our little lives are encompassed, to consider how beneficent they are, and how upon the smallest flower and leaf there was already a freshness poured from all this seeming rage, which seemed to make creation new again.`
+
+ jarndyce int `
+ Jarndyce and Jarndyce drones on. This scarecrow of a suit has, over the course of time, become so complicated, that no man alive knows what it means. The parties to it understand it least; but it has been observed that no two Chancery lawyers can talk about it for five minutes, without coming to a total disagreement as to all the premises. Innumerable children have been born into the cause; innumerable young people have married into it; innumerable old people have died out of it. Scores of persons have deliriously found themselves made parties in Jarndyce and Jarndyce, without knowing how or why; whole families have inherited legendary hatreds with the suit. The little plaintiff or defendant, who was promised a new rocking-horse when Jarndyce and Jarndyce should be settled, has grown up, possessed himself of a real horse, and trotted away into the other world. Fair wards of court have faded into mothers and grandmothers; a long procession of Chancellors has come in and gone out; the legion of bills in the suit have been transformed into mere bills of mortality; there are not three Jarndyces left upon the earth perhaps, since old Tom Jarndyce in despair blew his brains out at a coffee-house in Chancery Lane; but Jarndyce and Jarndyce still drags its dreary length before the Court, perennially hopeless.`
+
+ principle int `
+ The one great principle of the English law is, to make business for itself. There is no other principle distinctly, certainly, and consistently maintained through all its narrow turnings. Viewed by this light it becomes a coherent scheme, and not the monstrous maze the laity are apt to think it. Let them but once clearly perceive that its grand principle is to make business for itself at their expense, and surely they will cease to grumble.`
+}
+
+func TestLargeSymName(t *testing.T) {
+ // The compiler generates a symbol name using the string form of the
+ // type. This tests that the linker can read symbol names larger than
+ // the bufio buffer. Issue #15104.
+ _ = AuthorPaidByTheColumnInch
+}
diff --git a/src/cmd/link/main.go b/src/cmd/link/main.go
index e52b718699..f92e02eac3 100644
--- a/src/cmd/link/main.go
+++ b/src/cmd/link/main.go
@@ -11,6 +11,7 @@ import (
"cmd/link/internal/arm64"
"cmd/link/internal/mips64"
"cmd/link/internal/ppc64"
+ "cmd/link/internal/s390x"
"cmd/link/internal/x86"
"fmt"
"os"
@@ -33,5 +34,7 @@ func main() {
mips64.Main()
case "ppc64", "ppc64le":
ppc64.Main()
+ case "s390x":
+ s390x.Main()
}
}
diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
index 8ceaba078c..899db06324 100644
--- a/src/cmd/objdump/objdump_test.go
+++ b/src/cmd/objdump/objdump_test.go
@@ -107,6 +107,8 @@ func TestDisasm(t *testing.T) {
t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
case "mips64", "mips64le":
t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
+ case "s390x":
+ t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
}
testDisasm(t)
}
@@ -123,6 +125,8 @@ func TestDisasmExtld(t *testing.T) {
t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
case "mips64", "mips64le":
t.Skipf("skipping on %s, issue 12559 and 12560", runtime.GOARCH)
+ case "s390x":
+ t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
}
// TODO(jsing): Reenable once openbsd/arm has external linking support.
if runtime.GOOS == "openbsd" && runtime.GOARCH == "arm" {
diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go
index 1c55d05d5d..bce37dcb97 100644
--- a/src/cmd/pprof/pprof.go
+++ b/src/cmd/pprof/pprof.go
@@ -15,13 +15,13 @@ import (
"sync"
"cmd/internal/objfile"
- "cmd/pprof/internal/commands"
- "cmd/pprof/internal/driver"
- "cmd/pprof/internal/fetch"
- "cmd/pprof/internal/plugin"
- "cmd/pprof/internal/profile"
- "cmd/pprof/internal/symbolizer"
- "cmd/pprof/internal/symbolz"
+ "cmd/internal/pprof/commands"
+ "cmd/internal/pprof/driver"
+ "cmd/internal/pprof/fetch"
+ "cmd/internal/pprof/plugin"
+ "cmd/internal/pprof/profile"
+ "cmd/internal/pprof/symbolizer"
+ "cmd/internal/pprof/symbolz"
)
func main() {
diff --git a/src/cmd/trace/main.go b/src/cmd/trace/main.go
index e493be91b7..cfd222e132 100644
--- a/src/cmd/trace/main.go
+++ b/src/cmd/trace/main.go
@@ -99,16 +99,11 @@ func parseEvents() ([]*trace.Event, error) {
defer tracef.Close()
// Parse and symbolize.
- events, err := trace.Parse(bufio.NewReader(tracef))
+ events, err := trace.Parse(bufio.NewReader(tracef), programBinary)
if err != nil {
loader.err = fmt.Errorf("failed to parse trace: %v", err)
return
}
- err = trace.Symbolize(events, programBinary)
- if err != nil {
- loader.err = fmt.Errorf("failed to symbolize trace: %v", err)
- return
- }
loader.events = events
})
return loader.events, loader.err
diff --git a/src/cmd/trace/pprof.go b/src/cmd/trace/pprof.go
index eaddf63ee8..fdda6d89be 100644
--- a/src/cmd/trace/pprof.go
+++ b/src/cmd/trace/pprof.go
@@ -8,6 +8,7 @@ package main
import (
"bufio"
+ "cmd/internal/pprof/profile"
"fmt"
"internal/trace"
"io/ioutil"
@@ -133,34 +134,79 @@ func serveSVGProfile(w http.ResponseWriter, r *http.Request, prof map[uint64]Rec
http.Error(w, fmt.Sprintf("failed to create temp file: %v", err), http.StatusInternalServerError)
return
}
- defer os.Remove(blockf.Name())
+ defer func() {
+ blockf.Close()
+ os.Remove(blockf.Name())
+ }()
blockb := bufio.NewWriter(blockf)
- fmt.Fprintf(blockb, "--- contention:\ncycles/second=1000000000\n")
- for _, rec := range prof {
- fmt.Fprintf(blockb, "%v %v @", rec.time, rec.n)
- for _, f := range rec.stk {
- fmt.Fprintf(blockb, " 0x%x", f.PC)
- }
- fmt.Fprintf(blockb, "\n")
+ if err := buildProfile(prof).Write(blockb); err != nil {
+ http.Error(w, fmt.Sprintf("failed to write profile: %v", err), http.StatusInternalServerError)
+ return
}
- err = blockb.Flush()
- if err != nil {
+ if err := blockb.Flush(); err != nil {
http.Error(w, fmt.Sprintf("failed to flush temp file: %v", err), http.StatusInternalServerError)
return
}
- err = blockf.Close()
- if err != nil {
+ if err := blockf.Close(); err != nil {
http.Error(w, fmt.Sprintf("failed to close temp file: %v", err), http.StatusInternalServerError)
return
}
-
svgFilename := blockf.Name() + ".svg"
- _, err = exec.Command("go", "tool", "pprof", "-svg", "-output", svgFilename, programBinary, blockf.Name()).CombinedOutput()
- if err != nil {
- http.Error(w, fmt.Sprintf("failed to execute go tool pprof: %v", err), http.StatusInternalServerError)
+ if output, err := exec.Command("go", "tool", "pprof", "-svg", "-output", svgFilename, blockf.Name()).CombinedOutput(); err != nil {
+ http.Error(w, fmt.Sprintf("failed to execute go tool pprof: %v\n%s", err, output), http.StatusInternalServerError)
return
}
defer os.Remove(svgFilename)
w.Header().Set("Content-Type", "image/svg+xml")
http.ServeFile(w, r, svgFilename)
}
+
+func buildProfile(prof map[uint64]Record) *profile.Profile {
+ p := &profile.Profile{
+ PeriodType: &profile.ValueType{Type: "trace", Unit: "count"},
+ Period: 1,
+ SampleType: []*profile.ValueType{
+ {Type: "contentions", Unit: "count"},
+ {Type: "delay", Unit: "nanoseconds"},
+ },
+ }
+ locs := make(map[uint64]*profile.Location)
+ funcs := make(map[string]*profile.Function)
+ for _, rec := range prof {
+ var sloc []*profile.Location
+ for _, frame := range rec.stk {
+ loc := locs[frame.PC]
+ if loc == nil {
+ fn := funcs[frame.File+frame.Fn]
+ if fn == nil {
+ fn = &profile.Function{
+ ID: uint64(len(p.Function) + 1),
+ Name: frame.Fn,
+ SystemName: frame.Fn,
+ Filename: frame.File,
+ }
+ p.Function = append(p.Function, fn)
+ funcs[frame.File+frame.Fn] = fn
+ }
+ loc = &profile.Location{
+ ID: uint64(len(p.Location) + 1),
+ Address: frame.PC,
+ Line: []profile.Line{
+ profile.Line{
+ Function: fn,
+ Line: int64(frame.Line),
+ },
+ },
+ }
+ p.Location = append(p.Location, loc)
+ locs[frame.PC] = loc
+ }
+ sloc = append(sloc, loc)
+ }
+ p.Sample = append(p.Sample, &profile.Sample{
+ Value: []int64{int64(rec.n), rec.time},
+ Location: sloc,
+ })
+ }
+ return p
+}
diff --git a/src/cmd/trace/trace.go b/src/cmd/trace/trace.go
index fff732b856..7782a5efc8 100644
--- a/src/cmd/trace/trace.go
+++ b/src/cmd/trace/trace.go
@@ -44,19 +44,88 @@ func httpTrace(w http.ResponseWriter, r *http.Request) {
}
+// See https://github.com/catapult-project/catapult/blob/master/tracing/docs/embedding-trace-viewer.md
+// This is almost verbatim copy of:
+// https://github.com/catapult-project/catapult/blob/master/tracing/bin/index.html
+// on revision 623a005a3ffa9de13c4b92bc72290e7bcd1ca591.
var templTrace = `
<html>
- <head>
- <link href="/trace_viewer_html" rel="import">
- <script>
- document.addEventListener("DOMContentLoaded", function(event) {
- var viewer = new tr.TraceViewer('/jsontrace{{PARAMS}}');
- document.body.appendChild(viewer);
- });
- </script>
- </head>
- <body>
- </body>
+<head>
+<link href="/trace_viewer_html" rel="import">
+<script>
+(function() {
+ var viewer;
+ var url;
+ var model;
+
+ function load() {
+ var req = new XMLHttpRequest();
+ var is_binary = /[.]gz$/.test(url) || /[.]zip$/.test(url);
+ req.overrideMimeType('text/plain; charset=x-user-defined');
+ req.open('GET', url, true);
+ if (is_binary)
+ req.responseType = 'arraybuffer';
+
+ req.onreadystatechange = function(event) {
+ if (req.readyState !== 4)
+ return;
+
+ window.setTimeout(function() {
+ if (req.status === 200)
+ onResult(is_binary ? req.response : req.responseText);
+ else
+ onResultFail(req.status);
+ }, 0);
+ };
+ req.send(null);
+ }
+
+ function onResultFail(err) {
+ var overlay = new tr.ui.b.Overlay();
+ overlay.textContent = err + ': ' + url + ' could not be loaded';
+ overlay.title = 'Failed to fetch data';
+ overlay.visible = true;
+ }
+
+ function onResult(result) {
+ model = new tr.Model();
+ var i = new tr.importer.Import(model);
+ var p = i.importTracesWithProgressDialog([result]);
+ p.then(onModelLoaded, onImportFail);
+ }
+
+ function onModelLoaded() {
+ viewer.model = model;
+ viewer.viewTitle = "trace";
+ }
+
+ function onImportFail() {
+ var overlay = new tr.ui.b.Overlay();
+ overlay.textContent = tr.b.normalizeException(err).message;
+ overlay.title = 'Import error';
+ overlay.visible = true;
+ }
+
+ document.addEventListener('DOMContentLoaded', function() {
+ var container = document.createElement('track-view-container');
+ container.id = 'track_view_container';
+
+ viewer = document.createElement('tr-ui-timeline-view');
+ viewer.track_view_container = container;
+ viewer.appendChild(container);
+
+ viewer.id = 'trace-viewer';
+ viewer.globalMode = true;
+ document.body.appendChild(viewer);
+
+ url = '/jsontrace{{PARAMS}}';
+ load();
+ });
+}());
+</script>
+</head>
+<body>
+</body>
</html>
`
diff --git a/src/cmd/vet/asmdecl.go b/src/cmd/vet/asmdecl.go
index 1b313cfe1b..389da353fc 100644
--- a/src/cmd/vet/asmdecl.go
+++ b/src/cmd/vet/asmdecl.go
@@ -559,6 +559,11 @@ func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr stri
src = 8
break
}
+ if strings.HasPrefix(op, "P") && strings.HasSuffix(op, "RD") {
+ // PINSRD, PEXTRD, etc
+ src = 4
+ break
+ }
if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "F") || strings.HasSuffix(op, "FP")) {
// FMOVFP, FXCHF, etc
src = 4
diff --git a/src/cmd/vet/atomic.go b/src/cmd/vet/atomic.go
index c084f13ab3..b2ca2d80f3 100644
--- a/src/cmd/vet/atomic.go
+++ b/src/cmd/vet/atomic.go
@@ -23,6 +23,9 @@ func checkAtomicAssignment(f *File, node ast.Node) {
if len(n.Lhs) != len(n.Rhs) {
return
}
+ if len(n.Lhs) == 1 && n.Tok == token.DEFINE {
+ return
+ }
for i, right := range n.Rhs {
call, ok := right.(*ast.CallExpr)
diff --git a/src/cmd/vet/composite.go b/src/cmd/vet/composite.go
index 731c793eac..ac6a598b0b 100644
--- a/src/cmd/vet/composite.go
+++ b/src/cmd/vet/composite.go
@@ -68,8 +68,10 @@ func checkUnkeyedLiteral(f *File, node ast.Node) {
allKeyValue := true
for _, e := range c.Elts {
if _, ok := e.(*ast.KeyValueExpr); !ok {
- allKeyValue = false
- break
+ if cl, ok := e.(*ast.CompositeLit); !ok || cl.Type != nil {
+ allKeyValue = false
+ break
+ }
}
}
if allKeyValue {
diff --git a/src/cmd/vet/doc.go b/src/cmd/vet/doc.go
index d295fb4345..c697f3bc36 100644
--- a/src/cmd/vet/doc.go
+++ b/src/cmd/vet/doc.go
@@ -29,11 +29,10 @@ check every possible problem and depends on unreliable heuristics
so it should be used as guidance only, not as a firm indicator of
program correctness.
-By default all checks are performed. If any flags are explicitly set
-to true, only those tests are run. Conversely, if any flag is
-explicitly set to false, only those tests are disabled.
-Thus -printf=true runs the printf check, -printf=false runs all checks
-except the printf check.
+By default the -all flag is set so all checks are performed.
+If any flags are explicitly set to true, only those tests are run. Conversely, if
+any flag is explicitly set to false, only those tests are disabled. Thus -printf=true
+runs the printf check, -printf=false runs all checks except the printf check.
Available checks:
@@ -188,15 +187,10 @@ These flags configure the behavior of vet:
-v
Verbose mode
-printfuncs
- A comma-separated list of print-like functions to supplement the
- standard list. Each entry is in the form Name:N where N is the
- zero-based argument position of the first argument involved in the
- print: either the format or the first print argument for non-formatted
- prints. For example, if you have Warn and Warnf functions that
- take an io.Writer as their first argument, like Fprintf,
- -printfuncs=Warn:1,Warnf:1
+ A comma-separated list of print-like function names
+ to supplement the standard list.
For more information, see the discussion of the -printf flag.
-shadowstrict
Whether to be strict about shadowing; can be noisy.
*/
-package main // import "golang.org/x/tools/cmd/vet"
+package main
diff --git a/src/cmd/vet/internal/whitelist/whitelist.go b/src/cmd/vet/internal/whitelist/whitelist.go
index b6c85850f3..696f7a533d 100644
--- a/src/cmd/vet/internal/whitelist/whitelist.go
+++ b/src/cmd/vet/internal/whitelist/whitelist.go
@@ -11,7 +11,8 @@ package whitelist
// library's exported slice types.
var UnkeyedLiteral = map[string]bool{
/*
- find $GOROOT/src -type f | grep -v _test.go | xargs grep '^type.*\[\]' | \
+ find $GOROOT/src -type f | grep -v _test.go | grep -v /internal/ | grep -v /testdata/ | \
+ xargs grep '^type.*\[\]' | grep -v ' func(' | \
grep -v ' map\[' | sed 's,/[^/]*go.type,,' | sed 's,.*src/,,' | \
sed 's, ,.,' | sed 's, .*,,' | grep -v '\.[a-z]' | \
sort | awk '{ print "\"" $0 "\": true," }'
diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go
index a2142dcabb..8212a14f03 100644
--- a/src/cmd/vet/main.go
+++ b/src/cmd/vet/main.go
@@ -100,7 +100,7 @@ func (ts *triState) Set(value string) error {
func (ts *triState) String() string {
switch *ts {
case unset:
- return "unset"
+ return "true" // An unset flag will be set by -all, so defaults to true.
case setTrue:
return "true"
case setFalse:
@@ -164,6 +164,7 @@ func Usage() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
fmt.Fprintf(os.Stderr, "\tvet [flags] directory...\n")
fmt.Fprintf(os.Stderr, "\tvet [flags] files... # Must be a single package\n")
+ fmt.Fprintf(os.Stderr, "By default, -all is set and all non-experimental checks are run.\n")
fmt.Fprintf(os.Stderr, "For more information run\n")
fmt.Fprintf(os.Stderr, "\tgo doc cmd/vet\n\n")
fmt.Fprintf(os.Stderr, "Flags:\n")
diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go
index 4e3252f2fb..07499e6ae6 100644
--- a/src/cmd/vet/print.go
+++ b/src/cmd/vet/print.go
@@ -35,20 +35,18 @@ func initPrintFlags() {
if len(name) == 0 {
flag.Usage()
}
- skip := 0
+
+ // Backwards compatibility: skip optional first argument
+ // index after the colon.
if colon := strings.LastIndex(name, ":"); colon > 0 {
- var err error
- skip, err = strconv.Atoi(name[colon+1:])
- if err != nil {
- errorf(`illegal format for "Func:N" argument %q; %s`, name, err)
- }
name = name[:colon]
}
+
name = strings.ToLower(name)
if name[len(name)-1] == 'f' {
isFormattedPrint[name] = true
} else {
- printList[name] = skip
+ isPrint[name] = true
}
}
}
@@ -65,17 +63,20 @@ var isFormattedPrint = map[string]bool{
"sprintf": true,
}
-// printList records the unformatted-print functions. The value is the location
-// of the first parameter to be printed. Names are lower-cased so the lookup is
-// case insensitive.
-var printList = map[string]int{
- "error": 0,
- "fatal": 0,
- "fprint": 1, "fprintln": 1,
- "log": 0,
- "panic": 0, "panicln": 0,
- "print": 0, "println": 0,
- "sprint": 0, "sprintln": 0,
+// isPrint records the unformatted-print functions. Names are lower-cased
+// so the lookup is case insensitive.
+var isPrint = map[string]bool{
+ "error": true,
+ "fatal": true,
+ "fprint": true,
+ "fprintln": true,
+ "log": true,
+ "panic": true,
+ "panicln": true,
+ "print": true,
+ "println": true,
+ "sprint": true,
+ "sprintln": true,
}
// formatString returns the format string argument and its index within
@@ -171,8 +172,8 @@ func checkFmtPrintfCall(f *File, node ast.Node) {
f.checkPrintf(call, Name)
return
}
- if skip, ok := printList[name]; ok {
- f.checkPrint(call, Name, skip)
+ if _, ok := isPrint[name]; ok {
+ f.checkPrint(call, Name)
return
}
}
@@ -583,25 +584,36 @@ func (f *File) argCanBeChecked(call *ast.CallExpr, formatArg int, isStar bool, s
}
// checkPrint checks a call to an unformatted print routine such as Println.
-// call.Args[firstArg] is the first argument to be printed.
-func (f *File) checkPrint(call *ast.CallExpr, name string, firstArg int) {
- isLn := strings.HasSuffix(name, "ln")
- isF := strings.HasPrefix(name, "F")
- args := call.Args
- if name == "Log" && len(args) > 0 {
- // Special case: Don't complain about math.Log or cmplx.Log.
- // Not strictly necessary because the only complaint likely is for Log("%d")
- // but it feels wrong to check that math.Log is a good print function.
- if sel, ok := args[0].(*ast.SelectorExpr); ok {
- if x, ok := sel.X.(*ast.Ident); ok {
- if x.Name == "math" || x.Name == "cmplx" {
- return
- }
+func (f *File) checkPrint(call *ast.CallExpr, name string) {
+ firstArg := 0
+ typ := f.pkg.types[call.Fun].Type
+ if typ != nil {
+ if sig, ok := typ.(*types.Signature); ok {
+ if !sig.Variadic() {
+ // Skip checking non-variadic functions.
+ return
+ }
+ params := sig.Params()
+ firstArg = params.Len() - 1
+
+ typ := params.At(firstArg).Type()
+ typ = typ.(*types.Slice).Elem()
+ it, ok := typ.(*types.Interface)
+ if !ok || !it.Empty() {
+ // Skip variadic functions accepting non-interface{} args.
+ return
}
}
}
+ args := call.Args
+ if len(args) <= firstArg {
+ // Skip calls without variadic args.
+ return
+ }
+ args = args[firstArg:]
+
// check for Println(os.Stderr, ...)
- if firstArg == 0 && !isF && len(args) > 0 {
+ if firstArg == 0 {
if sel, ok := args[0].(*ast.SelectorExpr); ok {
if x, ok := sel.X.(*ast.Ident); ok {
if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") {
@@ -610,31 +622,15 @@ func (f *File) checkPrint(call *ast.CallExpr, name string, firstArg int) {
}
}
}
- if len(args) <= firstArg {
- // If we have a call to a method called Error that satisfies the Error interface,
- // then it's ok. Otherwise it's something like (*T).Error from the testing package
- // and we need to check it.
- if name == "Error" && f.isErrorMethodCall(call) {
- return
- }
- // If it's an Error call now, it's probably for printing errors.
- if !isLn {
- // Check the signature to be sure: there are niladic functions called "error".
- if firstArg != 0 || f.numArgsInSignature(call) != firstArg {
- f.Badf(call.Pos(), "no args in %s call", name)
- }
- }
- return
- }
- arg := args[firstArg]
+ arg := args[0]
if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
if strings.Contains(lit.Value, "%") {
f.Badf(call.Pos(), "possible formatting directive in %s call", name)
}
}
- if isLn {
+ if strings.HasSuffix(name, "ln") {
// The last item, if a string, should not have a newline.
- arg = args[len(call.Args)-1]
+ arg = args[len(args)-1]
if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
if strings.HasSuffix(lit.Value, `\n"`) {
f.Badf(call.Pos(), "%s call ends with newline", name)
diff --git a/src/cmd/vet/structtag.go b/src/cmd/vet/structtag.go
index e8164a46f9..abff14fb1d 100644
--- a/src/cmd/vet/structtag.go
+++ b/src/cmd/vet/structtag.go
@@ -111,7 +111,7 @@ func validateStructTag(tag string) error {
if i >= len(tag) {
return errTagValueSyntax
}
- qvalue := string(tag[:i+1])
+ qvalue := tag[:i+1]
tag = tag[i+1:]
if _, err := strconv.Unquote(qvalue); err != nil {
diff --git a/src/cmd/vet/testdata/asm.go b/src/cmd/vet/testdata/asm.go
index 9a3d5315ad..81947102ec 100644
--- a/src/cmd/vet/testdata/asm.go
+++ b/src/cmd/vet/testdata/asm.go
@@ -31,3 +31,5 @@ func nosplit(x int)
func rodata(x int)
func noptr(x int)
func wrapper(x int)
+
+func f15271() (x uint32)
diff --git a/src/cmd/vet/testdata/asm1.s b/src/cmd/vet/testdata/asm1.s
index 62f423cd8b..2c6f13b137 100644
--- a/src/cmd/vet/testdata/asm1.s
+++ b/src/cmd/vet/testdata/asm1.s
@@ -252,3 +252,14 @@ TEXT ·returnnamed(SB),0,$0-41
TEXT ·returnintmissing(SB),0,$0-8
RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
+
+
+// issue 15271
+TEXT ·f15271(SB), NOSPLIT, $0-4
+ // Stick 123 into the low 32 bits of X0.
+ MOVQ $123, AX
+ PINSRD $0, AX, X0
+
+ // Return them.
+ PEXTRD $0, X0, x+0(FP)
+ RET
diff --git a/src/cmd/vet/testdata/atomic.go b/src/cmd/vet/testdata/atomic.go
index 1ba261d941..d5a8e61184 100644
--- a/src/cmd/vet/testdata/atomic.go
+++ b/src/cmd/vet/testdata/atomic.go
@@ -40,4 +40,13 @@ func AtomicTests() {
*ap[1] = atomic.AddUint64(ap[0], 1)
x = atomic.AddUint64() // Used to make vet crash; now silently ignored.
+
+ {
+ // A variable declaration creates a new variable in the current scope.
+ x := atomic.AddUint64(&x, 1) // ERROR "declaration of .x. shadows declaration at testdata/atomic.go:16"
+
+ // Re-declaration assigns a new value.
+ x, w := atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value"
+ _ = w
+ }
}
diff --git a/src/cmd/vet/testdata/composite.go b/src/cmd/vet/testdata/composite.go
index 69e7d7ccb0..0355c0b692 100644
--- a/src/cmd/vet/testdata/composite.go
+++ b/src/cmd/vet/testdata/composite.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This file contains tests for the untagged struct literal checker.
-
// This file contains the test for untagged struct literals.
package testdata
@@ -11,6 +9,7 @@ package testdata
import (
"flag"
"go/scanner"
+ "unicode"
)
var Okay1 = []string{
@@ -57,6 +56,11 @@ var BadStructLiteralUsedInTests = flag.Flag{ // ERROR "unkeyed fields"
"DefValue",
}
+// SpecialCase is an (aptly named) slice of CaseRange to test issue 9171.
+var GoodNamedSliceLiteralUsedInTests = unicode.SpecialCase{
+ {Lo: 1, Hi: 2},
+}
+
// Used to test the check for slices and arrays: If that test is disabled and
// vet is run with --compositewhitelist=false, this line triggers an error.
// Clumsy but sufficient.
diff --git a/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/print.go
index 5c7ff35c90..261ee788c7 100644
--- a/src/cmd/vet/testdata/print.go
+++ b/src/cmd/vet/testdata/print.go
@@ -185,11 +185,11 @@ func PrintfTests() {
// Something that looks like an error interface but isn't, such as the (*T).Error method
// in the testing package.
var et1 errorTest1
- fmt.Println(et1.Error()) // ERROR "no args in Error call"
+ fmt.Println(et1.Error()) // ok
fmt.Println(et1.Error("hi")) // ok
fmt.Println(et1.Error("%d", 3)) // ERROR "possible formatting directive in Error call"
var et2 errorTest2
- et2.Error() // ERROR "no args in Error call"
+ et2.Error() // ok
et2.Error("hi") // ok, not an error method.
et2.Error("%d", 3) // ERROR "possible formatting directive in Error call"
var et3 errorTest3
@@ -231,11 +231,41 @@ func PrintfTests() {
externalprintf.Logf(level, "%d", 42) // OK
externalprintf.Errorf(level, level, "foo %q bar", "foobar") // OK
externalprintf.Logf(level, "%d") // ERROR "format reads arg 1, have only 0 args"
+
+ // user-defined Println-like functions
+ ss := &someStruct{}
+ ss.Log(someFunction, "foo") // OK
+ ss.Error(someFunction, someFunction) // OK
+ ss.Println() // OK
+ ss.Println(1.234, "foo") // OK
+ ss.Println(1, someFunction) // ERROR "arg someFunction in Println call is a function value, not a function call"
+ ss.log(someFunction) // OK
+ ss.log(someFunction, "bar", 1.33) // OK
+ ss.log(someFunction, someFunction) // ERROR "arg someFunction in log call is a function value, not a function call"
}
+type someStruct struct{}
+
+// Log is non-variadic user-define Println-like function.
+// Calls to this func must be skipped when checking
+// for Println-like arguments.
+func (ss *someStruct) Log(f func(), s string) {}
+
+// Error is variadic user-define Println-like function.
+// Calls to this func mustn't be checked for Println-like arguments,
+// since variadic arguments type isn't interface{}.
+func (ss *someStruct) Error(args ...func()) {}
+
+// Println is variadic user-defined Println-like function.
+// Calls to this func must be checked for Println-like arguments.
+func (ss *someStruct) Println(args ...interface{}) {}
+
+// log is variadic user-defined Println-like function.
+// Calls to this func must be checked for Println-like arguments.
+func (ss *someStruct) log(f func(), args ...interface{}) {}
+
// A function we use as a function value; it has no other purpose.
-func someFunction() {
-}
+func someFunction() {}
// Printf is used by the test so we must declare it.
func Printf(format string, args ...interface{}) {
diff --git a/src/cmd/vet/types.go b/src/cmd/vet/types.go
index 692bae6192..4358955d93 100644
--- a/src/cmd/vet/types.go
+++ b/src/cmd/vet/types.go
@@ -292,72 +292,6 @@ func (f *File) matchStructArgType(t printfArgType, typ *types.Struct, arg ast.Ex
return true
}
-// numArgsInSignature tells how many formal arguments the function type
-// being called has.
-func (f *File) numArgsInSignature(call *ast.CallExpr) int {
- // Check the type of the function or method declaration
- typ := f.pkg.types[call.Fun].Type
- if typ == nil {
- return 0
- }
- // The type must be a signature, but be sure for safety.
- sig, ok := typ.(*types.Signature)
- if !ok {
- return 0
- }
- return sig.Params().Len()
-}
-
-// isErrorMethodCall reports whether the call is of a method with signature
-// func Error() string
-// where "string" is the universe's string type. We know the method is called "Error".
-func (f *File) isErrorMethodCall(call *ast.CallExpr) bool {
- typ := f.pkg.types[call].Type
- if typ != nil {
- // We know it's called "Error", so just check the function signature
- // (stringerType has exactly one method, String).
- if stringerType != nil && stringerType.NumMethods() == 1 {
- return types.Identical(f.pkg.types[call.Fun].Type, stringerType.Method(0).Type())
- }
- }
- // Without types, we can still check by hand.
- // Is it a selector expression? Otherwise it's a function call, not a method call.
- sel, ok := call.Fun.(*ast.SelectorExpr)
- if !ok {
- return false
- }
- // The package is type-checked, so if there are no arguments, we're done.
- if len(call.Args) > 0 {
- return false
- }
- // Check the type of the method declaration
- typ = f.pkg.types[sel].Type
- if typ == nil {
- return false
- }
- // The type must be a signature, but be sure for safety.
- sig, ok := typ.(*types.Signature)
- if !ok {
- return false
- }
- // There must be a receiver for it to be a method call. Otherwise it is
- // a function, not something that satisfies the error interface.
- if sig.Recv() == nil {
- return false
- }
- // There must be no arguments. Already verified by type checking, but be thorough.
- if sig.Params().Len() > 0 {
- return false
- }
- // Finally the real questions.
- // There must be one result.
- if sig.Results().Len() != 1 {
- return false
- }
- // It must have return type "string" from the universe.
- return sig.Results().At(0).Type() == types.Typ[types.String]
-}
-
// hasMethod reports whether the type contains a method with the given name.
// It is part of the workaround for Formatters and should be deleted when
// that workaround is no longer necessary.