[dev.boringcrypto] all: merge master into dev.boringcrypto

Change-Id: Ice4172e2058a45b1a24da561fd420244ab2a97bd
This commit is contained in:
Filippo Valsorda 2018-11-13 13:58:50 -05:00
commit af07f7734b
150 changed files with 4372 additions and 1832 deletions

View file

@ -33,9 +33,9 @@ func main() {
fail("did not find mobile provision matching device udids %q", udids) fail("did not find mobile provision matching device udids %q", udids)
} }
fmt.Println("Available provisioning profiles below.") fmt.Println("# Available provisioning profiles below.")
fmt.Println("NOTE: Any existing app on the device with the app id specified by GOIOS_APP_ID") fmt.Println("# NOTE: Any existing app on the device with the app id specified by GOIOS_APP_ID")
fmt.Println("will be overwritten when running Go programs.") fmt.Println("# will be overwritten when running Go programs.")
for _, mp := range mps { for _, mp := range mps {
fmt.Println() fmt.Println()
f, err := ioutil.TempFile("", "go_ios_detect_") f, err := ioutil.TempFile("", "go_ios_detect_")

View file

@ -3,8 +3,18 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
(() => { (() => {
if (typeof global !== "undefined") {
// global already exists
} else if (typeof window !== "undefined") {
window.global = window;
} else if (typeof self !== "undefined") {
self.global = self;
} else {
throw new Error("cannot export Go (neither global, window nor self is defined)");
}
// Map web browser API and Node.js API to a single common API (preferring web standards over Node.js API). // Map web browser API and Node.js API to a single common API (preferring web standards over Node.js API).
const isNodeJS = typeof process !== "undefined"; const isNodeJS = global.process && global.process.title === "node";
if (isNodeJS) { if (isNodeJS) {
global.require = require; global.require = require;
global.fs = require("fs"); global.fs = require("fs");
@ -27,14 +37,6 @@
global.TextEncoder = util.TextEncoder; global.TextEncoder = util.TextEncoder;
global.TextDecoder = util.TextDecoder; global.TextDecoder = util.TextDecoder;
} else { } else {
if (typeof window !== "undefined") {
window.global = window;
} else if (typeof self !== "undefined") {
self.global = self;
} else {
throw new Error("cannot export Go (neither window nor self is defined)");
}
let outputBuf = ""; let outputBuf = "";
global.fs = { global.fs = {
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused

View file

@ -369,6 +369,9 @@ TEXT main·foo(SB),DUPOK|NOSPLIT,$16-0 // TEXT main.foo(SB), DUPOK|NOSPLIT, $16-
VSTEH $7, V31, (R2) // e7f020007809 VSTEH $7, V31, (R2) // e7f020007809
VSTEB $15, V29, 4094(R12) // e7d0cffef808 VSTEB $15, V29, 4094(R12) // e7d0cffef808
VMSLG V21, V22, V23, V24 // e78563007fb8 VMSLG V21, V22, V23, V24 // e78563007fb8
VMSLEG V21, V22, V23, V24 // e78563807fb8
VMSLOG V21, V22, V23, V24 // e78563407fb8
VMSLEOG V21, V22, V23, V24 // e78563c07fb8
RET RET
RET foo(SB) RET foo(SB)

View file

@ -211,6 +211,8 @@ var exportHeader = flag.String("exportheader", "", "where to write export header
var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo") var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo") var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo") var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
var gccgoMangleCheckDone bool
var gccgoNewmanglingInEffect bool
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code") var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code") var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
var goarch, goos string var goarch, goos string

View file

@ -15,7 +15,9 @@ import (
"go/printer" "go/printer"
"go/token" "go/token"
"io" "io"
"io/ioutil"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"regexp" "regexp"
"sort" "sort"
@ -1186,12 +1188,91 @@ func (p *Package) writeExportHeader(fgcch io.Writer) {
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog()) fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
} }
// Return the package prefix when using gccgo. // gccgoUsesNewMangling returns whether gccgo uses the new collision-free
func (p *Package) gccgoSymbolPrefix() string { // packagepath mangling scheme (see determineGccgoManglingScheme for more
if !*gccgo { // info).
return "" func gccgoUsesNewMangling() bool {
if !gccgoMangleCheckDone {
gccgoNewmanglingInEffect = determineGccgoManglingScheme()
gccgoMangleCheckDone = true
}
return gccgoNewmanglingInEffect
}
const mangleCheckCode = `
package läufer
func Run(x int) int {
return 1
}
`
// determineGccgoManglingScheme performs a runtime test to see which
// flavor of packagepath mangling gccgo is using. Older versions of
// gccgo use a simple mangling scheme where there can be collisions
// between packages whose paths are different but mangle to the same
// string. More recent versions of gccgo use a new mangler that avoids
// these collisions. Return value is whether gccgo uses the new mangling.
func determineGccgoManglingScheme() bool {
// Emit a small Go file for gccgo to compile.
filepat := "*_gccgo_manglecheck.go"
var f *os.File
var err error
if f, err = ioutil.TempFile(*objDir, filepat); err != nil {
fatalf("%v", err)
}
gofilename := f.Name()
defer os.Remove(gofilename)
if err = ioutil.WriteFile(gofilename, []byte(mangleCheckCode), 0666); err != nil {
fatalf("%v", err)
} }
// Compile with gccgo, capturing generated assembly.
gccgocmd := os.Getenv("GCCGO")
if gccgocmd == "" {
gpath, gerr := exec.LookPath("gccgo")
if gerr != nil {
fatalf("unable to locate gccgo: %v", gerr)
}
gccgocmd = gpath
}
cmd := exec.Command(gccgocmd, "-S", "-o", "-", gofilename)
buf, cerr := cmd.CombinedOutput()
if cerr != nil {
fatalf("%s", err)
}
// New mangling: expect go.l..u00e4ufer.Run
// Old mangling: expect go.l__ufer.Run
return regexp.MustCompile(`go\.l\.\.u00e4ufer\.Run`).Match(buf)
}
// gccgoPkgpathToSymbolNew converts a package path to a gccgo-style
// package symbol.
func gccgoPkgpathToSymbolNew(ppath string) string {
bsl := []byte{}
changed := false
for _, c := range []byte(ppath) {
switch {
case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z',
'0' <= c && c <= '9', '_' == c:
bsl = append(bsl, c)
default:
changed = true
encbytes := []byte(fmt.Sprintf("..z%02x", c))
bsl = append(bsl, encbytes...)
}
}
if !changed {
return ppath
}
return string(bsl)
}
// gccgoPkgpathToSymbolOld converts a package path to a gccgo-style
// package symbol using the older mangling scheme.
func gccgoPkgpathToSymbolOld(ppath string) string {
clean := func(r rune) rune { clean := func(r rune) rune {
switch { switch {
case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z', case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
@ -1200,14 +1281,32 @@ func (p *Package) gccgoSymbolPrefix() string {
} }
return '_' return '_'
} }
return strings.Map(clean, ppath)
}
// gccgoPkgpathToSymbol converts a package path to a mangled packagepath
// symbol.
func gccgoPkgpathToSymbol(ppath string) string {
if gccgoUsesNewMangling() {
return gccgoPkgpathToSymbolNew(ppath)
} else {
return gccgoPkgpathToSymbolOld(ppath)
}
}
// Return the package prefix when using gccgo.
func (p *Package) gccgoSymbolPrefix() string {
if !*gccgo {
return ""
}
if *gccgopkgpath != "" { if *gccgopkgpath != "" {
return strings.Map(clean, *gccgopkgpath) return gccgoPkgpathToSymbol(*gccgopkgpath)
} }
if *gccgoprefix == "" && p.PackageName == "main" { if *gccgoprefix == "" && p.PackageName == "main" {
return "main" return "main"
} }
prefix := strings.Map(clean, *gccgoprefix) prefix := gccgoPkgpathToSymbol(*gccgoprefix)
if prefix == "" { if prefix == "" {
prefix = "go" prefix = "go"
} }

View file

@ -360,6 +360,41 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = r p.To.Reg = r
case ssa.OpAMD64ADDQcarry, ssa.OpAMD64ADCQ:
r := v.Reg0()
r0 := v.Args[0].Reg()
r1 := v.Args[1].Reg()
switch r {
case r0:
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = r1
p.To.Type = obj.TYPE_REG
p.To.Reg = r
case r1:
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = r0
p.To.Type = obj.TYPE_REG
p.To.Reg = r
default:
v.Fatalf("output not in same register as an input %s", v.LongString())
}
case ssa.OpAMD64SUBQborrow, ssa.OpAMD64SBBQ:
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[1].Reg()
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg0()
case ssa.OpAMD64ADDQconstcarry, ssa.OpAMD64ADCQconst, ssa.OpAMD64SUBQconstborrow, ssa.OpAMD64SBBQconst:
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg0()
case ssa.OpAMD64ADDQconst, ssa.OpAMD64ADDLconst: case ssa.OpAMD64ADDQconst, ssa.OpAMD64ADDLconst:
r := v.Reg() r := v.Reg()
a := v.Args[0].Reg() a := v.Args[0].Reg()
@ -946,6 +981,16 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := s.Prog(v.Op.Asm()) p := s.Prog(v.Op.Asm())
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = r p.To.Reg = r
case ssa.OpAMD64NEGLflags:
r := v.Reg0()
if r != v.Args[0].Reg() {
v.Fatalf("input[0] and output not in same register %s", v.LongString())
}
p := s.Prog(v.Op.Asm())
p.To.Type = obj.TYPE_REG
p.To.Reg = r
case ssa.OpAMD64BSFQ, ssa.OpAMD64BSRQ, ssa.OpAMD64BSFL, ssa.OpAMD64BSRL, ssa.OpAMD64SQRTSD: case ssa.OpAMD64BSFQ, ssa.OpAMD64BSRQ, ssa.OpAMD64BSFL, ssa.OpAMD64BSRL, ssa.OpAMD64SQRTSD:
p := s.Prog(v.Op.Asm()) p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG

View file

@ -863,7 +863,7 @@ func methodSymSuffix(recv *types.Type, msym *types.Sym, suffix string) *types.Sy
// Add a method, declared as a function. // Add a method, declared as a function.
// - msym is the method symbol // - msym is the method symbol
// - t is function type (with receiver) // - t is function type (with receiver)
// Returns a pointer to the existing or added Field. // Returns a pointer to the existing or added Field; or nil if there's an error.
func addmethod(msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field { func addmethod(msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field {
if msym == nil { if msym == nil {
Fatalf("no method symbol") Fatalf("no method symbol")
@ -918,6 +918,7 @@ func addmethod(msym *types.Sym, t *types.Type, local, nointerface bool) *types.F
for _, f := range mt.Fields().Slice() { for _, f := range mt.Fields().Slice() {
if f.Sym == msym { if f.Sym == msym {
yyerror("type %v has both field and method named %v", mt, msym) yyerror("type %v has both field and method named %v", mt, msym)
f.SetBroke(true)
return nil return nil
} }
} }
@ -927,7 +928,7 @@ func addmethod(msym *types.Sym, t *types.Type, local, nointerface bool) *types.F
if msym.Name != f.Sym.Name { if msym.Name != f.Sym.Name {
continue continue
} }
// eqtype only checks that incoming and result parameters match, // types.Identical only checks that incoming and result parameters match,
// so explicitly check that the receiver parameters match too. // so explicitly check that the receiver parameters match too.
if !types.Identical(t, f.Type) || !types.Identical(t.Recv().Type, f.Type.Recv().Type) { if !types.Identical(t, f.Type) || !types.Identical(t.Recv().Type, f.Type.Recv().Type) {
yyerror("method redeclared: %v.%v\n\t%v\n\t%v", mt, msym, f.Type, t) yyerror("method redeclared: %v.%v\n\t%v\n\t%v", mt, msym, f.Type, t)

View file

@ -621,23 +621,23 @@ func (e *EscState) escloopdepth(n *Node) {
switch n.Op { switch n.Op {
case OLABEL: case OLABEL:
if n.Left == nil || n.Left.Sym == nil { if n.Sym == nil {
Fatalf("esc:label without label: %+v", n) Fatalf("esc:label without label: %+v", n)
} }
// Walk will complain about this label being already defined, but that's not until // Walk will complain about this label being already defined, but that's not until
// after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc // after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc
n.Left.Sym.Label = asTypesNode(&nonlooping) n.Sym.Label = asTypesNode(&nonlooping)
case OGOTO: case OGOTO:
if n.Left == nil || n.Left.Sym == nil { if n.Sym == nil {
Fatalf("esc:goto without label: %+v", n) Fatalf("esc:goto without label: %+v", n)
} }
// If we come past one that's uninitialized, this must be a (harmless) forward jump // If we come past one that's uninitialized, this must be a (harmless) forward jump
// but if it's set to nonlooping the label must have preceded this goto. // but if it's set to nonlooping the label must have preceded this goto.
if asNode(n.Left.Sym.Label) == &nonlooping { if asNode(n.Sym.Label) == &nonlooping {
n.Left.Sym.Label = asTypesNode(&looping) n.Sym.Label = asTypesNode(&looping)
} }
} }
@ -851,18 +851,19 @@ opSwitch:
} }
case OLABEL: case OLABEL:
if asNode(n.Left.Sym.Label) == &nonlooping { switch asNode(n.Sym.Label) {
case &nonlooping:
if Debug['m'] > 2 { if Debug['m'] > 2 {
fmt.Printf("%v:%v non-looping label\n", linestr(lineno), n) fmt.Printf("%v:%v non-looping label\n", linestr(lineno), n)
} }
} else if asNode(n.Left.Sym.Label) == &looping { case &looping:
if Debug['m'] > 2 { if Debug['m'] > 2 {
fmt.Printf("%v: %v looping label\n", linestr(lineno), n) fmt.Printf("%v: %v looping label\n", linestr(lineno), n)
} }
e.loopdepth++ e.loopdepth++
} }
n.Left.Sym.Label = nil n.Sym.Label = nil
case ORANGE: case ORANGE:
if n.List.Len() >= 2 { if n.List.Len() >= 2 {

View file

@ -1045,8 +1045,8 @@ func (n *Node) stmtfmt(s fmt.State, mode fmtMode) {
mode.Fprintf(s, ": %v", n.Nbody) mode.Fprintf(s, ": %v", n.Nbody)
case OBREAK, OCONTINUE, OGOTO, OFALL: case OBREAK, OCONTINUE, OGOTO, OFALL:
if n.Left != nil { if n.Sym != nil {
mode.Fprintf(s, "%#v %v", n.Op, n.Left) mode.Fprintf(s, "%#v %v", n.Op, n.Sym)
} else { } else {
mode.Fprintf(s, "%#v", n.Op) mode.Fprintf(s, "%#v", n.Op)
} }
@ -1055,7 +1055,7 @@ func (n *Node) stmtfmt(s fmt.State, mode fmtMode) {
break break
case OLABEL: case OLABEL:
mode.Fprintf(s, "%v: ", n.Left) mode.Fprintf(s, "%v: ", n.Sym)
} }
if extrablock { if extrablock {

View file

@ -1102,7 +1102,7 @@ func (w *exportWriter) stmt(n *Node) {
case OGOTO, OLABEL: case OGOTO, OLABEL:
w.op(op) w.op(op)
w.pos(n.Pos) w.pos(n.Pos)
w.expr(n.Left) w.string(n.Sym.Name)
default: default:
Fatalf("exporter: CANNOT EXPORT: %v\nPlease notify gri@\n", n.Op) Fatalf("exporter: CANNOT EXPORT: %v\nPlease notify gri@\n", n.Op)

View file

@ -1043,7 +1043,9 @@ func (r *importReader) node() *Node {
// unreachable - not emitted by exporter // unreachable - not emitted by exporter
case OGOTO, OLABEL: case OGOTO, OLABEL:
return nodl(r.pos(), op, newname(r.expr().Sym), nil) n := nodl(r.pos(), op, nil, nil)
n.Sym = lookup(r.string())
return n
case OEND: case OEND:
return nil return nil

View file

@ -1072,7 +1072,7 @@ func mkinlcall(n, fn *Node, maxCost int32) *Node {
body := subst.list(asNodes(fn.Func.Inl.Body)) body := subst.list(asNodes(fn.Func.Inl.Body))
lab := nod(OLABEL, retlabel, nil) lab := nodSym(OLABEL, nil, retlabel)
body = append(body, lab) body = append(body, lab)
typecheckslice(body, Etop) typecheckslice(body, Etop)
@ -1158,7 +1158,7 @@ func argvar(t *types.Type, i int) *Node {
// function call. // function call.
type inlsubst struct { type inlsubst struct {
// Target of the goto substituted in place of a return. // Target of the goto substituted in place of a return.
retlabel *Node retlabel *types.Sym
// Temporary result variables. // Temporary result variables.
retvars []*Node retvars []*Node
@ -1218,7 +1218,7 @@ func (subst *inlsubst) node(n *Node) *Node {
// dump("Return before substitution", n); // dump("Return before substitution", n);
case ORETURN: case ORETURN:
m := nod(OGOTO, subst.retlabel, nil) m := nodSym(OGOTO, nil, subst.retlabel)
m.Ninit.Set(subst.list(n.Ninit)) m.Ninit.Set(subst.list(n.Ninit))
if len(subst.retvars) != 0 && n.List.Len() != 0 { if len(subst.retvars) != 0 && n.List.Len() != 0 {
@ -1245,8 +1245,8 @@ func (subst *inlsubst) node(n *Node) *Node {
m := n.copy() m := n.copy()
m.Pos = subst.updatedPos(m.Pos) m.Pos = subst.updatedPos(m.Pos)
m.Ninit.Set(nil) m.Ninit.Set(nil)
p := fmt.Sprintf("%s·%d", n.Left.Sym.Name, inlgen) p := fmt.Sprintf("%s·%d", n.Sym.Name, inlgen)
m.Left = newname(lookup(p)) m.Sym = lookup(p)
return m return m
} }

View file

@ -205,7 +205,6 @@ func Main(archInit func(*Arch)) {
flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", true, "add location lists to DWARF in optimized mode") flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", true, "add location lists to DWARF in optimized mode")
flag.IntVar(&genDwarfInline, "gendwarfinl", 2, "generate DWARF inline info records") flag.IntVar(&genDwarfInline, "gendwarfinl", 2, "generate DWARF inline info records")
objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e']) objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
objabi.Flagcount("f", "debug stack frames", &Debug['f'])
objabi.Flagcount("h", "halt on error", &Debug['h']) objabi.Flagcount("h", "halt on error", &Debug['h'])
objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap) objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg) objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
@ -478,9 +477,6 @@ func Main(archInit func(*Arch)) {
finishUniverse() finishUniverse()
typecheckok = true typecheckok = true
if Debug['f'] != 0 {
frame(1)
}
// Process top-level declarations in phases. // Process top-level declarations in phases.
@ -693,10 +689,14 @@ func Main(archInit func(*Arch)) {
// Check whether any of the functions we have compiled have gigantic stack frames. // Check whether any of the functions we have compiled have gigantic stack frames.
obj.SortSlice(largeStackFrames, func(i, j int) bool { obj.SortSlice(largeStackFrames, func(i, j int) bool {
return largeStackFrames[i].Before(largeStackFrames[j]) return largeStackFrames[i].pos.Before(largeStackFrames[j].pos)
}) })
for _, largePos := range largeStackFrames { for _, large := range largeStackFrames {
yyerrorl(largePos, "stack frame too large (>1GB)") if large.callee != 0 {
yyerrorl(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args + %d MB callee", large.locals>>20, large.args>>20, large.callee>>20)
} else {
yyerrorl(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args", large.locals>>20, large.args>>20)
}
} }
if len(compilequeue) != 0 { if len(compilequeue) != 0 {

View file

@ -819,13 +819,18 @@ func (p *noder) packname(expr syntax.Expr) *types.Sym {
return name return name
case *syntax.SelectorExpr: case *syntax.SelectorExpr:
name := p.name(expr.X.(*syntax.Name)) name := p.name(expr.X.(*syntax.Name))
def := asNode(name.Def)
if def == nil {
yyerror("undefined: %v", name)
return name
}
var pkg *types.Pkg var pkg *types.Pkg
if asNode(name.Def) == nil || asNode(name.Def).Op != OPACK { if def.Op != OPACK {
yyerror("%v is not a package", name) yyerror("%v is not a package", name)
pkg = localpkg pkg = localpkg
} else { } else {
asNode(name.Def).Name.SetUsed(true) def.Name.SetUsed(true)
pkg = asNode(name.Def).Name.Pkg pkg = def.Name.Pkg
} }
return restrictlookup(expr.Sel.Value, pkg) return restrictlookup(expr.Sel.Value, pkg)
} }
@ -936,7 +941,7 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node {
} }
n := p.nod(stmt, op, nil, nil) n := p.nod(stmt, op, nil, nil)
if stmt.Label != nil { if stmt.Label != nil {
n.Left = p.newname(stmt.Label) n.Sym = p.name(stmt.Label)
} }
return n return n
case *syntax.CallStmt: case *syntax.CallStmt:
@ -1200,7 +1205,7 @@ func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace syntax.Pos) []*
} }
func (p *noder) labeledStmt(label *syntax.LabeledStmt, fallOK bool) *Node { func (p *noder) labeledStmt(label *syntax.LabeledStmt, fallOK bool) *Node {
lhs := p.nod(label, OLABEL, p.newname(label.Label), nil) lhs := p.nodSym(label, OLABEL, nil, p.name(label.Label))
var ls *Node var ls *Node
if label.Stmt != nil { // TODO(mdempsky): Should always be present. if label.Stmt != nil { // TODO(mdempsky): Should always be present.

View file

@ -279,7 +279,7 @@ func compileSSA(fn *Node, worker int) {
// Note: check arg size to fix issue 25507. // Note: check arg size to fix issue 25507.
if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type.ArgWidth() >= maxStackSize { if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type.ArgWidth() >= maxStackSize {
largeStackFramesMu.Lock() largeStackFramesMu.Lock()
largeStackFrames = append(largeStackFrames, fn.Pos) largeStackFrames = append(largeStackFrames, largeStack{locals: f.Frontend().(*ssafn).stksize, args: fn.Type.ArgWidth(), pos: fn.Pos})
largeStackFramesMu.Unlock() largeStackFramesMu.Unlock()
return return
} }
@ -294,7 +294,8 @@ func compileSSA(fn *Node, worker int) {
// the assembler may emit inscrutable complaints about invalid instructions. // the assembler may emit inscrutable complaints about invalid instructions.
if pp.Text.To.Offset >= maxStackSize { if pp.Text.To.Offset >= maxStackSize {
largeStackFramesMu.Lock() largeStackFramesMu.Lock()
largeStackFrames = append(largeStackFrames, fn.Pos) locals := f.Frontend().(*ssafn).stksize
largeStackFrames = append(largeStackFrames, largeStack{locals: locals, args: fn.Type.ArgWidth(), callee: pp.Text.To.Offset - locals, pos: fn.Pos})
largeStackFramesMu.Unlock() largeStackFramesMu.Unlock()
return return
} }

View file

@ -845,7 +845,7 @@ func (s *state) stmt(n *Node) {
} }
case OLABEL: case OLABEL:
sym := n.Left.Sym sym := n.Sym
lab := s.label(sym) lab := s.label(sym)
// Associate label with its control flow node, if any // Associate label with its control flow node, if any
@ -867,7 +867,7 @@ func (s *state) stmt(n *Node) {
s.startBlock(lab.target) s.startBlock(lab.target)
case OGOTO: case OGOTO:
sym := n.Left.Sym sym := n.Sym
lab := s.label(sym) lab := s.label(sym)
if lab.target == nil { if lab.target == nil {
@ -1033,7 +1033,7 @@ func (s *state) stmt(n *Node) {
case OCONTINUE, OBREAK: case OCONTINUE, OBREAK:
var to *ssa.Block var to *ssa.Block
if n.Left == nil { if n.Sym == nil {
// plain break/continue // plain break/continue
switch n.Op { switch n.Op {
case OCONTINUE: case OCONTINUE:
@ -1043,7 +1043,7 @@ func (s *state) stmt(n *Node) {
} }
} else { } else {
// labeled break/continue; look up the target // labeled break/continue; look up the target
sym := n.Left.Sym sym := n.Sym
lab := s.label(sym) lab := s.label(sym)
switch n.Op { switch n.Op {
case OCONTINUE: case OCONTINUE:
@ -3474,12 +3474,26 @@ func init() {
addF("math/bits", "OnesCount", addF("math/bits", "OnesCount",
makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount32), makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount32),
sys.AMD64) sys.AMD64)
alias("math/bits", "Mul", "math/bits", "Mul64", sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64)
addF("math/bits", "Mul64", addF("math/bits", "Mul64",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value { func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
return s.newValue2(ssa.OpMul64uhilo, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1]) return s.newValue2(ssa.OpMul64uhilo, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1])
}, },
sys.AMD64, sys.ARM64, sys.PPC64) sys.AMD64, sys.ARM64, sys.PPC64)
alias("math/bits", "Mul", "math/bits", "Mul64", sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64)
addF("math/bits", "Add64",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
return s.newValue3(ssa.OpAdd64carry, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1], args[2])
},
sys.AMD64)
alias("math/bits", "Add", "math/bits", "Add64", sys.ArchAMD64)
addF("math/bits", "Sub64",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
return s.newValue3(ssa.OpSub64borrow, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1], args[2])
},
sys.AMD64)
alias("math/bits", "Sub", "math/bits", "Sub64", sys.ArchAMD64)
/******** sync/atomic ********/ /******** sync/atomic ********/
@ -5225,9 +5239,6 @@ func genssa(f *ssa.Func, pp *Progs) {
} }
defframe(&s, e) defframe(&s, e)
if Debug['f'] != 0 {
frame(0)
}
f.HTMLWriter.Close() f.HTMLWriter.Close()
f.HTMLWriter = nil f.HTMLWriter = nil

View file

@ -28,9 +28,17 @@ type Error struct {
var errors []Error var errors []Error
// largeStack is info about a function whose stack frame is too large (rare).
type largeStack struct {
locals int64
args int64
callee int64
pos src.XPos
}
var ( var (
largeStackFramesMu sync.Mutex // protects largeStackFrames largeStackFramesMu sync.Mutex // protects largeStackFrames
largeStackFrames []src.XPos // positions of functions whose stack frames are too large (rare) largeStackFrames []largeStack
) )
func errorexit() { func errorexit() {
@ -234,7 +242,7 @@ func lookupN(prefix string, n int) *types.Sym {
// to help with debugging. // to help with debugging.
// It should begin with "." to avoid conflicts with // It should begin with "." to avoid conflicts with
// user labels. // user labels.
func autolabel(prefix string) *Node { func autolabel(prefix string) *types.Sym {
if prefix[0] != '.' { if prefix[0] != '.' {
Fatalf("autolabel prefix must start with '.', have %q", prefix) Fatalf("autolabel prefix must start with '.', have %q", prefix)
} }
@ -244,7 +252,7 @@ func autolabel(prefix string) *Node {
} }
n := fn.Func.Label n := fn.Func.Label
fn.Func.Label++ fn.Func.Label++
return newname(lookupN(prefix, int(n))) return lookupN(prefix, int(n))
} }
func restrictlookup(name string, pkg *types.Pkg) *types.Sym { func restrictlookup(name string, pkg *types.Pkg) *types.Sym {
@ -954,36 +962,6 @@ func typehash(t *types.Type) uint32 {
return binary.LittleEndian.Uint32(h[:4]) return binary.LittleEndian.Uint32(h[:4])
} }
func frame(context int) {
if context != 0 {
fmt.Printf("--- external frame ---\n")
for _, n := range externdcl {
printframenode(n)
}
return
}
if Curfn != nil {
fmt.Printf("--- %v frame ---\n", Curfn.Func.Nname.Sym)
for _, ln := range Curfn.Func.Dcl {
printframenode(ln)
}
}
}
func printframenode(n *Node) {
w := int64(-1)
if n.Type != nil {
w = n.Type.Width
}
switch n.Op {
case ONAME:
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", n.Op, n.Type, w)
}
}
// updateHasCall checks whether expression n contains any function // updateHasCall checks whether expression n contains any function
// calls and sets the n.HasCall flag if so. // calls and sets the n.HasCall flag if so.
func updateHasCall(n *Node) { func updateHasCall(n *Node) {

View file

@ -421,7 +421,8 @@ func casebody(sw *Node, typeswvar *Node) {
n.Op = OCASE n.Op = OCASE
needvar := n.List.Len() != 1 || n.List.First().Op == OLITERAL needvar := n.List.Len() != 1 || n.List.First().Op == OLITERAL
jmp := nod(OGOTO, autolabel(".s"), nil) lbl := autolabel(".s")
jmp := nodSym(OGOTO, nil, lbl)
switch n.List.Len() { switch n.List.Len() {
case 0: case 0:
// default // default
@ -486,7 +487,7 @@ func casebody(sw *Node, typeswvar *Node) {
} }
} }
stat = append(stat, nod(OLABEL, jmp.Left, nil)) stat = append(stat, nodSym(OLABEL, nil, lbl))
if typeswvar != nil && needvar && n.Rlist.Len() != 0 { if typeswvar != nil && needvar && n.Rlist.Len() != 0 {
l := []*Node{ l := []*Node{
nod(ODCL, n.Rlist.First(), nil), nod(ODCL, n.Rlist.First(), nil),
@ -778,10 +779,10 @@ func (s *typeSwitch) walk(sw *Node) {
} else { } else {
// Jump to default case. // Jump to default case.
lbl := autolabel(".s") lbl := autolabel(".s")
i.Nbody.Set1(nod(OGOTO, lbl, nil)) i.Nbody.Set1(nodSym(OGOTO, nil, lbl))
// Wrap default case with label. // Wrap default case with label.
blk := nod(OBLOCK, nil, nil) blk := nod(OBLOCK, nil, nil)
blk.List.Set2(nod(OLABEL, lbl, nil), def) blk.List.Set2(nodSym(OLABEL, nil, lbl), def)
def = blk def = blk
} }
i.Left = typecheck(i.Left, Erv) i.Left = typecheck(i.Left, Erv)

View file

@ -574,7 +574,7 @@ const (
OXXX Op = iota OXXX Op = iota
// names // names
ONAME // var, const or func name ONAME // var or func name
ONONAME // unnamed arg or return value: f(int, string) (int, error) { etc } ONONAME // unnamed arg or return value: f(int, string) (int, error) { etc }
OTYPE // type name OTYPE // type name
OPACK // import OPACK // import
@ -698,10 +698,10 @@ const (
// statements // statements
OBLOCK // { List } (block of code) OBLOCK // { List } (block of code)
OBREAK // break OBREAK // break [Sym]
OCASE // case Left or List[0]..List[1]: Nbody (select case after processing; Left==nil and List==nil means default) OCASE // case Left or List[0]..List[1]: Nbody (select case after processing; Left==nil and List==nil means default)
OXCASE // case List: Nbody (select case before processing; List==nil means default) OXCASE // case List: Nbody (select case before processing; List==nil means default)
OCONTINUE // continue OCONTINUE // continue [Sym]
ODEFER // defer Left (Left must be call) ODEFER // defer Left (Left must be call)
OEMPTY // no-op (empty statement) OEMPTY // no-op (empty statement)
OFALL // fallthrough OFALL // fallthrough
@ -716,9 +716,9 @@ const (
// } // }
// OFORUNTIL is created by walk. There's no way to write this in Go code. // OFORUNTIL is created by walk. There's no way to write this in Go code.
OFORUNTIL OFORUNTIL
OGOTO // goto Left OGOTO // goto Sym
OIF // if Ninit; Left { Nbody } else { Rlist } OIF // if Ninit; Left { Nbody } else { Rlist }
OLABEL // Left: OLABEL // Sym:
OPROC // go Left (Left must be call) OPROC // go Left (Left must be call)
ORANGE // for List = range Right { Nbody } ORANGE // for List = range Right { Nbody }
ORETURN // return List ORETURN // return List

View file

@ -1984,7 +1984,7 @@ func typecheck1(n *Node, top int) *Node {
case OLABEL: case OLABEL:
ok |= Etop ok |= Etop
decldepth++ decldepth++
if n.Left.Sym.IsBlank() { if n.Sym.IsBlank() {
// Empty identifier is valid but useless. // Empty identifier is valid but useless.
// Eliminate now to simplify life later. // Eliminate now to simplify life later.
// See issues 7538, 11589, 11593. // See issues 7538, 11589, 11593.
@ -2443,7 +2443,7 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field {
} }
if f1 != nil { if f1 != nil {
if dostrcmp > 1 { if dostrcmp > 1 || f1.Broke() {
// Already in the process of diagnosing an error. // Already in the process of diagnosing an error.
return f1 return f1
} }
@ -3831,12 +3831,12 @@ func markbreak(n *Node, implicit *Node) {
switch n.Op { switch n.Op {
case OBREAK: case OBREAK:
if n.Left == nil { if n.Sym == nil {
if implicit != nil { if implicit != nil {
implicit.SetHasBreak(true) implicit.SetHasBreak(true)
} }
} else { } else {
lab := asNode(n.Left.Sym.Label) lab := asNode(n.Sym.Label)
if lab != nil { if lab != nil {
lab.SetHasBreak(true) lab.SetHasBreak(true)
} }
@ -3864,9 +3864,9 @@ func markbreaklist(l Nodes, implicit *Node) {
if n.Op == OLABEL && i+1 < len(s) && n.Name.Defn == s[i+1] { if n.Op == OLABEL && i+1 < len(s) && n.Name.Defn == s[i+1] {
switch n.Name.Defn.Op { switch n.Name.Defn.Op {
case OFOR, OFORUNTIL, OSWITCH, OTYPESW, OSELECT, ORANGE: case OFOR, OFORUNTIL, OSWITCH, OTYPESW, OSELECT, ORANGE:
n.Left.Sym.Label = asTypesNode(n.Name.Defn) n.Sym.Label = asTypesNode(n.Name.Defn)
markbreak(n.Name.Defn, n.Name.Defn) markbreak(n.Name.Defn, n.Name.Defn)
n.Left.Sym.Label = nil n.Sym.Label = nil
i++ i++
continue continue
} }

View file

@ -1772,10 +1772,22 @@ func walkCall(n *Node, init *Nodes) {
var tempAssigns []*Node var tempAssigns []*Node
for i, arg := range args { for i, arg := range args {
updateHasCall(arg) updateHasCall(arg)
if instrumenting || arg.HasCall() { // Determine param type.
var t *types.Type
if n.Op == OCALLMETH {
if i == 0 {
t = n.Left.Type.Recv().Type
} else {
t = params.Field(i - 1).Type
}
} else {
t = params.Field(i).Type
}
if instrumenting || fncall(arg, t) {
// make assignment of fncall to tempname // make assignment of fncall to tempname
tmp := temp(arg.Type) tmp := temp(t)
a := nod(OAS, tmp, arg) a := nod(OAS, tmp, arg)
a = convas(a, init)
tempAssigns = append(tempAssigns, a) tempAssigns = append(tempAssigns, a)
// replace arg with temp // replace arg with temp
args[i] = tmp args[i] = tmp

View file

@ -771,14 +771,14 @@
(MOVSDstoreidx8 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVSDstoreidx8 [int64(int32(c+8*d))] {sym} ptr idx val mem) (MOVSDstoreidx8 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVSDstoreidx8 [int64(int32(c+8*d))] {sym} ptr idx val mem)
// Merge load/store to op // Merge load/store to op
((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|AND|OR|XOR|SUB|MUL)Lload x [off] {sym} ptr mem) ((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) -> ((ADD|AND|OR|XOR|SUB|MUL)Lload x [off] {sym} ptr mem)
((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) && canMergeLoadClobber(v, l, x) && clobber(l) ->
((ADD|AND|OR|XOR|SUB|MUL)Lloadidx4 x [off] {sym} ptr idx mem) ((ADD|AND|OR|XOR|SUB|MUL)Lloadidx4 x [off] {sym} ptr idx mem)
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem) ((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem)
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem) ((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem)
((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem) ((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem)
((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem) ((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem)
(MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) -> ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem) (MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) -> ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
(MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) -> (MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) ->
((ADD|SUB|AND|OR|XOR)Lmodify [off] {sym} ptr x mem) ((ADD|SUB|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
@ -1217,8 +1217,8 @@
(MOVSSconst [c]) && config.ctxt.Flag_shared -> (MOVSSconst2 (MOVSSconst1 [c])) (MOVSSconst [c]) && config.ctxt.Flag_shared -> (MOVSSconst2 (MOVSSconst1 [c]))
(MOVSDconst [c]) && config.ctxt.Flag_shared -> (MOVSDconst2 (MOVSDconst1 [c])) (MOVSDconst [c]) && config.ctxt.Flag_shared -> (MOVSDconst2 (MOVSDconst1 [c]))
(CMP(L|W|B) l:(MOV(L|W|B)load {sym} [off] ptr mem) x) && canMergeLoad(v, l, x) && clobber(l) -> (CMP(L|W|B)load {sym} [off] ptr x mem) (CMP(L|W|B) l:(MOV(L|W|B)load {sym} [off] ptr mem) x) && canMergeLoad(v, l) && clobber(l) -> (CMP(L|W|B)load {sym} [off] ptr x mem)
(CMP(L|W|B) x l:(MOV(L|W|B)load {sym} [off] ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (InvertFlags (CMP(L|W|B)load {sym} [off] ptr x mem)) (CMP(L|W|B) x l:(MOV(L|W|B)load {sym} [off] ptr mem)) && canMergeLoad(v, l) && clobber(l) -> (InvertFlags (CMP(L|W|B)load {sym} [off] ptr x mem))
(CMP(L|W|B)const l:(MOV(L|W|B)load {sym} [off] ptr mem) [c]) (CMP(L|W|B)const l:(MOV(L|W|B)load {sym} [off] ptr mem) [c])
&& l.Uses == 1 && l.Uses == 1

View file

@ -29,6 +29,28 @@
(Div8u x y) -> (Select0 (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y))) (Div8u x y) -> (Select0 (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y)))
(Div(32|64)F x y) -> (DIVS(S|D) x y) (Div(32|64)F x y) -> (DIVS(S|D) x y)
(Select0 (Add64carry x y c)) ->
(Select0 <typ.UInt64> (ADCQ x y (Select1 <types.TypeFlags> (NEGLflags c))))
(Select1 (Add64carry x y c)) ->
(NEGQ <typ.UInt64> (SBBQcarrymask <typ.UInt64> (Select1 <types.TypeFlags> (ADCQ x y (Select1 <types.TypeFlags> (NEGLflags c))))))
(Select0 (Sub64borrow x y c)) ->
(Select0 <typ.UInt64> (SBBQ x y (Select1 <types.TypeFlags> (NEGLflags c))))
(Select1 (Sub64borrow x y c)) ->
(NEGQ <typ.UInt64> (SBBQcarrymask <typ.UInt64> (Select1 <types.TypeFlags> (SBBQ x y (Select1 <types.TypeFlags> (NEGLflags c))))))
// Optimize ADCQ and friends
(ADCQ x (MOVQconst [c]) carry) && is32Bit(c) -> (ADCQconst x [c] carry)
(ADCQ x y (FlagEQ)) -> (ADDQcarry x y)
(ADCQconst x [c] (FlagEQ)) -> (ADDQconstcarry x [c])
(ADDQcarry x (MOVQconst [c])) && is32Bit(c) -> (ADDQconstcarry x [c])
(SBBQ x (MOVQconst [c]) borrow) && is32Bit(c) -> (SBBQconst x [c] borrow)
(SBBQ x y (FlagEQ)) -> (SUBQborrow x y)
(SBBQconst x [c] (FlagEQ)) -> (SUBQconstborrow x [c])
(SUBQborrow x (MOVQconst [c])) && is32Bit(c) -> (SUBQconstborrow x [c])
(Select1 (NEGLflags (MOVQconst [0]))) -> (FlagEQ)
(Select1 (NEGLflags (NEGQ (SBBQcarrymask x)))) -> x
(Mul64uhilo x y) -> (MULQU2 x y) (Mul64uhilo x y) -> (MULQU2 x y)
(Div128u xhi xlo y) -> (DIVQU2 xhi xlo y) (Div128u xhi xlo y) -> (DIVQU2 xhi xlo y)
@ -2340,10 +2362,10 @@
// Merge load and op // Merge load and op
// TODO: add indexed variants? // TODO: add indexed variants?
((ADD|SUB|AND|OR|XOR)Q x l:(MOVQload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|SUB|AND|OR|XOR)Qload x [off] {sym} ptr mem) ((ADD|SUB|AND|OR|XOR)Q x l:(MOVQload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) -> ((ADD|SUB|AND|OR|XOR)Qload x [off] {sym} ptr mem)
((ADD|SUB|AND|OR|XOR)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|SUB|AND|OR|XOR)Lload x [off] {sym} ptr mem) ((ADD|SUB|AND|OR|XOR)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) -> ((ADD|SUB|AND|OR|XOR)Lload x [off] {sym} ptr mem)
((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem) ((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) -> ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem)
((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem) ((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) -> ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem)
(MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) -> ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem) (MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) -> ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
(MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) -> (MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) ->
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Lmodify [off] {sym} ptr x mem) ((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Lmodify [off] {sym} ptr x mem)
@ -2492,8 +2514,8 @@
// Fold loads into compares // Fold loads into compares
// Note: these may be undone by the flagalloc pass. // Note: these may be undone by the flagalloc pass.
(CMP(Q|L|W|B) l:(MOV(Q|L|W|B)load {sym} [off] ptr mem) x) && canMergeLoad(v, l, x) && clobber(l) -> (CMP(Q|L|W|B)load {sym} [off] ptr x mem) (CMP(Q|L|W|B) l:(MOV(Q|L|W|B)load {sym} [off] ptr mem) x) && canMergeLoad(v, l) && clobber(l) -> (CMP(Q|L|W|B)load {sym} [off] ptr x mem)
(CMP(Q|L|W|B) x l:(MOV(Q|L|W|B)load {sym} [off] ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (InvertFlags (CMP(Q|L|W|B)load {sym} [off] ptr x mem)) (CMP(Q|L|W|B) x l:(MOV(Q|L|W|B)load {sym} [off] ptr mem)) && canMergeLoad(v, l) && clobber(l) -> (InvertFlags (CMP(Q|L|W|B)load {sym} [off] ptr x mem))
(CMP(Q|L|W|B)const l:(MOV(Q|L|W|B)load {sym} [off] ptr mem) [c]) (CMP(Q|L|W|B)const l:(MOV(Q|L|W|B)load {sym} [off] ptr mem) [c])
&& l.Uses == 1 && l.Uses == 1

View file

@ -107,16 +107,18 @@ func init() {
// Common regInfo // Common regInfo
var ( var (
gp01 = regInfo{inputs: nil, outputs: gponly} gp01 = regInfo{inputs: nil, outputs: gponly}
gp11 = regInfo{inputs: []regMask{gp}, outputs: gponly} gp11 = regInfo{inputs: []regMask{gp}, outputs: gponly}
gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly} gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly}
gp11sb = regInfo{inputs: []regMask{gpspsb}, outputs: gponly} gp11sb = regInfo{inputs: []regMask{gpspsb}, outputs: gponly}
gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly} gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly} gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly}
gp21sb = regInfo{inputs: []regMask{gpspsb, gpsp}, outputs: gponly} gp21sb = regInfo{inputs: []regMask{gpspsb, gpsp}, outputs: gponly}
gp21shift = regInfo{inputs: []regMask{gp, cx}, outputs: []regMask{gp}} gp21shift = regInfo{inputs: []regMask{gp, cx}, outputs: []regMask{gp}}
gp11div = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{ax, dx}} gp11div = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{ax, dx}}
gp21hmul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx}, clobbers: ax} gp21hmul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx}, clobbers: ax}
gp21flags = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, 0}}
gp2flags1flags = regInfo{inputs: []regMask{gp, gp, 0}, outputs: []regMask{gp, 0}}
gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}} gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}}
gp1flags = regInfo{inputs: []regMask{gpsp}} gp1flags = regInfo{inputs: []regMask{gpsp}}
@ -124,7 +126,8 @@ func init() {
gp1flagsLoad = regInfo{inputs: []regMask{gpspsb, gpsp, 0}} gp1flagsLoad = regInfo{inputs: []regMask{gpspsb, gpsp, 0}}
flagsgp = regInfo{inputs: nil, outputs: gponly} flagsgp = regInfo{inputs: nil, outputs: gponly}
gp11flags = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp, 0}} gp11flags = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp, 0}}
gp1flags1flags = regInfo{inputs: []regMask{gp, 0}, outputs: []regMask{gp, 0}}
readflags = regInfo{inputs: nil, outputs: gponly} readflags = regInfo{inputs: nil, outputs: gponly}
flagsgpax = regInfo{inputs: nil, clobbers: ax, outputs: []regMask{gp &^ ax}} flagsgpax = regInfo{inputs: nil, clobbers: ax, outputs: []regMask{gp &^ ax}}
@ -229,6 +232,21 @@ func init() {
{name: "DIVLU", argLength: 2, reg: gp11div, typ: "(UInt32,UInt32)", asm: "DIVL", clobberFlags: true}, // [arg0 / arg1, arg0 % arg1] {name: "DIVLU", argLength: 2, reg: gp11div, typ: "(UInt32,UInt32)", asm: "DIVL", clobberFlags: true}, // [arg0 / arg1, arg0 % arg1]
{name: "DIVWU", argLength: 2, reg: gp11div, typ: "(UInt16,UInt16)", asm: "DIVW", clobberFlags: true}, // [arg0 / arg1, arg0 % arg1] {name: "DIVWU", argLength: 2, reg: gp11div, typ: "(UInt16,UInt16)", asm: "DIVW", clobberFlags: true}, // [arg0 / arg1, arg0 % arg1]
{name: "NEGLflags", argLength: 1, reg: gp11flags, typ: "(UInt32,Flags)", asm: "NEGL", resultInArg0: true}, // -arg0, flags set for 0-arg0.
// The following 4 add opcodes return the low 64 bits of the sum in the first result and
// the carry (the 65th bit) in the carry flag.
{name: "ADDQcarry", argLength: 2, reg: gp21flags, typ: "(UInt64,Flags)", asm: "ADDQ", commutative: true, resultInArg0: true}, // r = arg0+arg1
{name: "ADCQ", argLength: 3, reg: gp2flags1flags, typ: "(UInt64,Flags)", asm: "ADCQ", commutative: true, resultInArg0: true}, // r = arg0+arg1+carry(arg2)
{name: "ADDQconstcarry", argLength: 1, reg: gp11flags, typ: "(UInt64,Flags)", asm: "ADDQ", aux: "Int32", resultInArg0: true}, // r = arg0+auxint
{name: "ADCQconst", argLength: 2, reg: gp1flags1flags, typ: "(UInt64,Flags)", asm: "ADCQ", aux: "Int32", resultInArg0: true}, // r = arg0+auxint+carry(arg1)
// The following 4 add opcodes return the low 64 bits of the difference in the first result and
// the borrow (if the result is negative) in the carry flag.
{name: "SUBQborrow", argLength: 2, reg: gp21flags, typ: "(UInt64,Flags)", asm: "SUBQ", resultInArg0: true}, // r = arg0-arg1
{name: "SBBQ", argLength: 3, reg: gp2flags1flags, typ: "(UInt64,Flags)", asm: "SBBQ", resultInArg0: true}, // r = arg0-(arg1+carry(arg2))
{name: "SUBQconstborrow", argLength: 1, reg: gp11flags, typ: "(UInt64,Flags)", asm: "SUBQ", aux: "Int32", resultInArg0: true}, // r = arg0-auxint
{name: "SBBQconst", argLength: 2, reg: gp1flags1flags, typ: "(UInt64,Flags)", asm: "SBBQ", aux: "Int32", resultInArg0: true}, // r = arg0-(auxint+carry(arg1))
{name: "MULQU2", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx, ax}}, commutative: true, asm: "MULQ", clobberFlags: true}, // arg0 * arg1, returns (hi, lo) {name: "MULQU2", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx, ax}}, commutative: true, asm: "MULQ", clobberFlags: true}, // arg0 * arg1, returns (hi, lo)
{name: "DIVQU2", argLength: 3, reg: regInfo{inputs: []regMask{dx, ax, gpsp}, outputs: []regMask{ax, dx}}, asm: "DIVQ", clobberFlags: true}, // arg0:arg1 / arg2 (128-bit divided by 64-bit), returns (q, r) {name: "DIVQU2", argLength: 3, reg: regInfo{inputs: []regMask{dx, ax, gpsp}, outputs: []regMask{ax, dx}}, asm: "DIVQ", clobberFlags: true}, // arg0:arg1 / arg2 (128-bit divided by 64-bit), returns (q, r)

View file

@ -1125,71 +1125,71 @@
// Exclude global data (SB) because these instructions cannot handle relative addresses. // Exclude global data (SB) because these instructions cannot handle relative addresses.
// TODO(mundaym): use LARL in the assembler to handle SB? // TODO(mundaym): use LARL in the assembler to handle SB?
// TODO(mundaym): indexed versions of these? // TODO(mundaym): indexed versions of these?
(ADD <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (ADD <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ADDload <t> [off] {sym} x ptr mem) -> (ADDload <t> [off] {sym} x ptr mem)
(ADD <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (ADD <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ADDload <t> [off] {sym} x ptr mem) -> (ADDload <t> [off] {sym} x ptr mem)
(ADDW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (ADDW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ADDWload <t> [off] {sym} x ptr mem) -> (ADDWload <t> [off] {sym} x ptr mem)
(ADDW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (ADDW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ADDWload <t> [off] {sym} x ptr mem) -> (ADDWload <t> [off] {sym} x ptr mem)
(ADDW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (ADDW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ADDWload <t> [off] {sym} x ptr mem) -> (ADDWload <t> [off] {sym} x ptr mem)
(ADDW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (ADDW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ADDWload <t> [off] {sym} x ptr mem) -> (ADDWload <t> [off] {sym} x ptr mem)
(MULLD <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (MULLD <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (MULLDload <t> [off] {sym} x ptr mem) -> (MULLDload <t> [off] {sym} x ptr mem)
(MULLD <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (MULLD <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (MULLDload <t> [off] {sym} x ptr mem) -> (MULLDload <t> [off] {sym} x ptr mem)
(MULLW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (MULLW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (MULLWload <t> [off] {sym} x ptr mem) -> (MULLWload <t> [off] {sym} x ptr mem)
(MULLW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (MULLW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (MULLWload <t> [off] {sym} x ptr mem) -> (MULLWload <t> [off] {sym} x ptr mem)
(MULLW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (MULLW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (MULLWload <t> [off] {sym} x ptr mem) -> (MULLWload <t> [off] {sym} x ptr mem)
(MULLW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (MULLW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (MULLWload <t> [off] {sym} x ptr mem) -> (MULLWload <t> [off] {sym} x ptr mem)
(SUB <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (SUB <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (SUBload <t> [off] {sym} x ptr mem) -> (SUBload <t> [off] {sym} x ptr mem)
(SUBW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (SUBW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (SUBWload <t> [off] {sym} x ptr mem) -> (SUBWload <t> [off] {sym} x ptr mem)
(SUBW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (SUBW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (SUBWload <t> [off] {sym} x ptr mem) -> (SUBWload <t> [off] {sym} x ptr mem)
(AND <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (AND <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ANDload <t> [off] {sym} x ptr mem) -> (ANDload <t> [off] {sym} x ptr mem)
(AND <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (AND <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ANDload <t> [off] {sym} x ptr mem) -> (ANDload <t> [off] {sym} x ptr mem)
(ANDW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (ANDW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ANDWload <t> [off] {sym} x ptr mem) -> (ANDWload <t> [off] {sym} x ptr mem)
(ANDW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (ANDW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ANDWload <t> [off] {sym} x ptr mem) -> (ANDWload <t> [off] {sym} x ptr mem)
(ANDW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (ANDW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ANDWload <t> [off] {sym} x ptr mem) -> (ANDWload <t> [off] {sym} x ptr mem)
(ANDW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (ANDW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ANDWload <t> [off] {sym} x ptr mem) -> (ANDWload <t> [off] {sym} x ptr mem)
(OR <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (OR <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ORload <t> [off] {sym} x ptr mem) -> (ORload <t> [off] {sym} x ptr mem)
(OR <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (OR <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ORload <t> [off] {sym} x ptr mem) -> (ORload <t> [off] {sym} x ptr mem)
(ORW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (ORW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ORWload <t> [off] {sym} x ptr mem) -> (ORWload <t> [off] {sym} x ptr mem)
(ORW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (ORW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ORWload <t> [off] {sym} x ptr mem) -> (ORWload <t> [off] {sym} x ptr mem)
(ORW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (ORW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ORWload <t> [off] {sym} x ptr mem) -> (ORWload <t> [off] {sym} x ptr mem)
(ORW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (ORW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (ORWload <t> [off] {sym} x ptr mem) -> (ORWload <t> [off] {sym} x ptr mem)
(XOR <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (XOR <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (XORload <t> [off] {sym} x ptr mem) -> (XORload <t> [off] {sym} x ptr mem)
(XOR <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (XOR <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (XORload <t> [off] {sym} x ptr mem) -> (XORload <t> [off] {sym} x ptr mem)
(XORW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (XORW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (XORWload <t> [off] {sym} x ptr mem) -> (XORWload <t> [off] {sym} x ptr mem)
(XORW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (XORW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (XORWload <t> [off] {sym} x ptr mem) -> (XORWload <t> [off] {sym} x ptr mem)
(XORW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (XORW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (XORWload <t> [off] {sym} x ptr mem) -> (XORWload <t> [off] {sym} x ptr mem)
(XORW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g) (XORW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g)
-> (XORWload <t> [off] {sym} x ptr mem) -> (XORWload <t> [off] {sym} x ptr mem)
// Combine constant stores into larger (unaligned) stores. // Combine constant stores into larger (unaligned) stores.

View file

@ -491,6 +491,9 @@ var genericOps = []opData{
{name: "Sub32carry", argLength: 2, typ: "(UInt32,Flags)"}, // arg0 - arg1, returns (value, carry) {name: "Sub32carry", argLength: 2, typ: "(UInt32,Flags)"}, // arg0 - arg1, returns (value, carry)
{name: "Sub32withcarry", argLength: 3}, // arg0 - arg1 - arg2, arg2=carry (0 or 1) {name: "Sub32withcarry", argLength: 3}, // arg0 - arg1 - arg2, arg2=carry (0 or 1)
{name: "Add64carry", argLength: 3, commutative: true, typ: "(UInt64,UInt64)"}, // arg0 + arg1 + arg2, arg2 must be 0 or 1. returns (value, value>>64)
{name: "Sub64borrow", argLength: 3, typ: "(UInt64,UInt64)"}, // arg0 - (arg1 + arg2), arg2 must be 0 or 1. returns (value, value>>64&1)
{name: "Signmask", argLength: 1, typ: "Int32"}, // 0 if arg0 >= 0, -1 if arg0 < 0 {name: "Signmask", argLength: 1, typ: "Int32"}, // 0 if arg0 >= 0, -1 if arg0 < 0
{name: "Zeromask", argLength: 1, typ: "UInt32"}, // 0 if arg0 == 0, 0xffffffff if arg0 != 0 {name: "Zeromask", argLength: 1, typ: "UInt32"}, // 0 if arg0 == 0, 0xffffffff if arg0 != 0
{name: "Slicemask", argLength: 1}, // 0 if arg0 == 0, -1 if arg0 > 0, undef if arg0<0. Type is native int size. {name: "Slicemask", argLength: 1}, // 0 if arg0 == 0, -1 if arg0 > 0, undef if arg0<0. Type is native int size.

View file

@ -160,10 +160,12 @@ func genRules(arch arch) {
fmt.Fprintln(w, "// generated with: cd gen; go run *.go") fmt.Fprintln(w, "// generated with: cd gen; go run *.go")
fmt.Fprintln(w) fmt.Fprintln(w)
fmt.Fprintln(w, "package ssa") fmt.Fprintln(w, "package ssa")
fmt.Fprintln(w, "import \"fmt\"")
fmt.Fprintln(w, "import \"math\"") fmt.Fprintln(w, "import \"math\"")
fmt.Fprintln(w, "import \"cmd/internal/obj\"") fmt.Fprintln(w, "import \"cmd/internal/obj\"")
fmt.Fprintln(w, "import \"cmd/internal/objabi\"") fmt.Fprintln(w, "import \"cmd/internal/objabi\"")
fmt.Fprintln(w, "import \"cmd/compile/internal/types\"") fmt.Fprintln(w, "import \"cmd/compile/internal/types\"")
fmt.Fprintln(w, "var _ = fmt.Println // in case not otherwise used")
fmt.Fprintln(w, "var _ = math.MinInt8 // in case not otherwise used") fmt.Fprintln(w, "var _ = math.MinInt8 // in case not otherwise used")
fmt.Fprintln(w, "var _ = obj.ANOP // in case not otherwise used") fmt.Fprintln(w, "var _ = obj.ANOP // in case not otherwise used")
fmt.Fprintln(w, "var _ = objabi.GOROOT // in case not otherwise used") fmt.Fprintln(w, "var _ = objabi.GOROOT // in case not otherwise used")

View file

@ -50,10 +50,14 @@ body {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
} }
h1 {
font-size: 18px;
display: inline-block;
margin: 0 1em .5em 0;
}
#helplink { #helplink {
margin-bottom: 15px; display: inline-block;
display: block;
margin-top: -15px;
} }
#help { #help {

View file

@ -523,6 +523,15 @@ const (
OpAMD64DIVQU OpAMD64DIVQU
OpAMD64DIVLU OpAMD64DIVLU
OpAMD64DIVWU OpAMD64DIVWU
OpAMD64NEGLflags
OpAMD64ADDQcarry
OpAMD64ADCQ
OpAMD64ADDQconstcarry
OpAMD64ADCQconst
OpAMD64SUBQborrow
OpAMD64SBBQ
OpAMD64SUBQconstborrow
OpAMD64SBBQconst
OpAMD64MULQU2 OpAMD64MULQU2
OpAMD64DIVQU2 OpAMD64DIVQU2
OpAMD64ANDQ OpAMD64ANDQ
@ -2393,6 +2402,8 @@ const (
OpAdd32withcarry OpAdd32withcarry
OpSub32carry OpSub32carry
OpSub32withcarry OpSub32withcarry
OpAdd64carry
OpSub64borrow
OpSignmask OpSignmask
OpZeromask OpZeromask
OpSlicemask OpSlicemask
@ -6540,6 +6551,151 @@ var opcodeTable = [...]opInfo{
}, },
}, },
}, },
{
name: "NEGLflags",
argLen: 1,
resultInArg0: true,
asm: x86.ANEGL,
reg: regInfo{
inputs: []inputInfo{
{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
outputs: []outputInfo{
{1, 0},
{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
{
name: "ADDQcarry",
argLen: 2,
commutative: true,
resultInArg0: true,
asm: x86.AADDQ,
reg: regInfo{
inputs: []inputInfo{
{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
},
outputs: []outputInfo{
{1, 0},
{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
{
name: "ADCQ",
argLen: 3,
commutative: true,
resultInArg0: true,
asm: x86.AADCQ,
reg: regInfo{
inputs: []inputInfo{
{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
},
outputs: []outputInfo{
{1, 0},
{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
{
name: "ADDQconstcarry",
auxType: auxInt32,
argLen: 1,
resultInArg0: true,
asm: x86.AADDQ,
reg: regInfo{
inputs: []inputInfo{
{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
outputs: []outputInfo{
{1, 0},
{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
{
name: "ADCQconst",
auxType: auxInt32,
argLen: 2,
resultInArg0: true,
asm: x86.AADCQ,
reg: regInfo{
inputs: []inputInfo{
{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
outputs: []outputInfo{
{1, 0},
{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
{
name: "SUBQborrow",
argLen: 2,
resultInArg0: true,
asm: x86.ASUBQ,
reg: regInfo{
inputs: []inputInfo{
{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
},
outputs: []outputInfo{
{1, 0},
{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
{
name: "SBBQ",
argLen: 3,
resultInArg0: true,
asm: x86.ASBBQ,
reg: regInfo{
inputs: []inputInfo{
{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
},
outputs: []outputInfo{
{1, 0},
{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
{
name: "SUBQconstborrow",
auxType: auxInt32,
argLen: 1,
resultInArg0: true,
asm: x86.ASUBQ,
reg: regInfo{
inputs: []inputInfo{
{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
outputs: []outputInfo{
{1, 0},
{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
{
name: "SBBQconst",
auxType: auxInt32,
argLen: 2,
resultInArg0: true,
asm: x86.ASBBQ,
reg: regInfo{
inputs: []inputInfo{
{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
outputs: []outputInfo{
{1, 0},
{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
{ {
name: "MULQU2", name: "MULQU2",
argLen: 2, argLen: 2,
@ -29629,6 +29785,17 @@ var opcodeTable = [...]opInfo{
argLen: 3, argLen: 3,
generic: true, generic: true,
}, },
{
name: "Add64carry",
argLen: 3,
commutative: true,
generic: true,
},
{
name: "Sub64borrow",
argLen: 3,
generic: true,
},
{ {
name: "Signmask", name: "Signmask",
argLen: 1, argLen: 1,

View file

@ -177,23 +177,11 @@ func canMergeSym(x, y interface{}) bool {
return x == nil || y == nil return x == nil || y == nil
} }
// canMergeLoad reports whether the load can be merged into target without // canMergeLoadClobber reports whether the load can be merged into target without
// invalidating the schedule. // invalidating the schedule.
// It also checks that the other non-load argument x is something we // It also checks that the other non-load argument x is something we
// are ok with clobbering (all our current load+op instructions clobber // are ok with clobbering.
// their input register). func canMergeLoadClobber(target, load, x *Value) bool {
func canMergeLoad(target, load, x *Value) bool {
if target.Block.ID != load.Block.ID {
// If the load is in a different block do not merge it.
return false
}
// We can't merge the load into the target if the load
// has more than one use.
if load.Uses != 1 {
return false
}
// The register containing x is going to get clobbered. // The register containing x is going to get clobbered.
// Don't merge if we still need the value of x. // Don't merge if we still need the value of x.
// We don't have liveness information here, but we can // We don't have liveness information here, but we can
@ -208,6 +196,22 @@ func canMergeLoad(target, load, x *Value) bool {
if loopnest.depth(target.Block.ID) > loopnest.depth(x.Block.ID) { if loopnest.depth(target.Block.ID) > loopnest.depth(x.Block.ID) {
return false return false
} }
return canMergeLoad(target, load)
}
// canMergeLoad reports whether the load can be merged into target without
// invalidating the schedule.
func canMergeLoad(target, load *Value) bool {
if target.Block.ID != load.Block.ID {
// If the load is in a different block do not merge it.
return false
}
// We can't merge the load into the target if the load
// has more than one use.
if load.Uses != 1 {
return false
}
mem := load.MemoryArg() mem := load.MemoryArg()

View file

@ -3,11 +3,13 @@
package ssa package ssa
import "fmt"
import "math" import "math"
import "cmd/internal/obj" import "cmd/internal/obj"
import "cmd/internal/objabi" import "cmd/internal/objabi"
import "cmd/compile/internal/types" import "cmd/compile/internal/types"
var _ = fmt.Println // in case not otherwise used
var _ = math.MinInt8 // in case not otherwise used var _ = math.MinInt8 // in case not otherwise used
var _ = obj.ANOP // in case not otherwise used var _ = obj.ANOP // in case not otherwise used
var _ = objabi.GOROOT // in case not otherwise used var _ = objabi.GOROOT // in case not otherwise used
@ -1297,7 +1299,7 @@ func rewriteValue386_Op386ADDL_20(v *Value) bool {
return true return true
} }
// match: (ADDL x l:(MOVLload [off] {sym} ptr mem)) // match: (ADDL x l:(MOVLload [off] {sym} ptr mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (ADDLload x [off] {sym} ptr mem) // result: (ADDLload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -1311,7 +1313,7 @@ func rewriteValue386_Op386ADDL_20(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386ADDLload) v.reset(Op386ADDLload)
@ -1323,7 +1325,7 @@ func rewriteValue386_Op386ADDL_20(v *Value) bool {
return true return true
} }
// match: (ADDL l:(MOVLload [off] {sym} ptr mem) x) // match: (ADDL l:(MOVLload [off] {sym} ptr mem) x)
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (ADDLload x [off] {sym} ptr mem) // result: (ADDLload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -1337,7 +1339,7 @@ func rewriteValue386_Op386ADDL_20(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386ADDLload) v.reset(Op386ADDLload)
@ -1349,7 +1351,7 @@ func rewriteValue386_Op386ADDL_20(v *Value) bool {
return true return true
} }
// match: (ADDL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) // match: (ADDL x l:(MOVLloadidx4 [off] {sym} ptr idx mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (ADDLloadidx4 x [off] {sym} ptr idx mem) // result: (ADDLloadidx4 x [off] {sym} ptr idx mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -1364,7 +1366,7 @@ func rewriteValue386_Op386ADDL_20(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
idx := l.Args[1] idx := l.Args[1]
mem := l.Args[2] mem := l.Args[2]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386ADDLloadidx4) v.reset(Op386ADDLloadidx4)
@ -1377,7 +1379,7 @@ func rewriteValue386_Op386ADDL_20(v *Value) bool {
return true return true
} }
// match: (ADDL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) // match: (ADDL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x)
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (ADDLloadidx4 x [off] {sym} ptr idx mem) // result: (ADDLloadidx4 x [off] {sym} ptr idx mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -1392,7 +1394,7 @@ func rewriteValue386_Op386ADDL_20(v *Value) bool {
idx := l.Args[1] idx := l.Args[1]
mem := l.Args[2] mem := l.Args[2]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386ADDLloadidx4) v.reset(Op386ADDLloadidx4)
@ -2163,7 +2165,7 @@ func rewriteValue386_Op386ADDSD_0(v *Value) bool {
config := b.Func.Config config := b.Func.Config
_ = config _ = config
// match: (ADDSD x l:(MOVSDload [off] {sym} ptr mem)) // match: (ADDSD x l:(MOVSDload [off] {sym} ptr mem))
// cond: canMergeLoad(v, l, x) && !config.use387 && clobber(l) // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
// result: (ADDSDload x [off] {sym} ptr mem) // result: (ADDSDload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -2177,7 +2179,7 @@ func rewriteValue386_Op386ADDSD_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && !config.use387 && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
break break
} }
v.reset(Op386ADDSDload) v.reset(Op386ADDSDload)
@ -2189,7 +2191,7 @@ func rewriteValue386_Op386ADDSD_0(v *Value) bool {
return true return true
} }
// match: (ADDSD l:(MOVSDload [off] {sym} ptr mem) x) // match: (ADDSD l:(MOVSDload [off] {sym} ptr mem) x)
// cond: canMergeLoad(v, l, x) && !config.use387 && clobber(l) // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
// result: (ADDSDload x [off] {sym} ptr mem) // result: (ADDSDload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -2203,7 +2205,7 @@ func rewriteValue386_Op386ADDSD_0(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && !config.use387 && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
break break
} }
v.reset(Op386ADDSDload) v.reset(Op386ADDSDload)
@ -2282,7 +2284,7 @@ func rewriteValue386_Op386ADDSS_0(v *Value) bool {
config := b.Func.Config config := b.Func.Config
_ = config _ = config
// match: (ADDSS x l:(MOVSSload [off] {sym} ptr mem)) // match: (ADDSS x l:(MOVSSload [off] {sym} ptr mem))
// cond: canMergeLoad(v, l, x) && !config.use387 && clobber(l) // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
// result: (ADDSSload x [off] {sym} ptr mem) // result: (ADDSSload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -2296,7 +2298,7 @@ func rewriteValue386_Op386ADDSS_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && !config.use387 && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
break break
} }
v.reset(Op386ADDSSload) v.reset(Op386ADDSSload)
@ -2308,7 +2310,7 @@ func rewriteValue386_Op386ADDSS_0(v *Value) bool {
return true return true
} }
// match: (ADDSS l:(MOVSSload [off] {sym} ptr mem) x) // match: (ADDSS l:(MOVSSload [off] {sym} ptr mem) x)
// cond: canMergeLoad(v, l, x) && !config.use387 && clobber(l) // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
// result: (ADDSSload x [off] {sym} ptr mem) // result: (ADDSSload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -2322,7 +2324,7 @@ func rewriteValue386_Op386ADDSS_0(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && !config.use387 && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
break break
} }
v.reset(Op386ADDSSload) v.reset(Op386ADDSSload)
@ -2429,7 +2431,7 @@ func rewriteValue386_Op386ANDL_0(v *Value) bool {
return true return true
} }
// match: (ANDL x l:(MOVLload [off] {sym} ptr mem)) // match: (ANDL x l:(MOVLload [off] {sym} ptr mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (ANDLload x [off] {sym} ptr mem) // result: (ANDLload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -2443,7 +2445,7 @@ func rewriteValue386_Op386ANDL_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386ANDLload) v.reset(Op386ANDLload)
@ -2455,7 +2457,7 @@ func rewriteValue386_Op386ANDL_0(v *Value) bool {
return true return true
} }
// match: (ANDL l:(MOVLload [off] {sym} ptr mem) x) // match: (ANDL l:(MOVLload [off] {sym} ptr mem) x)
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (ANDLload x [off] {sym} ptr mem) // result: (ANDLload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -2469,7 +2471,7 @@ func rewriteValue386_Op386ANDL_0(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386ANDLload) v.reset(Op386ANDLload)
@ -2481,7 +2483,7 @@ func rewriteValue386_Op386ANDL_0(v *Value) bool {
return true return true
} }
// match: (ANDL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) // match: (ANDL x l:(MOVLloadidx4 [off] {sym} ptr idx mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (ANDLloadidx4 x [off] {sym} ptr idx mem) // result: (ANDLloadidx4 x [off] {sym} ptr idx mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -2496,7 +2498,7 @@ func rewriteValue386_Op386ANDL_0(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
idx := l.Args[1] idx := l.Args[1]
mem := l.Args[2] mem := l.Args[2]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386ANDLloadidx4) v.reset(Op386ANDLloadidx4)
@ -2509,7 +2511,7 @@ func rewriteValue386_Op386ANDL_0(v *Value) bool {
return true return true
} }
// match: (ANDL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) // match: (ANDL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x)
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (ANDLloadidx4 x [off] {sym} ptr idx mem) // result: (ANDLloadidx4 x [off] {sym} ptr idx mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -2524,7 +2526,7 @@ func rewriteValue386_Op386ANDL_0(v *Value) bool {
idx := l.Args[1] idx := l.Args[1]
mem := l.Args[2] mem := l.Args[2]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386ANDLloadidx4) v.reset(Op386ANDLloadidx4)
@ -3151,7 +3153,7 @@ func rewriteValue386_Op386CMPB_0(v *Value) bool {
return true return true
} }
// match: (CMPB l:(MOVBload {sym} [off] ptr mem) x) // match: (CMPB l:(MOVBload {sym} [off] ptr mem) x)
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoad(v, l) && clobber(l)
// result: (CMPBload {sym} [off] ptr x mem) // result: (CMPBload {sym} [off] ptr x mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -3165,7 +3167,7 @@ func rewriteValue386_Op386CMPB_0(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoad(v, l) && clobber(l)) {
break break
} }
v.reset(Op386CMPBload) v.reset(Op386CMPBload)
@ -3177,7 +3179,7 @@ func rewriteValue386_Op386CMPB_0(v *Value) bool {
return true return true
} }
// match: (CMPB x l:(MOVBload {sym} [off] ptr mem)) // match: (CMPB x l:(MOVBload {sym} [off] ptr mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoad(v, l) && clobber(l)
// result: (InvertFlags (CMPBload {sym} [off] ptr x mem)) // result: (InvertFlags (CMPBload {sym} [off] ptr x mem))
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -3191,7 +3193,7 @@ func rewriteValue386_Op386CMPB_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoad(v, l) && clobber(l)) {
break break
} }
v.reset(Op386InvertFlags) v.reset(Op386InvertFlags)
@ -3455,7 +3457,7 @@ func rewriteValue386_Op386CMPL_0(v *Value) bool {
return true return true
} }
// match: (CMPL l:(MOVLload {sym} [off] ptr mem) x) // match: (CMPL l:(MOVLload {sym} [off] ptr mem) x)
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoad(v, l) && clobber(l)
// result: (CMPLload {sym} [off] ptr x mem) // result: (CMPLload {sym} [off] ptr x mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -3469,7 +3471,7 @@ func rewriteValue386_Op386CMPL_0(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoad(v, l) && clobber(l)) {
break break
} }
v.reset(Op386CMPLload) v.reset(Op386CMPLload)
@ -3481,7 +3483,7 @@ func rewriteValue386_Op386CMPL_0(v *Value) bool {
return true return true
} }
// match: (CMPL x l:(MOVLload {sym} [off] ptr mem)) // match: (CMPL x l:(MOVLload {sym} [off] ptr mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoad(v, l) && clobber(l)
// result: (InvertFlags (CMPLload {sym} [off] ptr x mem)) // result: (InvertFlags (CMPLload {sym} [off] ptr x mem))
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -3495,7 +3497,7 @@ func rewriteValue386_Op386CMPL_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoad(v, l) && clobber(l)) {
break break
} }
v.reset(Op386InvertFlags) v.reset(Op386InvertFlags)
@ -3778,7 +3780,7 @@ func rewriteValue386_Op386CMPW_0(v *Value) bool {
return true return true
} }
// match: (CMPW l:(MOVWload {sym} [off] ptr mem) x) // match: (CMPW l:(MOVWload {sym} [off] ptr mem) x)
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoad(v, l) && clobber(l)
// result: (CMPWload {sym} [off] ptr x mem) // result: (CMPWload {sym} [off] ptr x mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -3792,7 +3794,7 @@ func rewriteValue386_Op386CMPW_0(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoad(v, l) && clobber(l)) {
break break
} }
v.reset(Op386CMPWload) v.reset(Op386CMPWload)
@ -3804,7 +3806,7 @@ func rewriteValue386_Op386CMPW_0(v *Value) bool {
return true return true
} }
// match: (CMPW x l:(MOVWload {sym} [off] ptr mem)) // match: (CMPW x l:(MOVWload {sym} [off] ptr mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoad(v, l) && clobber(l)
// result: (InvertFlags (CMPWload {sym} [off] ptr x mem)) // result: (InvertFlags (CMPWload {sym} [off] ptr x mem))
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -3818,7 +3820,7 @@ func rewriteValue386_Op386CMPW_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoad(v, l) && clobber(l)) {
break break
} }
v.reset(Op386InvertFlags) v.reset(Op386InvertFlags)
@ -4050,7 +4052,7 @@ func rewriteValue386_Op386DIVSD_0(v *Value) bool {
config := b.Func.Config config := b.Func.Config
_ = config _ = config
// match: (DIVSD x l:(MOVSDload [off] {sym} ptr mem)) // match: (DIVSD x l:(MOVSDload [off] {sym} ptr mem))
// cond: canMergeLoad(v, l, x) && !config.use387 && clobber(l) // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
// result: (DIVSDload x [off] {sym} ptr mem) // result: (DIVSDload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -4064,7 +4066,7 @@ func rewriteValue386_Op386DIVSD_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && !config.use387 && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
break break
} }
v.reset(Op386DIVSDload) v.reset(Op386DIVSDload)
@ -4143,7 +4145,7 @@ func rewriteValue386_Op386DIVSS_0(v *Value) bool {
config := b.Func.Config config := b.Func.Config
_ = config _ = config
// match: (DIVSS x l:(MOVSSload [off] {sym} ptr mem)) // match: (DIVSS x l:(MOVSSload [off] {sym} ptr mem))
// cond: canMergeLoad(v, l, x) && !config.use387 && clobber(l) // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
// result: (DIVSSload x [off] {sym} ptr mem) // result: (DIVSSload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -4157,7 +4159,7 @@ func rewriteValue386_Op386DIVSS_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && !config.use387 && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
break break
} }
v.reset(Op386DIVSSload) v.reset(Op386DIVSSload)
@ -12773,7 +12775,7 @@ func rewriteValue386_Op386MULL_0(v *Value) bool {
return true return true
} }
// match: (MULL x l:(MOVLload [off] {sym} ptr mem)) // match: (MULL x l:(MOVLload [off] {sym} ptr mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (MULLload x [off] {sym} ptr mem) // result: (MULLload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -12787,7 +12789,7 @@ func rewriteValue386_Op386MULL_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386MULLload) v.reset(Op386MULLload)
@ -12799,7 +12801,7 @@ func rewriteValue386_Op386MULL_0(v *Value) bool {
return true return true
} }
// match: (MULL l:(MOVLload [off] {sym} ptr mem) x) // match: (MULL l:(MOVLload [off] {sym} ptr mem) x)
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (MULLload x [off] {sym} ptr mem) // result: (MULLload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -12813,7 +12815,7 @@ func rewriteValue386_Op386MULL_0(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386MULLload) v.reset(Op386MULLload)
@ -12825,7 +12827,7 @@ func rewriteValue386_Op386MULL_0(v *Value) bool {
return true return true
} }
// match: (MULL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) // match: (MULL x l:(MOVLloadidx4 [off] {sym} ptr idx mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (MULLloadidx4 x [off] {sym} ptr idx mem) // result: (MULLloadidx4 x [off] {sym} ptr idx mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -12840,7 +12842,7 @@ func rewriteValue386_Op386MULL_0(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
idx := l.Args[1] idx := l.Args[1]
mem := l.Args[2] mem := l.Args[2]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386MULLloadidx4) v.reset(Op386MULLloadidx4)
@ -12853,7 +12855,7 @@ func rewriteValue386_Op386MULL_0(v *Value) bool {
return true return true
} }
// match: (MULL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) // match: (MULL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x)
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (MULLloadidx4 x [off] {sym} ptr idx mem) // result: (MULLloadidx4 x [off] {sym} ptr idx mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -12868,7 +12870,7 @@ func rewriteValue386_Op386MULL_0(v *Value) bool {
idx := l.Args[1] idx := l.Args[1]
mem := l.Args[2] mem := l.Args[2]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386MULLloadidx4) v.reset(Op386MULLloadidx4)
@ -13575,7 +13577,7 @@ func rewriteValue386_Op386MULSD_0(v *Value) bool {
config := b.Func.Config config := b.Func.Config
_ = config _ = config
// match: (MULSD x l:(MOVSDload [off] {sym} ptr mem)) // match: (MULSD x l:(MOVSDload [off] {sym} ptr mem))
// cond: canMergeLoad(v, l, x) && !config.use387 && clobber(l) // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
// result: (MULSDload x [off] {sym} ptr mem) // result: (MULSDload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -13589,7 +13591,7 @@ func rewriteValue386_Op386MULSD_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && !config.use387 && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
break break
} }
v.reset(Op386MULSDload) v.reset(Op386MULSDload)
@ -13601,7 +13603,7 @@ func rewriteValue386_Op386MULSD_0(v *Value) bool {
return true return true
} }
// match: (MULSD l:(MOVSDload [off] {sym} ptr mem) x) // match: (MULSD l:(MOVSDload [off] {sym} ptr mem) x)
// cond: canMergeLoad(v, l, x) && !config.use387 && clobber(l) // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
// result: (MULSDload x [off] {sym} ptr mem) // result: (MULSDload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -13615,7 +13617,7 @@ func rewriteValue386_Op386MULSD_0(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && !config.use387 && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
break break
} }
v.reset(Op386MULSDload) v.reset(Op386MULSDload)
@ -13694,7 +13696,7 @@ func rewriteValue386_Op386MULSS_0(v *Value) bool {
config := b.Func.Config config := b.Func.Config
_ = config _ = config
// match: (MULSS x l:(MOVSSload [off] {sym} ptr mem)) // match: (MULSS x l:(MOVSSload [off] {sym} ptr mem))
// cond: canMergeLoad(v, l, x) && !config.use387 && clobber(l) // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
// result: (MULSSload x [off] {sym} ptr mem) // result: (MULSSload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -13708,7 +13710,7 @@ func rewriteValue386_Op386MULSS_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && !config.use387 && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
break break
} }
v.reset(Op386MULSSload) v.reset(Op386MULSSload)
@ -13720,7 +13722,7 @@ func rewriteValue386_Op386MULSS_0(v *Value) bool {
return true return true
} }
// match: (MULSS l:(MOVSSload [off] {sym} ptr mem) x) // match: (MULSS l:(MOVSSload [off] {sym} ptr mem) x)
// cond: canMergeLoad(v, l, x) && !config.use387 && clobber(l) // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
// result: (MULSSload x [off] {sym} ptr mem) // result: (MULSSload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -13734,7 +13736,7 @@ func rewriteValue386_Op386MULSS_0(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && !config.use387 && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
break break
} }
v.reset(Op386MULSSload) v.reset(Op386MULSSload)
@ -14039,7 +14041,7 @@ func rewriteValue386_Op386ORL_0(v *Value) bool {
return true return true
} }
// match: (ORL x l:(MOVLload [off] {sym} ptr mem)) // match: (ORL x l:(MOVLload [off] {sym} ptr mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (ORLload x [off] {sym} ptr mem) // result: (ORLload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -14053,7 +14055,7 @@ func rewriteValue386_Op386ORL_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386ORLload) v.reset(Op386ORLload)
@ -14065,7 +14067,7 @@ func rewriteValue386_Op386ORL_0(v *Value) bool {
return true return true
} }
// match: (ORL l:(MOVLload [off] {sym} ptr mem) x) // match: (ORL l:(MOVLload [off] {sym} ptr mem) x)
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (ORLload x [off] {sym} ptr mem) // result: (ORLload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -14079,7 +14081,7 @@ func rewriteValue386_Op386ORL_0(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386ORLload) v.reset(Op386ORLload)
@ -14098,7 +14100,7 @@ func rewriteValue386_Op386ORL_10(v *Value) bool {
typ := &b.Func.Config.Types typ := &b.Func.Config.Types
_ = typ _ = typ
// match: (ORL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) // match: (ORL x l:(MOVLloadidx4 [off] {sym} ptr idx mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (ORLloadidx4 x [off] {sym} ptr idx mem) // result: (ORLloadidx4 x [off] {sym} ptr idx mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -14113,7 +14115,7 @@ func rewriteValue386_Op386ORL_10(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
idx := l.Args[1] idx := l.Args[1]
mem := l.Args[2] mem := l.Args[2]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386ORLloadidx4) v.reset(Op386ORLloadidx4)
@ -14126,7 +14128,7 @@ func rewriteValue386_Op386ORL_10(v *Value) bool {
return true return true
} }
// match: (ORL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) // match: (ORL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x)
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (ORLloadidx4 x [off] {sym} ptr idx mem) // result: (ORLloadidx4 x [off] {sym} ptr idx mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -14141,7 +14143,7 @@ func rewriteValue386_Op386ORL_10(v *Value) bool {
idx := l.Args[1] idx := l.Args[1]
mem := l.Args[2] mem := l.Args[2]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386ORLloadidx4) v.reset(Op386ORLloadidx4)
@ -19618,7 +19620,7 @@ func rewriteValue386_Op386SUBL_0(v *Value) bool {
return true return true
} }
// match: (SUBL x l:(MOVLload [off] {sym} ptr mem)) // match: (SUBL x l:(MOVLload [off] {sym} ptr mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (SUBLload x [off] {sym} ptr mem) // result: (SUBLload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -19632,7 +19634,7 @@ func rewriteValue386_Op386SUBL_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386SUBLload) v.reset(Op386SUBLload)
@ -19644,7 +19646,7 @@ func rewriteValue386_Op386SUBL_0(v *Value) bool {
return true return true
} }
// match: (SUBL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) // match: (SUBL x l:(MOVLloadidx4 [off] {sym} ptr idx mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (SUBLloadidx4 x [off] {sym} ptr idx mem) // result: (SUBLloadidx4 x [off] {sym} ptr idx mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -19659,7 +19661,7 @@ func rewriteValue386_Op386SUBL_0(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
idx := l.Args[1] idx := l.Args[1]
mem := l.Args[2] mem := l.Args[2]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386SUBLloadidx4) v.reset(Op386SUBLloadidx4)
@ -20098,7 +20100,7 @@ func rewriteValue386_Op386SUBSD_0(v *Value) bool {
config := b.Func.Config config := b.Func.Config
_ = config _ = config
// match: (SUBSD x l:(MOVSDload [off] {sym} ptr mem)) // match: (SUBSD x l:(MOVSDload [off] {sym} ptr mem))
// cond: canMergeLoad(v, l, x) && !config.use387 && clobber(l) // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
// result: (SUBSDload x [off] {sym} ptr mem) // result: (SUBSDload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -20112,7 +20114,7 @@ func rewriteValue386_Op386SUBSD_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && !config.use387 && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
break break
} }
v.reset(Op386SUBSDload) v.reset(Op386SUBSDload)
@ -20191,7 +20193,7 @@ func rewriteValue386_Op386SUBSS_0(v *Value) bool {
config := b.Func.Config config := b.Func.Config
_ = config _ = config
// match: (SUBSS x l:(MOVSSload [off] {sym} ptr mem)) // match: (SUBSS x l:(MOVSSload [off] {sym} ptr mem))
// cond: canMergeLoad(v, l, x) && !config.use387 && clobber(l) // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
// result: (SUBSSload x [off] {sym} ptr mem) // result: (SUBSSload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -20205,7 +20207,7 @@ func rewriteValue386_Op386SUBSS_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && !config.use387 && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
break break
} }
v.reset(Op386SUBSSload) v.reset(Op386SUBSSload)
@ -20478,7 +20480,7 @@ func rewriteValue386_Op386XORL_0(v *Value) bool {
return true return true
} }
// match: (XORL x l:(MOVLload [off] {sym} ptr mem)) // match: (XORL x l:(MOVLload [off] {sym} ptr mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (XORLload x [off] {sym} ptr mem) // result: (XORLload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -20492,7 +20494,7 @@ func rewriteValue386_Op386XORL_0(v *Value) bool {
_ = l.Args[1] _ = l.Args[1]
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386XORLload) v.reset(Op386XORLload)
@ -20504,7 +20506,7 @@ func rewriteValue386_Op386XORL_0(v *Value) bool {
return true return true
} }
// match: (XORL l:(MOVLload [off] {sym} ptr mem) x) // match: (XORL l:(MOVLload [off] {sym} ptr mem) x)
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (XORLload x [off] {sym} ptr mem) // result: (XORLload x [off] {sym} ptr mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -20518,7 +20520,7 @@ func rewriteValue386_Op386XORL_0(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
mem := l.Args[1] mem := l.Args[1]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386XORLload) v.reset(Op386XORLload)
@ -20533,7 +20535,7 @@ func rewriteValue386_Op386XORL_0(v *Value) bool {
} }
func rewriteValue386_Op386XORL_10(v *Value) bool { func rewriteValue386_Op386XORL_10(v *Value) bool {
// match: (XORL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) // match: (XORL x l:(MOVLloadidx4 [off] {sym} ptr idx mem))
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (XORLloadidx4 x [off] {sym} ptr idx mem) // result: (XORLloadidx4 x [off] {sym} ptr idx mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -20548,7 +20550,7 @@ func rewriteValue386_Op386XORL_10(v *Value) bool {
ptr := l.Args[0] ptr := l.Args[0]
idx := l.Args[1] idx := l.Args[1]
mem := l.Args[2] mem := l.Args[2]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386XORLloadidx4) v.reset(Op386XORLloadidx4)
@ -20561,7 +20563,7 @@ func rewriteValue386_Op386XORL_10(v *Value) bool {
return true return true
} }
// match: (XORL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) // match: (XORL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x)
// cond: canMergeLoad(v, l, x) && clobber(l) // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (XORLloadidx4 x [off] {sym} ptr idx mem) // result: (XORLloadidx4 x [off] {sym} ptr idx mem)
for { for {
_ = v.Args[1] _ = v.Args[1]
@ -20576,7 +20578,7 @@ func rewriteValue386_Op386XORL_10(v *Value) bool {
idx := l.Args[1] idx := l.Args[1]
mem := l.Args[2] mem := l.Args[2]
x := v.Args[1] x := v.Args[1]
if !(canMergeLoad(v, l, x) && clobber(l)) { if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break break
} }
v.reset(Op386XORLloadidx4) v.reset(Op386XORLloadidx4)

File diff suppressed because it is too large Load diff

View file

@ -3,11 +3,13 @@
package ssa package ssa
import "fmt"
import "math" import "math"
import "cmd/internal/obj" import "cmd/internal/obj"
import "cmd/internal/objabi" import "cmd/internal/objabi"
import "cmd/compile/internal/types" import "cmd/compile/internal/types"
var _ = fmt.Println // in case not otherwise used
var _ = math.MinInt8 // in case not otherwise used var _ = math.MinInt8 // in case not otherwise used
var _ = obj.ANOP // in case not otherwise used var _ = obj.ANOP // in case not otherwise used
var _ = objabi.GOROOT // in case not otherwise used var _ = objabi.GOROOT // in case not otherwise used

View file

@ -3,11 +3,13 @@
package ssa package ssa
import "fmt"
import "math" import "math"
import "cmd/internal/obj" import "cmd/internal/obj"
import "cmd/internal/objabi" import "cmd/internal/objabi"
import "cmd/compile/internal/types" import "cmd/compile/internal/types"
var _ = fmt.Println // in case not otherwise used
var _ = math.MinInt8 // in case not otherwise used var _ = math.MinInt8 // in case not otherwise used
var _ = obj.ANOP // in case not otherwise used var _ = obj.ANOP // in case not otherwise used
var _ = objabi.GOROOT // in case not otherwise used var _ = objabi.GOROOT // in case not otherwise used

View file

@ -3,11 +3,13 @@
package ssa package ssa
import "fmt"
import "math" import "math"
import "cmd/internal/obj" import "cmd/internal/obj"
import "cmd/internal/objabi" import "cmd/internal/objabi"
import "cmd/compile/internal/types" import "cmd/compile/internal/types"
var _ = fmt.Println // in case not otherwise used
var _ = math.MinInt8 // in case not otherwise used var _ = math.MinInt8 // in case not otherwise used
var _ = obj.ANOP // in case not otherwise used var _ = obj.ANOP // in case not otherwise used
var _ = objabi.GOROOT // in case not otherwise used var _ = objabi.GOROOT // in case not otherwise used

View file

@ -3,11 +3,13 @@
package ssa package ssa
import "fmt"
import "math" import "math"
import "cmd/internal/obj" import "cmd/internal/obj"
import "cmd/internal/objabi" import "cmd/internal/objabi"
import "cmd/compile/internal/types" import "cmd/compile/internal/types"
var _ = fmt.Println // in case not otherwise used
var _ = math.MinInt8 // in case not otherwise used var _ = math.MinInt8 // in case not otherwise used
var _ = obj.ANOP // in case not otherwise used var _ = obj.ANOP // in case not otherwise used
var _ = objabi.GOROOT // in case not otherwise used var _ = objabi.GOROOT // in case not otherwise used

View file

@ -3,11 +3,13 @@
package ssa package ssa
import "fmt"
import "math" import "math"
import "cmd/internal/obj" import "cmd/internal/obj"
import "cmd/internal/objabi" import "cmd/internal/objabi"
import "cmd/compile/internal/types" import "cmd/compile/internal/types"
var _ = fmt.Println // in case not otherwise used
var _ = math.MinInt8 // in case not otherwise used var _ = math.MinInt8 // in case not otherwise used
var _ = obj.ANOP // in case not otherwise used var _ = obj.ANOP // in case not otherwise used
var _ = objabi.GOROOT // in case not otherwise used var _ = objabi.GOROOT // in case not otherwise used

File diff suppressed because it is too large Load diff

View file

@ -3,11 +3,13 @@
package ssa package ssa
import "fmt"
import "math" import "math"
import "cmd/internal/obj" import "cmd/internal/obj"
import "cmd/internal/objabi" import "cmd/internal/objabi"
import "cmd/compile/internal/types" import "cmd/compile/internal/types"
var _ = fmt.Println // in case not otherwise used
var _ = math.MinInt8 // in case not otherwise used var _ = math.MinInt8 // in case not otherwise used
var _ = obj.ANOP // in case not otherwise used var _ = obj.ANOP // in case not otherwise used
var _ = objabi.GOROOT // in case not otherwise used var _ = objabi.GOROOT // in case not otherwise used

View file

@ -3,11 +3,13 @@
package ssa package ssa
import "fmt"
import "math" import "math"
import "cmd/internal/obj" import "cmd/internal/obj"
import "cmd/internal/objabi" import "cmd/internal/objabi"
import "cmd/compile/internal/types" import "cmd/compile/internal/types"
var _ = fmt.Println // in case not otherwise used
var _ = math.MinInt8 // in case not otherwise used var _ = math.MinInt8 // in case not otherwise used
var _ = obj.ANOP // in case not otherwise used var _ = obj.ANOP // in case not otherwise used
var _ = objabi.GOROOT // in case not otherwise used var _ = objabi.GOROOT // in case not otherwise used

View file

@ -3,11 +3,13 @@
package ssa package ssa
import "fmt"
import "math" import "math"
import "cmd/internal/obj" import "cmd/internal/obj"
import "cmd/internal/objabi" import "cmd/internal/objabi"
import "cmd/compile/internal/types" import "cmd/compile/internal/types"
var _ = fmt.Println // in case not otherwise used
var _ = math.MinInt8 // in case not otherwise used var _ = math.MinInt8 // in case not otherwise used
var _ = obj.ANOP // in case not otherwise used var _ = obj.ANOP // in case not otherwise used
var _ = objabi.GOROOT // in case not otherwise used var _ = objabi.GOROOT // in case not otherwise used

View file

@ -3,11 +3,13 @@
package ssa package ssa
import "fmt"
import "math" import "math"
import "cmd/internal/obj" import "cmd/internal/obj"
import "cmd/internal/objabi" import "cmd/internal/objabi"
import "cmd/compile/internal/types" import "cmd/compile/internal/types"
var _ = fmt.Println // in case not otherwise used
var _ = math.MinInt8 // in case not otherwise used var _ = math.MinInt8 // in case not otherwise used
var _ = obj.ANOP // in case not otherwise used var _ = obj.ANOP // in case not otherwise used
var _ = objabi.GOROOT // in case not otherwise used var _ = objabi.GOROOT // in case not otherwise used

View file

@ -13,6 +13,7 @@ const (
ScoreReadTuple ScoreReadTuple
ScoreVarDef ScoreVarDef
ScoreMemory ScoreMemory
ScoreReadFlags
ScoreDefault ScoreDefault
ScoreFlags ScoreFlags
ScoreControl // towards bottom of block ScoreControl // towards bottom of block
@ -129,13 +130,19 @@ func schedule(f *Func) {
// false dependency on the other part of the tuple. // false dependency on the other part of the tuple.
// Also ensures tuple is never spilled. // Also ensures tuple is never spilled.
score[v.ID] = ScoreReadTuple score[v.ID] = ScoreReadTuple
case v.Type.IsFlags() || v.Type.IsTuple(): case v.Type.IsFlags() || v.Type.IsTuple() && v.Type.FieldType(1).IsFlags():
// Schedule flag register generation as late as possible. // Schedule flag register generation as late as possible.
// This makes sure that we only have one live flags // This makes sure that we only have one live flags
// value at a time. // value at a time.
score[v.ID] = ScoreFlags score[v.ID] = ScoreFlags
default: default:
score[v.ID] = ScoreDefault score[v.ID] = ScoreDefault
// If we're reading flags, schedule earlier to keep flag lifetime short.
for _, a := range v.Args {
if a.Type.IsFlags() {
score[v.ID] = ScoreReadFlags
}
}
} }
} }
} }

View file

@ -1,6 +1,7 @@
package ssa_test package ssa_test
import ( import (
"cmd/internal/xcoff"
"debug/dwarf" "debug/dwarf"
"debug/elf" "debug/elf"
"debug/macho" "debug/macho"
@ -25,6 +26,10 @@ func open(path string) (*dwarf.Data, error) {
return fh.DWARF() return fh.DWARF()
} }
if fh, err := xcoff.Open(path); err == nil {
return fh.DWARF()
}
return nil, fmt.Errorf("unrecognized executable format") return nil, fmt.Errorf("unrecognized executable format")
} }

View file

@ -2499,7 +2499,7 @@
// In general, adding a new dependency may require upgrading // In general, adding a new dependency may require upgrading
// existing dependencies to keep a working build, and 'go get' does // existing dependencies to keep a working build, and 'go get' does
// this automatically. Similarly, downgrading one dependency may // this automatically. Similarly, downgrading one dependency may
// require downgrading other dependenceis, and 'go get' does // require downgrading other dependencies, and 'go get' does
// this automatically as well. // this automatically as well.
// //
// The -m flag instructs get to stop here, after resolving, upgrading, // The -m flag instructs get to stop here, after resolving, upgrading,

View file

@ -9,7 +9,6 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"sync" "sync"
) )
@ -78,52 +77,19 @@ func defaultDir() (string, bool) {
} }
// Compute default location. // Compute default location.
// TODO(rsc): This code belongs somewhere else, dir, err := os.UserCacheDir()
// like maybe ioutil.CacheDir or os.CacheDir. if err != nil {
showWarnings := true return "off", true
switch runtime.GOOS {
case "windows":
dir = os.Getenv("LocalAppData")
if dir == "" {
// Fall back to %AppData%, the old name of
// %LocalAppData% on Windows XP.
dir = os.Getenv("AppData")
}
if dir == "" {
return "off", true
}
case "darwin":
dir = os.Getenv("HOME")
if dir == "" {
return "off", true
}
dir += "/Library/Caches"
case "plan9":
dir = os.Getenv("home")
if dir == "" {
return "off", true
}
// Plan 9 has no established per-user cache directory,
// but $home/lib/xyz is the usual equivalent of $HOME/.xyz on Unix.
dir += "/lib/cache"
default: // Unix
// https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
dir = os.Getenv("XDG_CACHE_HOME")
if dir == "" {
dir = os.Getenv("HOME")
if dir == "" {
return "off", true
}
if dir == "/" {
// probably docker run with -u flag
// https://golang.org/issue/26280
showWarnings = false
}
dir += "/.cache"
}
} }
return filepath.Join(dir, "go-build"), showWarnings dir = filepath.Join(dir, "go-build")
// Do this after filepath.Join, so that the path has been cleaned.
showWarnings := true
switch dir {
case "/.cache/go-build":
// probably docker run with -u flag
// https://golang.org/issue/26280
showWarnings = false
}
return dir, showWarnings
} }

View file

@ -45,7 +45,7 @@ func runVendor(cmd *base.Command, args []string) {
vdir := filepath.Join(modload.ModRoot, "vendor") vdir := filepath.Join(modload.ModRoot, "vendor")
if err := os.RemoveAll(vdir); err != nil { if err := os.RemoveAll(vdir); err != nil {
base.Fatalf("go vendor: %v", err) base.Fatalf("go mod vendor: %v", err)
} }
modpkgs := make(map[module.Version][]string) modpkgs := make(map[module.Version][]string)
@ -85,7 +85,7 @@ func runVendor(cmd *base.Command, args []string) {
return return
} }
if err := ioutil.WriteFile(filepath.Join(vdir, "modules.txt"), buf.Bytes(), 0666); err != nil { if err := ioutil.WriteFile(filepath.Join(vdir, "modules.txt"), buf.Bytes(), 0666); err != nil {
base.Fatalf("go vendor: %v", err) base.Fatalf("go mod vendor: %v", err)
} }
} }
@ -172,10 +172,10 @@ func matchNonTest(info os.FileInfo) bool {
func copyDir(dst, src string, match func(os.FileInfo) bool) { func copyDir(dst, src string, match func(os.FileInfo) bool) {
files, err := ioutil.ReadDir(src) files, err := ioutil.ReadDir(src)
if err != nil { if err != nil {
base.Fatalf("go vendor: %v", err) base.Fatalf("go mod vendor: %v", err)
} }
if err := os.MkdirAll(dst, 0777); err != nil { if err := os.MkdirAll(dst, 0777); err != nil {
base.Fatalf("go vendor: %v", err) base.Fatalf("go mod vendor: %v", err)
} }
for _, file := range files { for _, file := range files {
if file.IsDir() || !file.Mode().IsRegular() || !match(file) { if file.IsDir() || !file.Mode().IsRegular() || !match(file) {
@ -183,18 +183,18 @@ func copyDir(dst, src string, match func(os.FileInfo) bool) {
} }
r, err := os.Open(filepath.Join(src, file.Name())) r, err := os.Open(filepath.Join(src, file.Name()))
if err != nil { if err != nil {
base.Fatalf("go vendor: %v", err) base.Fatalf("go mod vendor: %v", err)
} }
w, err := os.Create(filepath.Join(dst, file.Name())) w, err := os.Create(filepath.Join(dst, file.Name()))
if err != nil { if err != nil {
base.Fatalf("go vendor: %v", err) base.Fatalf("go mod vendor: %v", err)
} }
if _, err := io.Copy(w, r); err != nil { if _, err := io.Copy(w, r); err != nil {
base.Fatalf("go vendor: %v", err) base.Fatalf("go mod vendor: %v", err)
} }
r.Close() r.Close()
if err := w.Close(); err != nil { if err := w.Close(); err != nil {
base.Fatalf("go vendor: %v", err) base.Fatalf("go mod vendor: %v", err)
} }
} }
} }

View file

@ -78,7 +78,7 @@ to use newer patch releases when available. Continuing the previous example,
In general, adding a new dependency may require upgrading In general, adding a new dependency may require upgrading
existing dependencies to keep a working build, and 'go get' does existing dependencies to keep a working build, and 'go get' does
this automatically. Similarly, downgrading one dependency may this automatically. Similarly, downgrading one dependency may
require downgrading other dependenceis, and 'go get' does require downgrading other dependencies, and 'go get' does
this automatically as well. this automatically as well.
The -m flag instructs get to stop here, after resolving, upgrading, The -m flag instructs get to stop here, after resolving, upgrading,

View file

@ -145,34 +145,38 @@ func moduleInfo(m module.Version, fromBuildList bool) *modinfo.ModulePublic {
} }
} }
} }
if cfg.BuildMod == "vendor" {
m.Dir = filepath.Join(ModRoot, "vendor", m.Path)
}
} }
complete(info) if !fromBuildList {
complete(info)
if fromBuildList { return info
if r := Replacement(m); r.Path != "" {
info.Replace = &modinfo.ModulePublic{
Path: r.Path,
Version: r.Version,
GoVersion: info.GoVersion,
}
if r.Version == "" {
if filepath.IsAbs(r.Path) {
info.Replace.Dir = r.Path
} else {
info.Replace.Dir = filepath.Join(ModRoot, r.Path)
}
}
complete(info.Replace)
info.Dir = info.Replace.Dir
info.GoMod = filepath.Join(info.Dir, "go.mod")
info.Error = nil // ignore error loading original module version (it has been replaced)
}
} }
r := Replacement(m)
if r.Path == "" {
complete(info)
return info
}
// Don't hit the network to fill in extra data for replaced modules.
// The original resolved Version and Time don't matter enough to be
// worth the cost, and we're going to overwrite the GoMod and Dir from the
// replacement anyway. See https://golang.org/issue/27859.
info.Replace = &modinfo.ModulePublic{
Path: r.Path,
Version: r.Version,
GoVersion: info.GoVersion,
}
if r.Version == "" {
if filepath.IsAbs(r.Path) {
info.Replace.Dir = r.Path
} else {
info.Replace.Dir = filepath.Join(ModRoot, r.Path)
}
}
complete(info.Replace)
info.Dir = info.Replace.Dir
info.GoMod = filepath.Join(info.Dir, "go.mod")
return info return info
} }
@ -224,6 +228,10 @@ func findModule(target, path string) module.Version {
if path == "." { if path == "." {
return buildList[0] return buildList[0]
} }
if cfg.BuildMod == "vendor" {
readVendorList()
return vendorMap[path]
}
for _, mod := range buildList { for _, mod := range buildList {
if maybeInModule(path, mod.Path) { if maybeInModule(path, mod.Path) {
return mod return mod

View file

@ -68,6 +68,7 @@ func (e *MissingModuleError) Error() string {
} }
// BuildList returns the build list for the target module. // BuildList returns the build list for the target module.
// The first element is the target itself, with the remainder of the list sorted by path.
func BuildList(target module.Version, reqs Reqs) ([]module.Version, error) { func BuildList(target module.Version, reqs Reqs) ([]module.Version, error) {
return buildList(target, reqs, nil) return buildList(target, reqs, nil)
} }

View file

@ -2080,14 +2080,37 @@ func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []s
} }
// gccld runs the gcc linker to create an executable from a set of object files. // gccld runs the gcc linker to create an executable from a set of object files.
func (b *Builder) gccld(p *load.Package, objdir, out string, flags []string, objs []string) error { func (b *Builder) gccld(p *load.Package, objdir, outfile string, flags []string, objs []string) error {
var cmd []string var cmd []string
if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 { if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 {
cmd = b.GxxCmd(p.Dir, objdir) cmd = b.GxxCmd(p.Dir, objdir)
} else { } else {
cmd = b.GccCmd(p.Dir, objdir) cmd = b.GccCmd(p.Dir, objdir)
} }
return b.run(nil, p.Dir, p.ImportPath, b.cCompilerEnv(), cmd, "-o", out, objs, flags)
cmdargs := []interface{}{cmd, "-o", outfile, objs, flags}
dir := p.Dir
out, err := b.runOut(dir, b.cCompilerEnv(), cmdargs...)
if len(out) > 0 {
// Filter out useless linker warnings caused by bugs outside Go.
// See also cmd/link/internal/ld's hostlink method.
var save [][]byte
for _, line := range bytes.SplitAfter(out, []byte("\n")) {
// golang.org/issue/26073 - Apple Xcode bug
if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
continue
}
save = append(save, line)
}
out = bytes.Join(save, nil)
if len(out) > 0 {
b.showOutput(nil, dir, p.ImportPath, b.processOutput(out))
if err != nil {
err = errPrintedOutput
}
}
}
return err
} }
// Grab these before main helpfully overwrites them. // Grab these before main helpfully overwrites them.

View file

@ -1,10 +1,14 @@
env GO111MODULE=on env GO111MODULE=on
cp go.mod go.mod.orig
# Make sure the test builds without replacement.
go build -o a1.exe . go build -o a1.exe .
exec ./a1.exe exec ./a1.exe
stdout 'Don''t communicate by sharing memory' stdout 'Don''t communicate by sharing memory'
# Modules can be replaced by local packages. # Modules can be replaced by local packages.
cp go.mod.orig go.mod
go mod edit -replace=rsc.io/quote/v3=./local/rsc.io/quote/v3 go mod edit -replace=rsc.io/quote/v3=./local/rsc.io/quote/v3
go build -o a2.exe . go build -o a2.exe .
exec ./a2.exe exec ./a2.exe
@ -12,16 +16,26 @@ stdout 'Concurrency is not parallelism.'
# The module path of the replacement doesn't need to match. # The module path of the replacement doesn't need to match.
# (For example, it could be a long-running fork with its own import path.) # (For example, it could be a long-running fork with its own import path.)
cp go.mod.orig go.mod
go mod edit -replace=rsc.io/quote/v3=./local/not-rsc.io/quote/v3 go mod edit -replace=rsc.io/quote/v3=./local/not-rsc.io/quote/v3
go build -o a3.exe . go build -o a3.exe .
exec ./a3.exe exec ./a3.exe
stdout 'Clear is better than clever.' stdout 'Clear is better than clever.'
# However, the same module can't be used as two different paths. # However, the same module can't be used as two different paths.
go mod edit -dropreplace=rsc.io/quote/v3 -replace=not-rsc.io/quote/v3@v3.0.0=rsc.io/quote/v3@v3.0.0 -require=not-rsc.io/quote/v3@v3.0.0 cp go.mod.orig go.mod
go mod edit -replace=not-rsc.io/quote/v3@v3.0.0=rsc.io/quote/v3@v3.0.0 -require=not-rsc.io/quote/v3@v3.0.0
! go build -o a4.exe . ! go build -o a4.exe .
stderr 'rsc.io/quote/v3@v3.0.0 used for two different module paths \(not-rsc.io/quote/v3 and rsc.io/quote/v3\)' stderr 'rsc.io/quote/v3@v3.0.0 used for two different module paths \(not-rsc.io/quote/v3 and rsc.io/quote/v3\)'
# Modules that do not (yet) exist upstream can be replaced too.
cp go.mod.orig go.mod
go mod edit -require not-rsc.io/quote/v3@v3.0.0 -replace=not-rsc.io/quote/v3=./local/rsc.io/quote/v3
go build -o a5.exe ./usenewmodule
! stderr 'finding not-rsc.io/quote/v3'
exec ./a5.exe
stdout 'Concurrency is not parallelism.'
-- go.mod -- -- go.mod --
module quoter module quoter
@ -39,6 +53,18 @@ func main() {
fmt.Println(quote.GoV3()) fmt.Println(quote.GoV3())
} }
-- usenewmodule/main.go --
package main
import (
"fmt"
"not-rsc.io/quote/v3"
)
func main() {
fmt.Println(quote.GoV3())
}
-- local/rsc.io/quote/v3/go.mod -- -- local/rsc.io/quote/v3/go.mod --
module rsc.io/quote/v3 module rsc.io/quote/v3

View file

@ -0,0 +1,71 @@
env GO111MODULE=on
# From inside the module, 'go list -m all' should NOT include transitive
# requirements of modules that have been replaced.
go list -m all
stdout 'rsc.io/quote/v3 v3.0.0'
! stdout 'rsc.io/sampler'
! stdout 'golang.org/x/text'
# From outside the module, 'go list -m all' should include them.
cd outside
go list -m all
stdout 'rsc.io/quote/v3 v3.0.0'
stdout 'rsc.io/sampler v1.3.0'
stdout 'golang.org/x/text'
cd ..
# 'go list all' should add indirect requirements to satisfy the packages
# imported from replacement modules.
! grep 'rsc.io/sampler' go.mod
! grep 'golang.org/x/text' go.mod
go list all
grep 'rsc.io/sampler' go.mod
grep 'golang.org/x/text' go.mod
# 'go get' and 'go mod tidy' should follow the requirements of the replacements,
# not the originals, even if that results in a set of versions that are
# misleading or redundant without those replacements.
go get rsc.io/sampler@v1.2.0
go mod tidy
go list -m all
stdout 'rsc.io/quote/v3 v3.0.0'
stdout 'rsc.io/sampler v1.2.0'
stdout 'golang.org/x/text'
# The requirements seen from outside may be higher (or lower)
# than those seen from within the module.
grep 'rsc.io/sampler v1.2.0' go.mod
cd outside
go list -m all
stdout 'rsc.io/sampler v1.3.0'
-- go.mod --
module example.com/tidy
require rsc.io/quote/v3 v3.0.0
replace rsc.io/quote/v3 => ./not-rsc.io/quote/v3
-- imports.go --
package tidy
import _ "rsc.io/quote/v3"
-- outside/go.mod --
module example.com/tidy/outside
require example.com/tidy v0.0.0
replace example.com/tidy => ./..
-- not-rsc.io/quote/v3/go.mod --
module not-rsc.io/quote/v3
// No requirements specified!
-- not-rsc.io/quote/v3/quote.go --
package quote
import (
_ "rsc.io/sampler"
_ "golang.org/x/text/language"
)

View file

@ -67,6 +67,7 @@ module m
require ( require (
a v1.0.0 a v1.0.0
diamondroot v0.0.0
mysite/myname/mypkg v1.0.0 mysite/myname/mypkg v1.0.0
w v1.0.0 // indirect w v1.0.0 // indirect
x v1.0.0 x v1.0.0
@ -76,6 +77,10 @@ require (
replace ( replace (
a v1.0.0 => ./a a v1.0.0 => ./a
diamondleft => ./diamondleft
diamondpoint => ./diamondpoint
diamondright => ./diamondright
diamondroot => ./diamondroot
mysite/myname/mypkg v1.0.0 => ./mypkg mysite/myname/mypkg v1.0.0 => ./mypkg
w v1.0.0 => ./w w v1.0.0 => ./w
x v1.0.0 => ./x x v1.0.0 => ./x
@ -200,6 +205,10 @@ import _ "z"
package m package m
import _ "x/x1" import _ "x/x1"
-- importdiamond.go --
package m
import _ "diamondroot"
-- w/go.mod -- -- w/go.mod --
module w module w
-- w/w.go -- -- w/w.go --
@ -228,3 +237,42 @@ package y
module z module z
-- z/z.go -- -- z/z.go --
package z package z
-- diamondroot/go.mod --
module diamondroot
require (
diamondleft v0.0.0
diamondright v0.0.0
)
-- diamondroot/x.go --
package diamondroot
import (
_ "diamondleft"
_ "diamondright"
)
-- diamondleft/go.mod --
module diamondleft
require (
diamondpoint v0.0.0
)
-- diamondleft/x.go --
package diamondleft
import _ "diamondpoint"
-- diamondright/go.mod --
module diamondright
require (
diamondpoint v0.0.0
)
-- diamondright/x.go --
package diamondright
import _ "diamondpoint"
-- diamondpoint/go.mod --
module diamondpoint
-- diamondpoint/x.go --
package diamondpoint

View file

@ -0,0 +1,39 @@
env GO111MODULE=on
# Before vendoring, we expect to see the original directory.
go list -f '{{.Version}} {{.Dir}}' -m rsc.io/quote/v3
stdout 'v3.0.0'
stdout '.*[/\\]not-rsc.io[/\\]quote[/\\]v3'
# Since all dependencies are replaced, 'go mod vendor' should not
# have to download anything from the network.
go mod vendor
! stderr 'downloading'
! stderr 'finding'
# After vendoring, we expect to see the replacement in the vendor directory,
# without attempting to look up the non-replaced version.
cmp vendor/rsc.io/quote/v3/quote.go local/not-rsc.io/quote/v3/quote.go
go list -mod=vendor -f '{{.Version}} {{.Dir}}' -m rsc.io/quote/v3
stdout 'v3.0.0'
stdout '.*[/\\]vendor[/\\]rsc.io[/\\]quote[/\\]v3'
! stderr 'finding'
! stderr 'lookup disabled'
-- go.mod --
module example.com/replace
require rsc.io/quote/v3 v3.0.0
replace rsc.io/quote/v3 => ./local/not-rsc.io/quote/v3
-- imports.go --
package replace
import _ "rsc.io/quote/v3"
-- local/not-rsc.io/quote/v3/go.mod --
module not-rsc.io/quote/v3
-- local/not-rsc.io/quote/v3/quote.go --
package quote

View file

@ -179,7 +179,7 @@ type Context interface {
AddBytes(s Sym, b []byte) AddBytes(s Sym, b []byte)
AddAddress(s Sym, t interface{}, ofs int64) AddAddress(s Sym, t interface{}, ofs int64)
AddSectionOffset(s Sym, size int, t interface{}, ofs int64) AddSectionOffset(s Sym, size int, t interface{}, ofs int64)
AddDWARFSectionOffset(s Sym, size int, t interface{}, ofs int64) AddDWARFAddrSectionOffset(s Sym, t interface{}, ofs int64)
CurrentOffset(s Sym) int64 CurrentOffset(s Sym) int64
RecordDclReference(from Sym, to Sym, dclIdx int, inlIndex int) RecordDclReference(from Sym, to Sym, dclIdx int, inlIndex int)
RecordChildDieOffsets(s Sym, vars []*Var, offsets []int32) RecordChildDieOffsets(s Sym, vars []*Var, offsets []int32)
@ -895,7 +895,7 @@ func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, da
case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
if cls == DW_CLS_PTR { // DW_AT_stmt_list and DW_AT_ranges if cls == DW_CLS_PTR { // DW_AT_stmt_list and DW_AT_ranges
ctxt.AddDWARFSectionOffset(s, 4, data, value) ctxt.AddDWARFAddrSectionOffset(s, data, value)
break break
} }
ctxt.AddInt(s, 4, value) ctxt.AddInt(s, 4, value)
@ -932,7 +932,7 @@ func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, da
if data == nil { if data == nil {
return fmt.Errorf("dwarf: null reference in %d", abbrev) return fmt.Errorf("dwarf: null reference in %d", abbrev)
} }
ctxt.AddDWARFSectionOffset(s, 4, data, value) ctxt.AddDWARFAddrSectionOffset(s, data, value)
case DW_FORM_ref1, // reference within the compilation unit case DW_FORM_ref1, // reference within the compilation unit
DW_FORM_ref2, // reference DW_FORM_ref2, // reference

View file

@ -459,7 +459,12 @@ func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
panic("should be used only in the linker") panic("should be used only in the linker")
} }
func (c dwCtxt) AddDWARFSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
size := 4
if isDwarf64(c.Link) {
size = 8
}
ls := s.(*LSym) ls := s.(*LSym)
rsym := t.(*LSym) rsym := t.(*LSym)
ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs) ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
@ -500,6 +505,10 @@ func (c dwCtxt) Logf(format string, args ...interface{}) {
c.Link.Logf(format, args...) c.Link.Logf(format, args...)
} }
func isDwarf64(ctxt *Link) bool {
return ctxt.Headtype == objabi.Haix
}
func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfIsStmtSym *LSym) { func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfIsStmtSym *LSym) {
if s.Type != objabi.STEXT { if s.Type != objabi.STEXT {
ctxt.Diag("dwarfSym of non-TEXT %v", s) ctxt.Diag("dwarfSym of non-TEXT %v", s)

View file

@ -945,6 +945,9 @@ const (
AVUPLHW AVUPLHW
AVUPLF AVUPLF
AVMSLG AVMSLG
AVMSLEG
AVMSLOG
AVMSLEOG
// binary // binary
ABYTE ABYTE

View file

@ -678,6 +678,9 @@ var Anames = []string{
"VUPLHW", "VUPLHW",
"VUPLF", "VUPLF",
"VMSLG", "VMSLG",
"VMSLEG",
"VMSLOG",
"VMSLEOG",
"BYTE", "BYTE",
"WORD", "WORD",
"DWORD", "DWORD",

View file

@ -1379,6 +1379,9 @@ func buildop(ctxt *obj.Link) {
opset(AVSBCBIQ, r) opset(AVSBCBIQ, r)
opset(AVSBIQ, r) opset(AVSBIQ, r)
opset(AVMSLG, r) opset(AVMSLG, r)
opset(AVMSLEG, r)
opset(AVMSLOG, r)
opset(AVMSLEOG, r)
case AVSEL: case AVSEL:
opset(AVFMADB, r) opset(AVFMADB, r)
opset(AWFMADB, r) opset(AWFMADB, r)

View file

@ -45,7 +45,7 @@ func vop(as obj.As) (opcode, es, cs uint32) {
return op_VAC, 0, 0 return op_VAC, 0, 0
case AVACQ: case AVACQ:
return op_VAC, 4, 0 return op_VAC, 4, 0
case AVMSLG: case AVMSLG, AVMSLEG, AVMSLOG, AVMSLEOG:
return op_VMSL, 3, 0 return op_VMSL, 3, 0
case AVACCC: case AVACCC:
return op_VACCC, 0, 0 return op_VACCC, 0, 0
@ -1058,6 +1058,12 @@ func singleElementMask(as obj.As) uint32 {
AWFTCIDB, AWFTCIDB,
AWFIDB: AWFIDB:
return 8 return 8
case AVMSLEG:
return 8
case AVMSLOG:
return 4
case AVMSLEOG:
return 12
} }
return 0 return 0
} }

View file

@ -314,6 +314,18 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
break break
} }
// On AIX, if a relocated symbol is in .data, a second relocation
// must be done by the loader, as the section .data will be moved.
// The "default" symbol address is still needed by the loader so
// the current relocation can't be skipped.
// runtime.algarray is different because it will end up in .rodata section
if ctxt.HeadType == objabi.Haix && r.Sym.Sect.Seg == &Segdata && r.Sym.Name != "runtime.algarray" {
// It's not possible to make a loader relocation to a DWARF section.
// FIXME
if s.Sect.Seg != &Segdwarf {
xcoffaddloaderreloc(ctxt, s, r)
}
}
o = Symaddr(r.Sym) + r.Add o = Symaddr(r.Sym) + r.Add
@ -606,6 +618,7 @@ func dynrelocsym(ctxt *Link, s *sym.Symbol) {
thearch.Adddynrel(ctxt, s, r) thearch.Adddynrel(ctxt, s, r)
continue continue
} }
if r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT || r.Type >= 256 { if r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT || r.Type >= 256 {
if r.Sym != nil && !r.Sym.Attr.Reachable() { if r.Sym != nil && !r.Sym.Attr.Reachable() {
Errorf(s, "dynamic relocation to unreachable symbol %s", r.Sym.Name) Errorf(s, "dynamic relocation to unreachable symbol %s", r.Sym.Name)
@ -1329,6 +1342,14 @@ func (ctxt *Link) dodata() {
gc.AddSym(s) gc.AddSym(s)
datsize += s.Size datsize += s.Size
} }
// On AIX, TOC entries must be the last of .data
for _, s := range data[sym.SXCOFFTOC] {
s.Sect = sect
s.Type = sym.SDATA
datsize = aligndatsize(datsize, s)
s.Value = int64(uint64(datsize) - sect.Vaddr)
datsize += s.Size
}
checkdatsize(ctxt, datsize, sym.SDATA) checkdatsize(ctxt, datsize, sym.SDATA)
sect.Length = uint64(datsize) - sect.Vaddr sect.Length = uint64(datsize) - sect.Vaddr
gc.End(int64(sect.Length)) gc.End(int64(sect.Length))
@ -1688,6 +1709,10 @@ func (ctxt *Link) dodata() {
} }
for _, sect := range Segdata.Sections { for _, sect := range Segdata.Sections {
sect.Extnum = int16(n) sect.Extnum = int16(n)
if ctxt.HeadType == objabi.Haix && (sect.Name == ".noptrdata" || sect.Name == ".bss") {
// On AIX, "noptr" sections are merged with their "ptr" section
continue
}
n++ n++
} }
for _, sect := range Segdwarf.Sections { for _, sect := range Segdwarf.Sections {

View file

@ -67,7 +67,12 @@ func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64
r.Add = ofs r.Add = ofs
} }
func (c dwctxt) AddDWARFSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { func (c dwctxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
size := 4
if isDwarf64(c.linkctxt) {
size = 8
}
c.AddSectionOffset(s, size, t, ofs) c.AddSectionOffset(s, size, t, ofs)
ls := s.(*sym.Symbol) ls := s.(*sym.Symbol)
ls.R[len(ls.R)-1].Type = objabi.R_DWARFSECREF ls.R[len(ls.R)-1].Type = objabi.R_DWARFSECREF
@ -95,6 +100,10 @@ func (c dwctxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []
panic("should be used only in the compiler") panic("should be used only in the compiler")
} }
func isDwarf64(ctxt *Link) bool {
return ctxt.HeadType == objabi.Haix
}
var gdbscript string var gdbscript string
var dwarfp []*sym.Symbol var dwarfp []*sym.Symbol
@ -873,6 +882,33 @@ func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, got
} }
} }
// createUnitLength creates the initial length field with value v and update
// offset of unit_length if needed.
func createUnitLength(ctxt *Link, s *sym.Symbol, v uint64) {
if isDwarf64(ctxt) {
s.AddUint32(ctxt.Arch, 0xFFFFFFFF)
}
addDwarfAddrField(ctxt, s, v)
}
// addDwarfAddrField adds a DWARF field in DWARF 64bits or 32bits.
func addDwarfAddrField(ctxt *Link, s *sym.Symbol, v uint64) {
if isDwarf64(ctxt) {
s.AddUint(ctxt.Arch, v)
} else {
s.AddUint32(ctxt.Arch, uint32(v))
}
}
// addDwarfAddrRef adds a DWARF pointer in DWARF 64bits or 32bits.
func addDwarfAddrRef(ctxt *Link, s *sym.Symbol, t *sym.Symbol) {
if isDwarf64(ctxt) {
adddwarfref(ctxt, s, t, 8)
} else {
adddwarfref(ctxt, s, t, 4)
}
}
// compilationUnit is per-compilation unit (equivalently, per-package) // compilationUnit is per-compilation unit (equivalently, per-package)
// debug-related data. // debug-related data.
type compilationUnit struct { type compilationUnit struct {
@ -1081,11 +1117,11 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
// Write .debug_line Line Number Program Header (sec 6.2.4) // Write .debug_line Line Number Program Header (sec 6.2.4)
// Fields marked with (*) must be changed for 64-bit dwarf // Fields marked with (*) must be changed for 64-bit dwarf
unitLengthOffset := ls.Size unitLengthOffset := ls.Size
ls.AddUint32(ctxt.Arch, 0) // unit_length (*), filled in at end. createUnitLength(ctxt, ls, 0) // unit_length (*), filled in at end
unitstart = ls.Size unitstart = ls.Size
ls.AddUint16(ctxt.Arch, 2) // dwarf version (appendix F) -- version 3 is incompatible w/ XCode 9.0's dsymutil, latest supported on OSX 10.12 as of 2018-05 ls.AddUint16(ctxt.Arch, 2) // dwarf version (appendix F) -- version 3 is incompatible w/ XCode 9.0's dsymutil, latest supported on OSX 10.12 as of 2018-05
headerLengthOffset := ls.Size headerLengthOffset := ls.Size
ls.AddUint32(ctxt.Arch, 0) // header_length (*), filled in at end. addDwarfAddrField(ctxt, ls, 0) // header_length (*), filled in at end
headerstart = ls.Size headerstart = ls.Size
// cpos == unitstart + 4 + 2 + 4 // cpos == unitstart + 4 + 2 + 4
@ -1238,8 +1274,16 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
dwarf.Uleb128put(dwarfctxt, ls, 1) dwarf.Uleb128put(dwarfctxt, ls, 1)
ls.AddUint8(dwarf.DW_LNE_end_sequence) ls.AddUint8(dwarf.DW_LNE_end_sequence)
ls.SetUint32(ctxt.Arch, unitLengthOffset, uint32(ls.Size-unitstart)) if ctxt.HeadType == objabi.Haix {
ls.SetUint32(ctxt.Arch, headerLengthOffset, uint32(headerend-headerstart)) saveDwsectCUSize(".debug_line", unit.lib.String(), uint64(ls.Size-unitLengthOffset))
}
if isDwarf64(ctxt) {
ls.SetUint(ctxt.Arch, unitLengthOffset+4, uint64(ls.Size-unitstart)) // +4 because of 0xFFFFFFFF
ls.SetUint(ctxt.Arch, headerLengthOffset, uint64(headerend-headerstart))
} else {
ls.SetUint32(ctxt.Arch, unitLengthOffset, uint32(ls.Size-unitstart))
ls.SetUint32(ctxt.Arch, headerLengthOffset, uint32(headerend-headerstart))
}
// Apply any R_DWARFFILEREF relocations, since we now know the // Apply any R_DWARFFILEREF relocations, since we now know the
// line table file indices for this compilation unit. Note that // line table file indices for this compilation unit. Note that
@ -1329,8 +1373,8 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
if haslinkregister(ctxt) { if haslinkregister(ctxt) {
cieReserve = 32 cieReserve = 32
} }
fs.AddUint32(ctxt.Arch, cieReserve) // initial length, must be multiple of thearch.ptrsize createUnitLength(ctxt, fs, uint64(cieReserve)) // initial length, must be multiple of thearch.ptrsize
fs.AddUint32(ctxt.Arch, 0xffffffff) // cid. addDwarfAddrField(ctxt, fs, 0xffffffff) // cid.
fs.AddUint8(3) // dwarf version (appendix F) fs.AddUint8(3) // dwarf version (appendix F)
fs.AddUint8(0) // augmentation "" fs.AddUint8(0) // augmentation ""
dwarf.Uleb128put(dwarfctxt, fs, 1) // code_alignment_factor dwarf.Uleb128put(dwarfctxt, fs, 1) // code_alignment_factor
@ -1418,9 +1462,9 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
// ptrsize: address range // ptrsize: address range
fs.AddUint32(ctxt.Arch, uint32(4+2*ctxt.Arch.PtrSize+len(deltaBuf))) // length (excludes itself) fs.AddUint32(ctxt.Arch, uint32(4+2*ctxt.Arch.PtrSize+len(deltaBuf))) // length (excludes itself)
if ctxt.LinkMode == LinkExternal { if ctxt.LinkMode == LinkExternal {
adddwarfref(ctxt, fs, fs, 4) addDwarfAddrRef(ctxt, fs, fs)
} else { } else {
fs.AddUint32(ctxt.Arch, 0) // CIE offset addDwarfAddrField(ctxt, fs, 0) // CIE offset
} }
fs.AddAddr(ctxt.Arch, s) fs.AddAddr(ctxt.Arch, s)
fs.AddUintXX(ctxt.Arch, uint64(s.Size), ctxt.Arch.PtrSize) // address range fs.AddUintXX(ctxt.Arch, uint64(s.Size), ctxt.Arch.PtrSize) // address range
@ -1455,11 +1499,11 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs
// Write .debug_info Compilation Unit Header (sec 7.5.1) // Write .debug_info Compilation Unit Header (sec 7.5.1)
// Fields marked with (*) must be changed for 64-bit dwarf // Fields marked with (*) must be changed for 64-bit dwarf
// This must match COMPUNITHEADERSIZE above. // This must match COMPUNITHEADERSIZE above.
s.AddUint32(ctxt.Arch, 0) // unit_length (*), will be filled in later. createUnitLength(ctxt, s, 0) // unit_length (*), will be filled in later.
s.AddUint16(ctxt.Arch, 4) // dwarf version (appendix F) s.AddUint16(ctxt.Arch, 4) // dwarf version (appendix F)
// debug_abbrev_offset (*) // debug_abbrev_offset (*)
adddwarfref(ctxt, s, abbrevsym, 4) addDwarfAddrRef(ctxt, s, abbrevsym)
s.AddUint8(uint8(ctxt.Arch.PtrSize)) // address_size s.AddUint8(uint8(ctxt.Arch.PtrSize)) // address_size
@ -1477,8 +1521,17 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs
for _, child := range cu { for _, child := range cu {
cusize += child.Size cusize += child.Size
} }
cusize -= 4 // exclude the length field. // Save size for AIX symbol table.
s.SetUint32(ctxt.Arch, 0, uint32(cusize)) if ctxt.HeadType == objabi.Haix {
saveDwsectCUSize(".debug_info", getPkgFromCUSym(s), uint64(cusize))
}
if isDwarf64(ctxt) {
cusize -= 12 // exclude the length field.
s.SetUint(ctxt.Arch, 4, uint64(cusize)) // 4 because of 0XFFFFFFFF
} else {
cusize -= 4 // exclude the length field.
s.SetUint32(ctxt.Arch, 0, uint32(cusize))
}
// Leave a breadcrumb for writepub. This does not // Leave a breadcrumb for writepub. This does not
// appear in the DWARF output. // appear in the DWARF output.
newattr(compunit, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, cusize, 0) newattr(compunit, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, cusize, 0)
@ -1519,10 +1572,10 @@ func writepub(ctxt *Link, sname string, ispub func(*dwarf.DWDie) bool, syms []*s
culength := uint32(getattr(compunit, dwarf.DW_AT_byte_size).Value) + 4 culength := uint32(getattr(compunit, dwarf.DW_AT_byte_size).Value) + 4
// Write .debug_pubnames/types Header (sec 6.1.1) // Write .debug_pubnames/types Header (sec 6.1.1)
s.AddUint32(ctxt.Arch, 0) // unit_length (*), will be filled in later. createUnitLength(ctxt, s, 0) // unit_length (*), will be filled in later.
s.AddUint16(ctxt.Arch, 2) // dwarf version (appendix F) s.AddUint16(ctxt.Arch, 2) // dwarf version (appendix F)
adddwarfref(ctxt, s, dtolsym(compunit.Sym), 4) // debug_info_offset (of the Comp unit Header) addDwarfAddrRef(ctxt, s, dtolsym(compunit.Sym)) // debug_info_offset (of the Comp unit Header)
s.AddUint32(ctxt.Arch, culength) // debug_info_length addDwarfAddrField(ctxt, s, uint64(culength)) // debug_info_length
for die := compunit.Child; die != nil; die = die.Link { for die := compunit.Child; die != nil; die = die.Link {
if !ispub(die) { if !ispub(die) {
@ -1533,19 +1586,31 @@ func writepub(ctxt *Link, sname string, ispub func(*dwarf.DWDie) bool, syms []*s
if die.Sym == nil { if die.Sym == nil {
fmt.Println("Missing sym for ", name) fmt.Println("Missing sym for ", name)
} }
adddwarfref(ctxt, s, dtolsym(die.Sym), 4) addDwarfAddrRef(ctxt, s, dtolsym(die.Sym))
Addstring(s, name) Addstring(s, name)
} }
s.AddUint32(ctxt.Arch, 0) addDwarfAddrField(ctxt, s, 0) // Null offset
s.SetUint32(ctxt.Arch, sectionstart, uint32(s.Size-sectionstart)-4) // exclude the length field. // On AIX, save the current size of this compilation unit.
if ctxt.HeadType == objabi.Haix {
saveDwsectCUSize(sname, getPkgFromCUSym(dtolsym(compunit.Sym)), uint64(s.Size-sectionstart))
}
if isDwarf64(ctxt) {
s.SetUint(ctxt.Arch, sectionstart+4, uint64(s.Size-sectionstart)-12) // exclude the length field.
} else {
s.SetUint32(ctxt.Arch, sectionstart, uint32(s.Size-sectionstart)-4) // exclude the length field.
}
} }
return syms return syms
} }
func writegdbscript(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol { func writegdbscript(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
// TODO (aix): make it available
if ctxt.HeadType == objabi.Haix {
return syms
}
if ctxt.LinkMode == LinkExternal && ctxt.HeadType == objabi.Hwindows && ctxt.BuildMode == BuildModeCArchive { if ctxt.LinkMode == LinkExternal && ctxt.HeadType == objabi.Hwindows && ctxt.BuildMode == BuildModeCArchive {
// gcc on Windows places .debug_gdb_scripts in the wrong location, which // gcc on Windows places .debug_gdb_scripts in the wrong location, which
// causes the program not to run. See https://golang.org/issue/20183 // causes the program not to run. See https://golang.org/issue/20183
@ -2019,3 +2084,27 @@ func (v compilationUnitByStartPC) Less(i, j int) bool {
return v[i].lib.Textp[0].Value < v[j].lib.Textp[0].Value return v[i].lib.Textp[0].Value < v[j].lib.Textp[0].Value
} }
} }
// On AIX, the symbol table needs to know where are the compilation units parts
// for a specific package in each .dw section.
// dwsectCUSize map will save the size of a compilation unit for
// the corresponding .dw section.
// This size can later be retrieved with the index "sectionName.pkgName".
var dwsectCUSize map[string]uint64
// getDwsectCUSize retrieves the corresponding package size inside the current section.
func getDwsectCUSize(sname string, pkgname string) uint64 {
return dwsectCUSize[sname+"."+pkgname]
}
func saveDwsectCUSize(sname string, pkgname string, size uint64) {
dwsectCUSize[sname+"."+pkgname] = size
}
// getPkgFromCUSym returns the package name for the compilation unit
// represented by s.
// The prefix dwarf.InfoPrefix+".pkg." needs to be removed in order to get
// the package name.
func getPkgFromCUSym(s *sym.Symbol) string {
return strings.TrimPrefix(s.Name, dwarf.InfoPrefix+".pkg.")
}

View file

@ -163,6 +163,10 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
} }
havedynamic = 1 havedynamic = 1
} }
if ctxt.HeadType == objabi.Haix {
xcoffadddynimpsym(ctxt, s)
}
continue continue
case "cgo_import_static": case "cgo_import_static":
@ -317,7 +321,8 @@ func fieldtrack(ctxt *Link) {
} }
func (ctxt *Link) addexport() { func (ctxt *Link) addexport() {
if ctxt.HeadType == objabi.Hdarwin { // TODO(aix)
if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix {
return return
} }

View file

@ -39,6 +39,7 @@ import (
"cmd/link/internal/loadelf" "cmd/link/internal/loadelf"
"cmd/link/internal/loadmacho" "cmd/link/internal/loadmacho"
"cmd/link/internal/loadpe" "cmd/link/internal/loadpe"
"cmd/link/internal/loadxcoff"
"cmd/link/internal/objfile" "cmd/link/internal/objfile"
"cmd/link/internal/sym" "cmd/link/internal/sym"
"crypto/sha1" "crypto/sha1"
@ -1338,9 +1339,24 @@ func (ctxt *Link) hostlink() {
ctxt.Logf("\n") ctxt.Logf("\n")
} }
if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil { out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput()
if err != nil {
Exitf("running %s failed: %v\n%s", argv[0], err, out) Exitf("running %s failed: %v\n%s", argv[0], err, out)
} else if len(out) > 0 { }
// Filter out useless linker warnings caused by bugs outside Go.
// See also cmd/go/internal/work/exec.go's gccld method.
var save [][]byte
for _, line := range bytes.SplitAfter(out, []byte("\n")) {
// golang.org/issue/26073 - Apple Xcode bug
if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
continue
}
save = append(save, line)
}
out = bytes.Join(save, nil)
if len(out) > 0 {
// always print external output even if the command is successful, so that we don't // always print external output even if the command is successful, so that we don't
// swallow linker warnings (see https://golang.org/issue/17935). // swallow linker warnings (see https://golang.org/issue/17935).
ctxt.Logf("%s", out) ctxt.Logf("%s", out)
@ -1518,6 +1534,18 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file) return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
} }
if c1 == 0x01 && (c2 == 0xD7 || c2 == 0xF7) {
ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
textp, err := loadxcoff.Load(ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
if err != nil {
Errorf(nil, "%v", err)
return
}
ctxt.Textp = append(ctxt.Textp, textp...)
}
return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
}
/* check the header */ /* check the header */
line, err := f.ReadString('\n') line, err := f.ReadString('\n')
if err != nil { if err != nil {
@ -2244,7 +2272,7 @@ func Entryvalue(ctxt *Link) int64 {
if s.Type == 0 { if s.Type == 0 {
return *FlagTextAddr return *FlagTextAddr
} }
if s.Type != sym.STEXT { if ctxt.HeadType != objabi.Haix && s.Type != sym.STEXT {
Errorf(s, "entry not text") Errorf(s, "entry not text")
} }
return s.Value return s.Value

View file

@ -224,6 +224,10 @@ func Main(arch *sys.Arch, theArch Arch) {
ctxt.dope() ctxt.dope()
ctxt.windynrelocsyms() ctxt.windynrelocsyms()
} }
if ctxt.HeadType == objabi.Haix {
ctxt.doxcoff()
}
ctxt.addexport() ctxt.addexport()
thearch.Gentext(ctxt) // trampolines, call stubs, etc. thearch.Gentext(ctxt) // trampolines, call stubs, etc.
ctxt.textbuildid() ctxt.textbuildid()

View file

@ -66,7 +66,7 @@ func (ctxt *Link) computeTLSOffset() {
default: default:
log.Fatalf("unknown thread-local storage offset for %v", ctxt.HeadType) log.Fatalf("unknown thread-local storage offset for %v", ctxt.HeadType)
case objabi.Hplan9, objabi.Hwindows, objabi.Hjs: case objabi.Hplan9, objabi.Hwindows, objabi.Hjs, objabi.Haix:
break break
/* /*

File diff suppressed because it is too large Load diff

View file

@ -692,6 +692,11 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
// Runtime Handling" of "Power Architecture 64-Bit ELF V2 ABI // Runtime Handling" of "Power Architecture 64-Bit ELF V2 ABI
// Specification". // Specification".
v := r.Sym.Value - 0x7000 v := r.Sym.Value - 0x7000
if ctxt.HeadType == objabi.Haix {
// On AIX, the thread pointer points 0x7800 bytes after
// the TLS.
v -= 0x800
}
if int64(int16(v)) != v { if int64(int16(v)) != v {
ld.Errorf(s, "TLS offset out of range %d", v) ld.Errorf(s, "TLS offset out of range %d", v)
} }
@ -941,6 +946,13 @@ func asmb(ctxt *ld.Link) {
ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff)) ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
loadersize := uint64(0)
if ctxt.HeadType == objabi.Haix && ctxt.BuildMode == ld.BuildModeExe {
loadero := uint64(ld.Rnd(int64(ld.Segdwarf.Fileoff+ld.Segdwarf.Filelen), int64(*ld.FlagRound)))
ctxt.Out.SeekSet(int64(loadero))
loadersize = ld.Loaderblk(ctxt, loadero)
}
/* output symbol table */ /* output symbol table */
ld.Symsize = 0 ld.Symsize = 0
@ -960,6 +972,16 @@ func asmb(ctxt *ld.Link) {
case objabi.Hplan9: case objabi.Hplan9:
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
case objabi.Haix:
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
// Add loader size if needed
if ctxt.BuildMode == ld.BuildModeExe {
symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
symo += uint32(loadersize)
}
symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
} }
ctxt.Out.SeekSet(int64(symo)) ctxt.Out.SeekSet(int64(symo))
@ -988,6 +1010,10 @@ func asmb(ctxt *ld.Link) {
ctxt.Out.Write(sym.P) ctxt.Out.Write(sym.P)
ctxt.Out.Flush() ctxt.Out.Flush()
} }
case objabi.Haix:
ld.Asmaixsym(ctxt)
ctxt.Out.Flush()
} }
} }
@ -1013,6 +1039,9 @@ func asmb(ctxt *ld.Link) {
objabi.Hopenbsd, objabi.Hopenbsd,
objabi.Hnacl: objabi.Hnacl:
ld.Asmbelf(ctxt, int64(symo)) ld.Asmbelf(ctxt, int64(symo))
case objabi.Haix:
ld.Asmbxcoff(ctxt)
} }
ctxt.Out.Flush() ctxt.Out.Flush()

View file

@ -121,6 +121,10 @@ func archinit(ctxt *ld.Link) {
if *ld.FlagRound == -1 { if *ld.FlagRound == -1 {
*ld.FlagRound = 0x10000 *ld.FlagRound = 0x10000
} }
case objabi.Haix:
ld.Xcoffinit(ctxt)
} }
if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 { if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {

View file

@ -116,6 +116,23 @@ func (l *List) remove(e *Element) *Element {
return e return e
} }
// move moves e to next to at and returns e.
func (l *List) move(e, at *Element) *Element {
if e == at {
return e
}
e.prev.next = e.next
e.next.prev = e.prev
n := at.next
at.next = e
e.prev = at
e.next = n
n.prev = e
return e
}
// Remove removes e from l if e is an element of list l. // Remove removes e from l if e is an element of list l.
// It returns the element value e.Value. // It returns the element value e.Value.
// The element must not be nil. // The element must not be nil.
@ -170,7 +187,7 @@ func (l *List) MoveToFront(e *Element) {
return return
} }
// see comment in List.Remove about initialization of l // see comment in List.Remove about initialization of l
l.insert(l.remove(e), &l.root) l.move(e, &l.root)
} }
// MoveToBack moves element e to the back of list l. // MoveToBack moves element e to the back of list l.
@ -181,7 +198,7 @@ func (l *List) MoveToBack(e *Element) {
return return
} }
// see comment in List.Remove about initialization of l // see comment in List.Remove about initialization of l
l.insert(l.remove(e), l.root.prev) l.move(e, l.root.prev)
} }
// MoveBefore moves element e to its new position before mark. // MoveBefore moves element e to its new position before mark.
@ -191,7 +208,7 @@ func (l *List) MoveBefore(e, mark *Element) {
if e.list != l || e == mark || mark.list != l { if e.list != l || e == mark || mark.list != l {
return return
} }
l.insert(l.remove(e), mark.prev) l.move(e, mark.prev)
} }
// MoveAfter moves element e to its new position after mark. // MoveAfter moves element e to its new position after mark.
@ -201,7 +218,7 @@ func (l *List) MoveAfter(e, mark *Element) {
if e.list != l || e == mark || mark.list != l { if e.list != l || e == mark || mark.list != l {
return return
} }
l.insert(l.remove(e), mark) l.move(e, mark)
} }
// PushBackList inserts a copy of an other list at the back of list l. // PushBackList inserts a copy of an other list at the back of list l.

View file

@ -28,6 +28,7 @@ func TestBoringServerProtocolVersion(t *testing.T) {
serverConfig.MinVersion = VersionSSL30 serverConfig.MinVersion = VersionSSL30
clientHello := &clientHelloMsg{ clientHello := &clientHelloMsg{
vers: v, vers: v,
random: make([]byte, 32),
cipherSuites: allCipherSuites(), cipherSuites: allCipherSuites(),
compressionMethods: []uint8{compressionNone}, compressionMethods: []uint8{compressionNone},
} }
@ -110,6 +111,7 @@ func TestBoringServerCipherSuites(t *testing.T) {
t.Run(fmt.Sprintf("suite=%#x", id), func(t *testing.T) { t.Run(fmt.Sprintf("suite=%#x", id), func(t *testing.T) {
clientHello := &clientHelloMsg{ clientHello := &clientHelloMsg{
vers: VersionTLS12, vers: VersionTLS12,
random: make([]byte, 32),
cipherSuites: []uint16{id}, cipherSuites: []uint16{id},
compressionMethods: []uint8{compressionNone}, compressionMethods: []uint8{compressionNone},
supportedCurves: defaultCurvePreferences, supportedCurves: defaultCurvePreferences,
@ -141,6 +143,7 @@ func TestBoringServerCurves(t *testing.T) {
t.Run(fmt.Sprintf("curve=%d", curveid), func(t *testing.T) { t.Run(fmt.Sprintf("curve=%d", curveid), func(t *testing.T) {
clientHello := &clientHelloMsg{ clientHello := &clientHelloMsg{
vers: VersionTLS12, vers: VersionTLS12,
random: make([]byte, 32),
cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
compressionMethods: []uint8{compressionNone}, compressionMethods: []uint8{compressionNone},
supportedCurves: []CurveID{curveid}, supportedCurves: []CurveID{curveid},

View file

@ -478,12 +478,18 @@ type RecordHeaderError struct {
// RecordHeader contains the five bytes of TLS record header that // RecordHeader contains the five bytes of TLS record header that
// triggered the error. // triggered the error.
RecordHeader [5]byte RecordHeader [5]byte
// Conn provides the underlying net.Conn in the case that a client
// sent an initial handshake that didn't look like TLS.
// It is nil if there's already been a handshake or a TLS alert has
// been written to the connection.
Conn net.Conn
} }
func (e RecordHeaderError) Error() string { return "tls: " + e.Msg } func (e RecordHeaderError) Error() string { return "tls: " + e.Msg }
func (c *Conn) newRecordHeaderError(msg string) (err RecordHeaderError) { func (c *Conn) newRecordHeaderError(conn net.Conn, msg string) (err RecordHeaderError) {
err.Msg = msg err.Msg = msg
err.Conn = conn
copy(err.RecordHeader[:], c.rawInput.Bytes()) copy(err.RecordHeader[:], c.rawInput.Bytes())
return err return err
} }
@ -535,7 +541,7 @@ func (c *Conn) readRecord(want recordType) error {
// an SSLv2 client. // an SSLv2 client.
if want == recordTypeHandshake && typ == 0x80 { if want == recordTypeHandshake && typ == 0x80 {
c.sendAlert(alertProtocolVersion) c.sendAlert(alertProtocolVersion)
return c.in.setErrorLocked(c.newRecordHeaderError("unsupported SSLv2 handshake received")) return c.in.setErrorLocked(c.newRecordHeaderError(nil, "unsupported SSLv2 handshake received"))
} }
vers := uint16(hdr[1])<<8 | uint16(hdr[2]) vers := uint16(hdr[1])<<8 | uint16(hdr[2])
@ -543,12 +549,7 @@ func (c *Conn) readRecord(want recordType) error {
if c.haveVers && vers != c.vers { if c.haveVers && vers != c.vers {
c.sendAlert(alertProtocolVersion) c.sendAlert(alertProtocolVersion)
msg := fmt.Sprintf("received record with version %x when expecting version %x", vers, c.vers) msg := fmt.Sprintf("received record with version %x when expecting version %x", vers, c.vers)
return c.in.setErrorLocked(c.newRecordHeaderError(msg)) return c.in.setErrorLocked(c.newRecordHeaderError(nil, msg))
}
if n > maxCiphertext {
c.sendAlert(alertRecordOverflow)
msg := fmt.Sprintf("oversized record received with length %d", n)
return c.in.setErrorLocked(c.newRecordHeaderError(msg))
} }
if !c.haveVers { if !c.haveVers {
// First message, be extra suspicious: this might not be a TLS // First message, be extra suspicious: this might not be a TLS
@ -556,10 +557,14 @@ func (c *Conn) readRecord(want recordType) error {
// The current max version is 3.3 so if the version is >= 16.0, // The current max version is 3.3 so if the version is >= 16.0,
// it's probably not real. // it's probably not real.
if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 { if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 {
c.sendAlert(alertUnexpectedMessage) return c.in.setErrorLocked(c.newRecordHeaderError(c.conn, "first record does not look like a TLS handshake"))
return c.in.setErrorLocked(c.newRecordHeaderError("first record does not look like a TLS handshake"))
} }
} }
if n > maxCiphertext {
c.sendAlert(alertRecordOverflow)
msg := fmt.Sprintf("oversized record received with length %d", n)
return c.in.setErrorLocked(c.newRecordHeaderError(nil, msg))
}
if err := c.readFromUntil(c.conn, recordHeaderLen+n); err != nil { if err := c.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
if e, ok := err.(net.Error); !ok || !e.Temporary() { if e, ok := err.(net.Error); !ok || !e.Temporary() {
c.in.setErrorLocked(err) c.in.setErrorLocked(err)
@ -894,7 +899,7 @@ func (c *Conn) readHandshake() (interface{}, error) {
m = new(certificateMsg) m = new(certificateMsg)
case typeCertificateRequest: case typeCertificateRequest:
m = &certificateRequestMsg{ m = &certificateRequestMsg{
hasSignatureAndHash: c.vers >= VersionTLS12, hasSignatureAlgorithm: c.vers >= VersionTLS12,
} }
case typeCertificateStatus: case typeCertificateStatus:
m = new(certificateStatusMsg) m = new(certificateStatusMsg)
@ -906,7 +911,7 @@ func (c *Conn) readHandshake() (interface{}, error) {
m = new(clientKeyExchangeMsg) m = new(clientKeyExchangeMsg)
case typeCertificateVerify: case typeCertificateVerify:
m = &certificateVerifyMsg{ m = &certificateVerifyMsg{
hasSignatureAndHash: c.vers >= VersionTLS12, hasSignatureAlgorithm: c.vers >= VersionTLS12,
} }
case typeNextProtocol: case typeNextProtocol:
m = new(nextProtoMsg) m = new(nextProtoMsg)

View file

@ -476,7 +476,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
if chainToSend != nil && len(chainToSend.Certificate) > 0 { if chainToSend != nil && len(chainToSend.Certificate) > 0 {
certVerify := &certificateVerifyMsg{ certVerify := &certificateVerifyMsg{
hasSignatureAndHash: c.vers >= VersionTLS12, hasSignatureAlgorithm: c.vers >= VersionTLS12,
} }
key, ok := chainToSend.PrivateKey.(crypto.Signer) key, ok := chainToSend.PrivateKey.(crypto.Signer)
@ -491,7 +491,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
return err return err
} }
// SignatureAndHashAlgorithm was introduced in TLS 1.2. // SignatureAndHashAlgorithm was introduced in TLS 1.2.
if certVerify.hasSignatureAndHash { if certVerify.hasSignatureAlgorithm {
certVerify.signatureAlgorithm = signatureAlgorithm certVerify.signatureAlgorithm = signatureAlgorithm
} }
digest, err := hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret) digest, err := hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret)
@ -744,7 +744,7 @@ func (hs *clientHandshakeState) getCertificate(certReq *certificateRequestMsg) (
if c.config.GetClientCertificate != nil { if c.config.GetClientCertificate != nil {
var signatureSchemes []SignatureScheme var signatureSchemes []SignatureScheme
if !certReq.hasSignatureAndHash { if !certReq.hasSignatureAlgorithm {
// Prior to TLS 1.2, the signature schemes were not // Prior to TLS 1.2, the signature schemes were not
// included in the certificate request message. In this // included in the certificate request message. In this
// case we use a plausible list based on the acceptable // case we use a plausible list based on the acceptable

View file

@ -384,10 +384,12 @@ func (test *clientTest) run(t *testing.T, write bool) {
} }
for i, b := range flows { for i, b := range flows {
if i%2 == 1 { if i%2 == 1 {
serverConn.SetWriteDeadline(time.Now().Add(1 * time.Minute))
serverConn.Write(b) serverConn.Write(b)
continue continue
} }
bb := make([]byte, len(b)) bb := make([]byte, len(b))
serverConn.SetReadDeadline(time.Now().Add(1 * time.Minute))
_, err := io.ReadFull(serverConn, bb) _, err := io.ReadFull(serverConn, bb)
if err != nil { if err != nil {
t.Fatalf("%s #%d: %s", test.name, i, err) t.Fatalf("%s #%d: %s", test.name, i, err)
@ -1644,7 +1646,7 @@ func TestCloseClientConnectionOnIdleServer(t *testing.T) {
serverConn.Read(b[:]) serverConn.Read(b[:])
client.Close() client.Close()
}() }()
client.SetWriteDeadline(time.Now().Add(time.Second)) client.SetWriteDeadline(time.Now().Add(time.Minute))
err := client.Handshake() err := client.Handshake()
if err != nil { if err != nil {
if err, ok := err.(net.Error); ok && err.Timeout() { if err, ok := err.(net.Error); ok && err.Timeout() {

File diff suppressed because it is too large Load diff

View file

@ -20,7 +20,9 @@ var tests = []interface{}{
&certificateMsg{}, &certificateMsg{},
&certificateRequestMsg{}, &certificateRequestMsg{},
&certificateVerifyMsg{}, &certificateVerifyMsg{
hasSignatureAlgorithm: true,
},
&certificateStatusMsg{}, &certificateStatusMsg{},
&clientKeyExchangeMsg{}, &clientKeyExchangeMsg{},
&nextProtoMsg{}, &nextProtoMsg{},
@ -28,12 +30,6 @@ var tests = []interface{}{
&sessionState{}, &sessionState{},
} }
type testMessage interface {
marshal() []byte
unmarshal([]byte) bool
equal(interface{}) bool
}
func TestMarshalUnmarshal(t *testing.T) { func TestMarshalUnmarshal(t *testing.T) {
rand := rand.New(rand.NewSource(0)) rand := rand.New(rand.NewSource(0))
@ -51,16 +47,16 @@ func TestMarshalUnmarshal(t *testing.T) {
break break
} }
m1 := v.Interface().(testMessage) m1 := v.Interface().(handshakeMessage)
marshaled := m1.marshal() marshaled := m1.marshal()
m2 := iface.(testMessage) m2 := iface.(handshakeMessage)
if !m2.unmarshal(marshaled) { if !m2.unmarshal(marshaled) {
t.Errorf("#%d failed to unmarshal %#v %x", i, m1, marshaled) t.Errorf("#%d failed to unmarshal %#v %x", i, m1, marshaled)
break break
} }
m2.marshal() // to fill any marshal cache in the message m2.marshal() // to fill any marshal cache in the message
if !m1.equal(m2) { if !reflect.DeepEqual(m1, m2) {
t.Errorf("#%d got:%#v want:%#v %x", i, m2, m1, marshaled) t.Errorf("#%d got:%#v want:%#v %x", i, m2, m1, marshaled)
break break
} }
@ -85,7 +81,7 @@ func TestMarshalUnmarshal(t *testing.T) {
func TestFuzz(t *testing.T) { func TestFuzz(t *testing.T) {
rand := rand.New(rand.NewSource(0)) rand := rand.New(rand.NewSource(0))
for _, iface := range tests { for _, iface := range tests {
m := iface.(testMessage) m := iface.(handshakeMessage)
for j := 0; j < 1000; j++ { for j := 0; j < 1000; j++ {
len := rand.Intn(100) len := rand.Intn(100)
@ -142,18 +138,23 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
m.ticketSupported = true m.ticketSupported = true
if rand.Intn(10) > 5 { if rand.Intn(10) > 5 {
m.sessionTicket = randomBytes(rand.Intn(300), rand) m.sessionTicket = randomBytes(rand.Intn(300), rand)
} else {
m.sessionTicket = make([]byte, 0)
} }
} }
if rand.Intn(10) > 5 { if rand.Intn(10) > 5 {
m.supportedSignatureAlgorithms = supportedSignatureAlgorithms() m.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
} }
m.alpnProtocols = make([]string, rand.Intn(5)) for i := 0; i < rand.Intn(5); i++ {
for i := range m.alpnProtocols { m.alpnProtocols = append(m.alpnProtocols, randomString(rand.Intn(20)+1, rand))
m.alpnProtocols[i] = randomString(rand.Intn(20)+1, rand)
} }
if rand.Intn(10) > 5 { if rand.Intn(10) > 5 {
m.scts = true m.scts = true
} }
if rand.Intn(10) > 5 {
m.secureRenegotiationSupported = true
m.secureRenegotiation = randomBytes(rand.Intn(50)+1, rand)
}
return reflect.ValueOf(m) return reflect.ValueOf(m)
} }
@ -168,11 +169,8 @@ func (*serverHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
if rand.Intn(10) > 5 { if rand.Intn(10) > 5 {
m.nextProtoNeg = true m.nextProtoNeg = true
for i := 0; i < rand.Intn(10); i++ {
n := rand.Intn(10) m.nextProtos = append(m.nextProtos, randomString(20, rand))
m.nextProtos = make([]string, n)
for i := 0; i < n; i++ {
m.nextProtos[i] = randomString(20, rand)
} }
} }
@ -184,12 +182,13 @@ func (*serverHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
} }
m.alpnProtocol = randomString(rand.Intn(32)+1, rand) m.alpnProtocol = randomString(rand.Intn(32)+1, rand)
for i := 0; i < rand.Intn(4); i++ {
m.scts = append(m.scts, randomBytes(rand.Intn(500)+1, rand))
}
if rand.Intn(10) > 5 { if rand.Intn(10) > 5 {
numSCTs := rand.Intn(4) m.secureRenegotiationSupported = true
m.scts = make([][]byte, numSCTs) m.secureRenegotiation = randomBytes(rand.Intn(50)+1, rand)
for i := range m.scts {
m.scts[i] = randomBytes(rand.Intn(500)+1, rand)
}
} }
return reflect.ValueOf(m) return reflect.ValueOf(m)
@ -208,16 +207,16 @@ func (*certificateMsg) Generate(rand *rand.Rand, size int) reflect.Value {
func (*certificateRequestMsg) Generate(rand *rand.Rand, size int) reflect.Value { func (*certificateRequestMsg) Generate(rand *rand.Rand, size int) reflect.Value {
m := &certificateRequestMsg{} m := &certificateRequestMsg{}
m.certificateTypes = randomBytes(rand.Intn(5)+1, rand) m.certificateTypes = randomBytes(rand.Intn(5)+1, rand)
numCAs := rand.Intn(100) for i := 0; i < rand.Intn(100); i++ {
m.certificateAuthorities = make([][]byte, numCAs) m.certificateAuthorities = append(m.certificateAuthorities, randomBytes(rand.Intn(15)+1, rand))
for i := 0; i < numCAs; i++ {
m.certificateAuthorities[i] = randomBytes(rand.Intn(15)+1, rand)
} }
return reflect.ValueOf(m) return reflect.ValueOf(m)
} }
func (*certificateVerifyMsg) Generate(rand *rand.Rand, size int) reflect.Value { func (*certificateVerifyMsg) Generate(rand *rand.Rand, size int) reflect.Value {
m := &certificateVerifyMsg{} m := &certificateVerifyMsg{}
m.hasSignatureAlgorithm = true
m.signatureAlgorithm = SignatureScheme(rand.Intn(30000))
m.signature = randomBytes(rand.Intn(15)+1, rand) m.signature = randomBytes(rand.Intn(15)+1, rand)
return reflect.ValueOf(m) return reflect.ValueOf(m)
} }

View file

@ -418,7 +418,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
byte(certTypeECDSASign), byte(certTypeECDSASign),
} }
if c.vers >= VersionTLS12 { if c.vers >= VersionTLS12 {
certReq.hasSignatureAndHash = true certReq.hasSignatureAlgorithm = true
certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms() certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
} }

View file

@ -101,13 +101,17 @@ var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x020
func TestRejectBadProtocolVersion(t *testing.T) { func TestRejectBadProtocolVersion(t *testing.T) {
for _, v := range badProtocolVersions { for _, v := range badProtocolVersions {
testClientHelloFailure(t, testConfig, &clientHelloMsg{vers: v}, "unsupported, maximum protocol version") testClientHelloFailure(t, testConfig, &clientHelloMsg{
vers: v,
random: make([]byte, 32),
}, "unsupported, maximum protocol version")
} }
} }
func TestNoSuiteOverlap(t *testing.T) { func TestNoSuiteOverlap(t *testing.T) {
clientHello := &clientHelloMsg{ clientHello := &clientHelloMsg{
vers: VersionTLS10, vers: VersionTLS10,
random: make([]byte, 32),
cipherSuites: []uint16{0xff00}, cipherSuites: []uint16{0xff00},
compressionMethods: []uint8{compressionNone}, compressionMethods: []uint8{compressionNone},
} }
@ -117,6 +121,7 @@ func TestNoSuiteOverlap(t *testing.T) {
func TestNoCompressionOverlap(t *testing.T) { func TestNoCompressionOverlap(t *testing.T) {
clientHello := &clientHelloMsg{ clientHello := &clientHelloMsg{
vers: VersionTLS10, vers: VersionTLS10,
random: make([]byte, 32),
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
compressionMethods: []uint8{0xff}, compressionMethods: []uint8{0xff},
} }
@ -126,6 +131,7 @@ func TestNoCompressionOverlap(t *testing.T) {
func TestNoRC4ByDefault(t *testing.T) { func TestNoRC4ByDefault(t *testing.T) {
clientHello := &clientHelloMsg{ clientHello := &clientHelloMsg{
vers: VersionTLS10, vers: VersionTLS10,
random: make([]byte, 32),
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
compressionMethods: []uint8{compressionNone}, compressionMethods: []uint8{compressionNone},
} }
@ -137,7 +143,11 @@ func TestNoRC4ByDefault(t *testing.T) {
} }
func TestRejectSNIWithTrailingDot(t *testing.T) { func TestRejectSNIWithTrailingDot(t *testing.T) {
testClientHelloFailure(t, testConfig, &clientHelloMsg{vers: VersionTLS12, serverName: "foo.com."}, "unexpected message") testClientHelloFailure(t, testConfig, &clientHelloMsg{
vers: VersionTLS12,
random: make([]byte, 32),
serverName: "foo.com.",
}, "unexpected message")
} }
func TestDontSelectECDSAWithRSAKey(t *testing.T) { func TestDontSelectECDSAWithRSAKey(t *testing.T) {
@ -145,6 +155,7 @@ func TestDontSelectECDSAWithRSAKey(t *testing.T) {
// won't be selected if the server's private key doesn't support it. // won't be selected if the server's private key doesn't support it.
clientHello := &clientHelloMsg{ clientHello := &clientHelloMsg{
vers: VersionTLS10, vers: VersionTLS10,
random: make([]byte, 32),
cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}, cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
compressionMethods: []uint8{compressionNone}, compressionMethods: []uint8{compressionNone},
supportedCurves: []CurveID{CurveP256}, supportedCurves: []CurveID{CurveP256},
@ -170,6 +181,7 @@ func TestDontSelectRSAWithECDSAKey(t *testing.T) {
// won't be selected if the server's private key doesn't support it. // won't be selected if the server's private key doesn't support it.
clientHello := &clientHelloMsg{ clientHello := &clientHelloMsg{
vers: VersionTLS10, vers: VersionTLS10,
random: make([]byte, 32),
cipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, cipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
compressionMethods: []uint8{compressionNone}, compressionMethods: []uint8{compressionNone},
supportedCurves: []CurveID{CurveP256}, supportedCurves: []CurveID{CurveP256},
@ -242,11 +254,9 @@ func TestRenegotiationExtension(t *testing.T) {
func TestTLS12OnlyCipherSuites(t *testing.T) { func TestTLS12OnlyCipherSuites(t *testing.T) {
// Test that a Server doesn't select a TLS 1.2-only cipher suite when // Test that a Server doesn't select a TLS 1.2-only cipher suite when
// the client negotiates TLS 1.1. // the client negotiates TLS 1.1.
var zeros [32]byte
clientHello := &clientHelloMsg{ clientHello := &clientHelloMsg{
vers: VersionTLS11, vers: VersionTLS11,
random: zeros[:], random: make([]byte, 32),
cipherSuites: []uint16{ cipherSuites: []uint16{
// The Server, by default, will use the client's // The Server, by default, will use the client's
// preference order. So the GCM cipher suite // preference order. So the GCM cipher suite
@ -615,10 +625,12 @@ func (test *serverTest) run(t *testing.T, write bool) {
} }
for i, b := range flows { for i, b := range flows {
if i%2 == 0 { if i%2 == 0 {
clientConn.SetWriteDeadline(time.Now().Add(1 * time.Minute))
clientConn.Write(b) clientConn.Write(b)
continue continue
} }
bb := make([]byte, len(b)) bb := make([]byte, len(b))
clientConn.SetReadDeadline(time.Now().Add(1 * time.Minute))
n, err := io.ReadFull(clientConn, bb) n, err := io.ReadFull(clientConn, bb)
if err != nil { if err != nil {
t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", test.name, i+1, err, n, len(bb), bb[:n], b) t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", test.name, i+1, err, n, len(bb), bb[:n], b)
@ -876,6 +888,7 @@ func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
clientHello := &clientHelloMsg{ clientHello := &clientHelloMsg{
vers: VersionTLS10, vers: VersionTLS10,
random: make([]byte, 32),
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
compressionMethods: []uint8{compressionNone}, compressionMethods: []uint8{compressionNone},
serverName: "test", serverName: "test",
@ -896,6 +909,7 @@ func TestHandshakeServerEmptyCertificates(t *testing.T) {
clientHello := &clientHelloMsg{ clientHello := &clientHelloMsg{
vers: VersionTLS10, vers: VersionTLS10,
random: make([]byte, 32),
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
compressionMethods: []uint8{compressionNone}, compressionMethods: []uint8{compressionNone},
} }
@ -907,6 +921,7 @@ func TestHandshakeServerEmptyCertificates(t *testing.T) {
clientHello = &clientHelloMsg{ clientHello = &clientHelloMsg{
vers: VersionTLS10, vers: VersionTLS10,
random: make([]byte, 32),
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
compressionMethods: []uint8{compressionNone}, compressionMethods: []uint8{compressionNone},
} }
@ -1210,6 +1225,7 @@ func TestSNIGivenOnFailure(t *testing.T) {
clientHello := &clientHelloMsg{ clientHello := &clientHelloMsg{
vers: VersionTLS10, vers: VersionTLS10,
random: make([]byte, 32),
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
compressionMethods: []uint8{compressionNone}, compressionMethods: []uint8{compressionNone},
serverName: expectedServerName, serverName: expectedServerName,
@ -1432,7 +1448,7 @@ func TestCloseServerConnectionOnIdleClient(t *testing.T) {
clientConn.Write([]byte{'0'}) clientConn.Write([]byte{'0'})
server.Close() server.Close()
}() }()
server.SetReadDeadline(time.Now().Add(time.Second)) server.SetReadDeadline(time.Now().Add(time.Minute))
err := server.Handshake() err := server.Handshake()
if err != nil { if err != nil {
if err, ok := err.(net.Error); ok && err.Timeout() { if err, ok := err.(net.Error); ok && err.Timeout() {

View file

@ -27,31 +27,6 @@ type sessionState struct {
usedOldKey bool usedOldKey bool
} }
func (s *sessionState) equal(i interface{}) bool {
s1, ok := i.(*sessionState)
if !ok {
return false
}
if s.vers != s1.vers ||
s.cipherSuite != s1.cipherSuite ||
!bytes.Equal(s.masterSecret, s1.masterSecret) {
return false
}
if len(s.certificates) != len(s1.certificates) {
return false
}
for i := range s.certificates {
if !bytes.Equal(s.certificates[i], s1.certificates[i]) {
return false
}
}
return true
}
func (s *sessionState) marshal() []byte { func (s *sessionState) marshal() []byte {
length := 2 + 2 + 2 + len(s.masterSecret) + 2 length := 2 + 2 + 2 + len(s.masterSecret) + 2
for _, cert := range s.certificates { for _, cert := range s.certificates {

View file

@ -2605,6 +2605,15 @@ type Rows struct {
lastcols []driver.Value lastcols []driver.Value
} }
// lasterrOrErrLocked returns either lasterr or the provided err.
// rs.closemu must be read-locked.
func (rs *Rows) lasterrOrErrLocked(err error) error {
if rs.lasterr != nil && rs.lasterr != io.EOF {
return rs.lasterr
}
return err
}
func (rs *Rows) initContextClose(ctx, txctx context.Context) { func (rs *Rows) initContextClose(ctx, txctx context.Context) {
if ctx.Done() == nil && (txctx == nil || txctx.Done() == nil) { if ctx.Done() == nil && (txctx == nil || txctx.Done() == nil) {
return return
@ -2728,22 +2737,22 @@ func (rs *Rows) NextResultSet() bool {
func (rs *Rows) Err() error { func (rs *Rows) Err() error {
rs.closemu.RLock() rs.closemu.RLock()
defer rs.closemu.RUnlock() defer rs.closemu.RUnlock()
if rs.lasterr == io.EOF { return rs.lasterrOrErrLocked(nil)
return nil
}
return rs.lasterr
} }
var errRowsClosed = errors.New("sql: Rows are closed")
var errNoRows = errors.New("sql: no Rows available")
// Columns returns the column names. // Columns returns the column names.
// Columns returns an error if the rows are closed. // Columns returns an error if the rows are closed.
func (rs *Rows) Columns() ([]string, error) { func (rs *Rows) Columns() ([]string, error) {
rs.closemu.RLock() rs.closemu.RLock()
defer rs.closemu.RUnlock() defer rs.closemu.RUnlock()
if rs.closed { if rs.closed {
return nil, errors.New("sql: Rows are closed") return nil, rs.lasterrOrErrLocked(errRowsClosed)
} }
if rs.rowsi == nil { if rs.rowsi == nil {
return nil, errors.New("sql: no Rows available") return nil, rs.lasterrOrErrLocked(errNoRows)
} }
rs.dc.Lock() rs.dc.Lock()
defer rs.dc.Unlock() defer rs.dc.Unlock()
@ -2757,10 +2766,10 @@ func (rs *Rows) ColumnTypes() ([]*ColumnType, error) {
rs.closemu.RLock() rs.closemu.RLock()
defer rs.closemu.RUnlock() defer rs.closemu.RUnlock()
if rs.closed { if rs.closed {
return nil, errors.New("sql: Rows are closed") return nil, rs.lasterrOrErrLocked(errRowsClosed)
} }
if rs.rowsi == nil { if rs.rowsi == nil {
return nil, errors.New("sql: no Rows available") return nil, rs.lasterrOrErrLocked(errNoRows)
} }
rs.dc.Lock() rs.dc.Lock()
defer rs.dc.Unlock() defer rs.dc.Unlock()
@ -2916,8 +2925,9 @@ func (rs *Rows) Scan(dest ...interface{}) error {
return rs.lasterr return rs.lasterr
} }
if rs.closed { if rs.closed {
err := rs.lasterrOrErrLocked(errRowsClosed)
rs.closemu.RUnlock() rs.closemu.RUnlock()
return errors.New("sql: Rows are closed") return err
} }
rs.closemu.RUnlock() rs.closemu.RUnlock()

View file

@ -292,3 +292,12 @@ func ExampleMarshalIndent() {
// <prefix><indent>"b": 2 // <prefix><indent>"b": 2
// <prefix>} // <prefix>}
} }
func ExampleValid() {
goodJSON := `{"example": 1}`
badJSON := `{"example":2:]}}`
fmt.Println(json.Valid([]byte(goodJSON)), json.Valid([]byte(badJSON)))
// Output:
// true false
}

View file

@ -166,6 +166,7 @@ var pkgDeps = map[string][]string{
// Other time dependencies: // Other time dependencies:
"internal/syscall/windows/registry", "internal/syscall/windows/registry",
"syscall", "syscall",
"syscall/js",
}, },
"internal/poll": {"L0", "internal/race", "syscall", "time", "unicode/utf16", "unicode/utf8", "internal/syscall/windows"}, "internal/poll": {"L0", "internal/race", "syscall", "time", "unicode/utf16", "unicode/utf8", "internal/syscall/windows"},
@ -395,7 +396,7 @@ var pkgDeps = map[string][]string{
// SSL/TLS. // SSL/TLS.
"crypto/tls": { "crypto/tls": {
"L4", "CRYPTO-MATH", "OS", "L4", "CRYPTO-MATH", "OS", "golang_org/x/crypto/cryptobyte",
"container/list", "crypto/x509", "encoding/pem", "net", "syscall", "container/list", "crypto/x509", "encoding/pem", "net", "syscall",
}, },
"crypto/x509": { "crypto/x509": {

View file

@ -461,7 +461,11 @@ func (check *Checker) updateExprType(x ast.Expr, typ Type, final bool) {
check.invalidOp(x.Pos(), "shifted operand %s (type %s) must be integer", x, typ) check.invalidOp(x.Pos(), "shifted operand %s (type %s) must be integer", x, typ)
return return
} }
} else if old.val != nil { // Even if we have an integer, if the value is a constant we
// still must check that it is representable as the specific
// int type requested (was issue #22969). Fall through here.
}
if old.val != nil {
// If x is a constant, it must be representable as a value of typ. // If x is a constant, it must be representable as a value of typ.
c := operand{old.mode, x, old.typ, old.val, 0} c := operand{old.mode, x, old.typ, old.val, 0}
check.convertUntyped(&c, typ) check.convertUntyped(&c, typ)

View file

@ -46,8 +46,11 @@ func TestStdlib(t *testing.T) {
} }
} }
// firstComment returns the contents of the first comment in // firstComment returns the contents of the first non-empty comment in
// the given file, assuming there's one within the first KB. // the given file, "skip", or the empty string. No matter the present
// comments, if any of them contains a build tag, the result is always
// "skip". Only comments before the "package" token and within the first
// 4K of the file are considered.
func firstComment(filename string) string { func firstComment(filename string) string {
f, err := os.Open(filename) f, err := os.Open(filename)
if err != nil { if err != nil {
@ -55,11 +58,12 @@ func firstComment(filename string) string {
} }
defer f.Close() defer f.Close()
var src [1 << 10]byte // read at most 1KB var src [4 << 10]byte // read at most 4KB
n, _ := f.Read(src[:]) n, _ := f.Read(src[:])
var first string
var s scanner.Scanner var s scanner.Scanner
s.Init(fset.AddFile("", fset.Base(), n), src[:n], nil, scanner.ScanComments) s.Init(fset.AddFile("", fset.Base(), n), src[:n], nil /* ignore errors */, scanner.ScanComments)
for { for {
_, tok, lit := s.Scan() _, tok, lit := s.Scan()
switch tok { switch tok {
@ -68,9 +72,17 @@ func firstComment(filename string) string {
if lit[1] == '*' { if lit[1] == '*' {
lit = lit[:len(lit)-2] lit = lit[:len(lit)-2]
} }
return strings.TrimSpace(lit[2:]) contents := strings.TrimSpace(lit[2:])
case token.EOF: if strings.HasPrefix(contents, "+build ") {
return "" return "skip"
}
if first == "" {
first = contents // contents may be "" but that's ok
}
// continue as we may still see build tags
case token.PACKAGE, token.EOF:
return first
} }
} }
} }
@ -142,15 +154,8 @@ func TestStdTest(t *testing.T) {
t.Skip("skipping in short mode") t.Skip("skipping in short mode")
} }
// test/recover4.go is only built for Linux and Darwin.
// TODO(gri) Remove once tests consider +build tags (issue 10370).
if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
return
}
testTestDir(t, filepath.Join(runtime.GOROOT(), "test"), testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
"cmplxdivide.go", // also needs file cmplxdivide1.go - ignore "cmplxdivide.go", // also needs file cmplxdivide1.go - ignore
"sigchld.go", // don't work on Windows; testTestDir should consult build tags
) )
} }
@ -166,7 +171,6 @@ func TestStdFixed(t *testing.T) {
"issue6889.go", // gc-specific test "issue6889.go", // gc-specific test
"issue7746.go", // large constants - consumes too much memory "issue7746.go", // large constants - consumes too much memory
"issue11362.go", // canonical import path check "issue11362.go", // canonical import path check
"issue15002.go", // uses Mmap; testTestDir should consult build tags
"issue16369.go", // go/types handles this correctly - not an issue "issue16369.go", // go/types handles this correctly - not an issue
"issue18459.go", // go/types doesn't check validity of //go:xxx directives "issue18459.go", // go/types doesn't check validity of //go:xxx directives
"issue18882.go", // go/types doesn't check validity of //go:xxx directives "issue18882.go", // go/types doesn't check validity of //go:xxx directives

View file

@ -354,3 +354,15 @@ func issue21727() {
var _ = string(1 << s) var _ = string(1 << s)
var _ = string(1.0 /* ERROR "cannot convert" */ << s) var _ = string(1.0 /* ERROR "cannot convert" */ << s)
} }
func issue22969() {
var s uint
var a []byte
_ = a[0xffffffffffffffff /* ERROR "overflows int" */ <<s] // example from issue 22969
_ = make([]int, 0xffffffffffffffff /* ERROR "overflows int" */ << s)
_ = make([]int, 0, 0xffffffffffffffff /* ERROR "overflows int" */ << s)
var _ byte = 0x100 /* ERROR "overflows byte" */ << s
var _ int8 = 0xff /* ERROR "overflows int8" */ << s
var _ int16 = 0xffff /* ERROR "overflows int16" */ << s
var _ int32 = 0x80000000 /* ERROR "overflows int32" */ << s
}

View file

@ -62,15 +62,13 @@ func TestGolden(t *testing.T) {
io.WriteString(c, g.in) io.WriteString(c, g.in)
s := c.Sum64() s := c.Sum64()
if s != g.outISO { if s != g.outISO {
t.Errorf("ISO crc64(%s) = 0x%x want 0x%x", g.in, s, g.outISO) t.Fatalf("ISO crc64(%s) = 0x%x want 0x%x", g.in, s, g.outISO)
t.FailNow()
} }
c = New(tabECMA) c = New(tabECMA)
io.WriteString(c, g.in) io.WriteString(c, g.in)
s = c.Sum64() s = c.Sum64()
if s != g.outECMA { if s != g.outECMA {
t.Errorf("ECMA crc64(%s) = 0x%x want 0x%x", g.in, s, g.outECMA) t.Fatalf("ECMA crc64(%s) = 0x%x want 0x%x", g.in, s, g.outECMA)
t.FailNow()
} }
} }
} }

View file

@ -1,26 +0,0 @@
// Copyright 2018 The Go 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 cpu_test
import (
. "internal/cpu"
"runtime"
"testing"
)
func TestARM64minimalFeatures(t *testing.T) {
switch runtime.GOOS {
case "linux", "android":
default:
t.Skipf("%s/arm64 is not supported", runtime.GOOS)
}
if !ARM64.HasASIMD {
t.Fatalf("HasASIMD expected true, got false")
}
if !ARM64.HasFP {
t.Fatalf("HasFP expected true, got false")
}
}

View file

@ -40,6 +40,7 @@ func doinit() {
{Name: "scv", Feature: &PPC64.HasSCV}, {Name: "scv", Feature: &PPC64.HasSCV},
// These capabilities should always be enabled on ppc64 and ppc64le: // These capabilities should always be enabled on ppc64 and ppc64le:
{Name: "power8", Feature: &PPC64.IsPOWER8, Required: true},
{Name: "vmx", Feature: &PPC64.HasVMX, Required: true}, {Name: "vmx", Feature: &PPC64.HasVMX, Required: true},
{Name: "dfp", Feature: &PPC64.HasDFP, Required: true}, {Name: "dfp", Feature: &PPC64.HasDFP, Required: true},
{Name: "vsx", Feature: &PPC64.HasVSX, Required: true}, {Name: "vsx", Feature: &PPC64.HasVSX, Required: true},

View file

@ -1,33 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ppc64 ppc64le
package cpu_test
import (
. "internal/cpu"
"testing"
)
func TestPPC64minimalFeatures(t *testing.T) {
if !PPC64.IsPOWER8 {
t.Fatalf("IsPOWER8 expected true, got false")
}
if !PPC64.HasVMX {
t.Fatalf("HasVMX expected true, got false")
}
if !PPC64.HasDFP {
t.Fatalf("HasDFP expected true, got false")
}
if !PPC64.HasVSX {
t.Fatalf("HasVSX expected true, got false")
}
if !PPC64.HasISEL {
t.Fatalf("HasISEL expected true, got false")
}
if !PPC64.HasVCRYPTO {
t.Fatalf("HasVCRYPTO expected true, got false")
}
}

View file

@ -9,10 +9,27 @@ import (
"internal/testenv" "internal/testenv"
"os" "os"
"os/exec" "os/exec"
"runtime"
"strings" "strings"
"testing" "testing"
) )
func TestMinimalFeatures(t *testing.T) {
if runtime.GOARCH == "arm64" {
switch runtime.GOOS {
case "linux", "android":
default:
t.Skipf("%s/%s is not supported", runtime.GOOS, runtime.GOARCH)
}
}
for _, o := range Options {
if o.Required && !*o.Feature {
t.Errorf("%v expected true, got false", o.Name)
}
}
}
func MustHaveDebugOptionsSupport(t *testing.T) { func MustHaveDebugOptionsSupport(t *testing.T) {
if !DebugOptions { if !DebugOptions {
t.Skipf("skipping test: cpu feature options not supported by OS") t.Skipf("skipping test: cpu feature options not supported by OS")

View file

@ -13,16 +13,6 @@ import (
"testing" "testing"
) )
func TestAMD64minimalFeatures(t *testing.T) {
if runtime.GOARCH != "amd64" {
return
}
if !X86.HasSSE2 {
t.Fatalf("HasSSE2 expected true, got false")
}
}
func TestX86ifAVX2hasAVX(t *testing.T) { func TestX86ifAVX2hasAVX(t *testing.T) {
if X86.HasAVX2 && !X86.HasAVX { if X86.HasAVX2 && !X86.HasAVX {
t.Fatalf("HasAVX expected true when HasAVX2 is true, got false") t.Fatalf("HasAVX expected true when HasAVX2 is true, got false")

View file

@ -28,9 +28,6 @@ const (
// GetRandom calls the FreeBSD getrandom system call. // GetRandom calls the FreeBSD getrandom system call.
func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) {
if randomTrap == 0 {
return 0, syscall.ENOSYS
}
if len(p) == 0 { if len(p) == 0 {
return 0, nil return 0, nil
} }

View file

@ -26,9 +26,6 @@ const (
// GetRandom calls the Linux getrandom system call. // GetRandom calls the Linux getrandom system call.
// See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c6e9d6f38894798696f23c8084ca7edbf16ee895 // See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c6e9d6f38894798696f23c8084ca7edbf16ee895
func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) {
if randomTrap == 0 {
return 0, syscall.ENOSYS
}
if len(p) == 0 { if len(p) == 0 {
return 0, nil return 0, nil
} }

View file

@ -8,6 +8,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"strings" "strings"
"testing" "testing"
) )
@ -27,6 +28,9 @@ var (
) )
func TestRemoteFiles(t *testing.T) { func TestRemoteFiles(t *testing.T) {
if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
t.Skipf("files from outside the package are not available on %s/%s", runtime.GOOS, runtime.GOARCH)
}
files, err := ioutil.ReadDir(otherDir) files, err := ioutil.ReadDir(otherDir)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View file

@ -254,6 +254,13 @@ func (l *Logger) SetPrefix(prefix string) {
l.prefix = prefix l.prefix = prefix
} }
// Writer returns the output destination for the logger.
func (l *Logger) Writer() io.Writer {
l.mu.Lock()
defer l.mu.Unlock()
return l.out
}
// SetOutput sets the output destination for the standard logger. // SetOutput sets the output destination for the standard logger.
func SetOutput(w io.Writer) { func SetOutput(w io.Writer) {
std.mu.Lock() std.mu.Lock()

View file

@ -82,7 +82,7 @@ func nlz(x Word) uint {
return uint(bits.LeadingZeros(uint(x))) return uint(bits.LeadingZeros(uint(x)))
} }
// q = (u1<<_W + u0 - r)/y // q = (u1<<_W + u0 - r)/v
// Adapted from Warren, Hacker's Delight, p. 152. // Adapted from Warren, Hacker's Delight, p. 152.
func divWW_g(u1, u0, v Word) (q, r Word) { func divWW_g(u1, u0, v Word) (q, r Word) {
if u1 >= v { if u1 >= v {

View file

@ -899,6 +899,21 @@ func BenchmarkAdd64(b *testing.B) {
Output = int(z + c) Output = int(z + c)
} }
func BenchmarkAdd64multiple(b *testing.B) {
var z0 = uint64(Input)
var z1 = uint64(Input)
var z2 = uint64(Input)
var z3 = uint64(Input)
for i := 0; i < b.N; i++ {
var c uint64
z0, c = Add64(z0, uint64(i), c)
z1, c = Add64(z1, uint64(i), c)
z2, c = Add64(z2, uint64(i), c)
z3, _ = Add64(z3, uint64(i), c)
}
Output = int(z0 + z1 + z2 + z3)
}
func BenchmarkSub(b *testing.B) { func BenchmarkSub(b *testing.B) {
var z, c uint var z, c uint
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@ -918,11 +933,26 @@ func BenchmarkSub32(b *testing.B) {
func BenchmarkSub64(b *testing.B) { func BenchmarkSub64(b *testing.B) {
var z, c uint64 var z, c uint64
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
z, c = Add64(uint64(Input), uint64(i), c) z, c = Sub64(uint64(Input), uint64(i), c)
} }
Output = int(z + c) Output = int(z + c)
} }
func BenchmarkSub64multiple(b *testing.B) {
var z0 = uint64(Input)
var z1 = uint64(Input)
var z2 = uint64(Input)
var z3 = uint64(Input)
for i := 0; i < b.N; i++ {
var c uint64
z0, c = Sub64(z0, uint64(i), c)
z1, c = Sub64(z1, uint64(i), c)
z2, c = Sub64(z2, uint64(i), c)
z3, _ = Sub64(z3, uint64(i), c)
}
Output = int(z0 + z1 + z2 + z3)
}
func BenchmarkMul(b *testing.B) { func BenchmarkMul(b *testing.B) {
var hi, lo uint var hi, lo uint
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {

View file

@ -24,7 +24,7 @@ func cgoLookupPort(ctx context.Context, network, service string) (port int, err
return 0, nil, false return 0, nil, false
} }
func cgoLookupIP(ctx context.Context, name string) (addrs []IPAddr, err error, completed bool) { func cgoLookupIP(ctx context.Context, network, name string) (addrs []IPAddr, err error, completed bool) {
return nil, nil, false return nil, nil, false
} }

View file

@ -49,7 +49,7 @@ type reverseLookupResult struct {
} }
func cgoLookupHost(ctx context.Context, name string) (hosts []string, err error, completed bool) { func cgoLookupHost(ctx context.Context, name string) (hosts []string, err error, completed bool) {
addrs, err, completed := cgoLookupIP(ctx, name) addrs, err, completed := cgoLookupIP(ctx, "ip", name)
for _, addr := range addrs { for _, addr := range addrs {
hosts = append(hosts, addr.String()) hosts = append(hosts, addr.String())
} }
@ -69,13 +69,11 @@ func cgoLookupPort(ctx context.Context, network, service string) (port int, err
default: default:
return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}, true return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}, true
} }
if len(network) >= 4 { switch ipVersion(network) {
switch network[3] { case '4':
case '4': hints.ai_family = C.AF_INET
hints.ai_family = C.AF_INET case '6':
case '6': hints.ai_family = C.AF_INET6
hints.ai_family = C.AF_INET6
}
} }
if ctx.Done() == nil { if ctx.Done() == nil {
port, err := cgoLookupServicePort(&hints, network, service) port, err := cgoLookupServicePort(&hints, network, service)
@ -135,13 +133,20 @@ func cgoPortLookup(result chan<- portLookupResult, hints *C.struct_addrinfo, net
result <- portLookupResult{port, err} result <- portLookupResult{port, err}
} }
func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error) { func cgoLookupIPCNAME(network, name string) (addrs []IPAddr, cname string, err error) {
acquireThread() acquireThread()
defer releaseThread() defer releaseThread()
var hints C.struct_addrinfo var hints C.struct_addrinfo
hints.ai_flags = cgoAddrInfoFlags hints.ai_flags = cgoAddrInfoFlags
hints.ai_socktype = C.SOCK_STREAM hints.ai_socktype = C.SOCK_STREAM
hints.ai_family = C.AF_UNSPEC
switch ipVersion(network) {
case '4':
hints.ai_family = C.AF_INET
case '6':
hints.ai_family = C.AF_INET6
}
h := make([]byte, len(name)+1) h := make([]byte, len(name)+1)
copy(h, name) copy(h, name)
@ -197,18 +202,18 @@ func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error) {
return addrs, cname, nil return addrs, cname, nil
} }
func cgoIPLookup(result chan<- ipLookupResult, name string) { func cgoIPLookup(result chan<- ipLookupResult, network, name string) {
addrs, cname, err := cgoLookupIPCNAME(name) addrs, cname, err := cgoLookupIPCNAME(network, name)
result <- ipLookupResult{addrs, cname, err} result <- ipLookupResult{addrs, cname, err}
} }
func cgoLookupIP(ctx context.Context, name string) (addrs []IPAddr, err error, completed bool) { func cgoLookupIP(ctx context.Context, network, name string) (addrs []IPAddr, err error, completed bool) {
if ctx.Done() == nil { if ctx.Done() == nil {
addrs, _, err = cgoLookupIPCNAME(name) addrs, _, err = cgoLookupIPCNAME(network, name)
return addrs, err, true return addrs, err, true
} }
result := make(chan ipLookupResult, 1) result := make(chan ipLookupResult, 1)
go cgoIPLookup(result, name) go cgoIPLookup(result, network, name)
select { select {
case r := <-result: case r := <-result:
return r.addrs, r.err, true return r.addrs, r.err, true
@ -219,11 +224,11 @@ func cgoLookupIP(ctx context.Context, name string) (addrs []IPAddr, err error, c
func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error, completed bool) { func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error, completed bool) {
if ctx.Done() == nil { if ctx.Done() == nil {
_, cname, err = cgoLookupIPCNAME(name) _, cname, err = cgoLookupIPCNAME("ip", name)
return cname, err, true return cname, err, true
} }
result := make(chan ipLookupResult, 1) result := make(chan ipLookupResult, 1)
go cgoIPLookup(result, name) go cgoIPLookup(result, "ip", name)
select { select {
case r := <-result: case r := <-result:
return r.cname, r.err, true return r.cname, r.err, true

Some files were not shown because too many files have changed in this diff Show more