mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
[dev.typealias] all: merge go1.8.3 into dev.typealias
352996a381 (tag: go1.8.3) [release-branch.go1.8] go1.8.3 bb5055d6f1 [release-branch.go1.8] doc: document go1.8.3 439c0c8be8 [release-branch.go1.8] cmd/compile: don't move spills to loop exits where the spill is dead e396667ba3 [release-branch.go1.8] cmd/compile: zero ambiguously live variables at VARKILLs daf6706f37 [release-branch.go1.8] runtime: use pselect6 for usleep on linux/386 958c64bbab [release-branch.go1.8] runtime: use pselect6 for usleep on linux/amd64 and linux/arm 195e20a976 [release-branch.go1.8] cmd/compile: ignore types when considering tuple select for CSE f55bc1c4eb [release-branch.go1.8] net/http: update bundled http2 for gracefulShutdownCh lock contention slowdown 51f508bb4a [release-branch.go1.8] cmd/compile: fix s390x unsigned comparison constant merging rules 243dee1737 [release-branch.go1.8] cmd/go: if we get a C compiler dwarf2 warning, try without -g a43c0d2dc8 [release-branch.go1.8] runtime: don't corrupt arena bounds on low mmap 1054085dcf [release-branch.go1.8] cmd/compile: fix store chain in schedule pass 18a13d373a [release-branch.go1.8] runtime: doubly fix "double wakeup" panic 6efa2f22ac [release-branch.go1.8] database/sql: ensure releaseConn is defined before a possible close fb9770f09b [release-branch.go1.8] runtime: print debug info on "base out of range" b6a8fc8d8c [release-branch.go1.8] doc: remove mentions of yacc tool 59870f9e19 (tag: go1.8.2) [release-branch.go1.8] go1.8.2 c9688ddb6b [release-branch.go1.8] doc: document go1.8.2 and go1.7.6 38d35f49e7 [release-branch.go1.8] crypto/elliptic: fix carry bug in x86-64 P-256 implementation. Change-Id: I2aa0eab7a990d24e25809fb13ce6cb031104f474
This commit is contained in:
commit
8a5ef1501d
@ -22,8 +22,6 @@ using the go <code>tool</code> subcommand, such as <code>go tool vet</code>.
|
||||
This style of invocation allows, for instance, checking a single source file
|
||||
rather than an entire package: <code>go tool vet myprogram.go</code> as
|
||||
compared to <code>go vet mypackage</code>.
|
||||
Some of the commands, such as <code>yacc</code>, are accessible only through
|
||||
the go <code>tool</code> subcommand.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@ -95,12 +93,6 @@ gofmt</a> command with more general options.</td>
|
||||
calls whose arguments do not align with the format string.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="/cmd/yacc/">yacc</a></td>
|
||||
<td> </td>
|
||||
<td>Yacc is a version of yacc that generates parsers implemented in Go.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<p>
|
||||
|
@ -49,6 +49,20 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.1">Go
|
||||
1.8.1 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.8.2 (released 2017/05/23) includes a security fix to the
|
||||
<code>crypto/elliptic</code> package.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.2">Go
|
||||
1.8.2 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.8.3 (released 2017/05/24) includes fixes to the compiler, runtime,
|
||||
documentation, and the <code>database/sql</code> package.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.3">Go
|
||||
1.8.3 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.7">go1.7 (released 2016/08/15)</h2>
|
||||
|
||||
<p>
|
||||
@ -95,6 +109,13 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.5">Go
|
||||
1.7.5 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.7.6 (released 2017/05/23) includes the same security fix as Go 1.8.2 and
|
||||
was released at the same time.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.2">Go
|
||||
1.8.2 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.6">go1.6 (released 2016/02/17)</h2>
|
||||
|
||||
<p>
|
||||
|
@ -27,4 +27,5 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = ssaMarkMoves
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
}
|
||||
|
@ -166,6 +166,27 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32, x0 *uin
|
||||
return p
|
||||
}
|
||||
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
op := x86.AMOVQ
|
||||
if gc.Widthptr == 4 {
|
||||
op = x86.AMOVL
|
||||
}
|
||||
sym := gc.Linksym(n.Sym)
|
||||
size := n.Type.Size()
|
||||
for i := int64(0); i < size; i += int64(gc.Widthptr) {
|
||||
p := gc.AddAsmAfter(op, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = 0
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = x86.REG_SP
|
||||
p.To.Offset = n.Xoffset + i
|
||||
p.To.Sym = sym
|
||||
}
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
// This is actually not the x86 NOP anymore,
|
||||
// but at the point where it gets used, AX is dead
|
||||
|
@ -21,4 +21,5 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
}
|
||||
|
@ -92,6 +92,27 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, r0 *uint32) *obj.Pr
|
||||
|
||||
return p
|
||||
}
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
sym := gc.Linksym(n.Sym)
|
||||
size := n.Type.Size()
|
||||
p := gc.Prog(arm.AMOVW)
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = 0
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = arm.REGTMP
|
||||
for i := int64(0); i < size; i += 4 {
|
||||
p := gc.AddAsmAfter(arm.AMOVW, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = arm.REGTMP
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = arm.REGSP
|
||||
p.To.Offset = n.Xoffset + i
|
||||
p.To.Sym = sym
|
||||
}
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
p := gc.Prog(arm.AAND)
|
||||
|
@ -21,4 +21,5 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
}
|
||||
|
@ -103,6 +103,23 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
|
||||
return p
|
||||
}
|
||||
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
sym := gc.Linksym(n.Sym)
|
||||
size := n.Type.Size()
|
||||
for i := int64(0); i < size; i += 8 {
|
||||
p := gc.AddAsmAfter(arm64.AMOVD, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = arm64.REGZERO
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = arm64.REGSP
|
||||
p.To.Offset = n.Xoffset + i
|
||||
p.To.Sym = sym
|
||||
}
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
p := gc.Prog(arm64.AHINT)
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
|
@ -364,6 +364,12 @@ type Arch struct {
|
||||
// SSAGenBlock emits end-of-block Progs. SSAGenValue should be called
|
||||
// for all values in the block before SSAGenBlock.
|
||||
SSAGenBlock func(s *SSAGenState, b, next *ssa.Block)
|
||||
|
||||
// ZeroAuto emits code to zero the given auto stack variable.
|
||||
// Code is added immediately after pp.
|
||||
// ZeroAuto must not use any non-temporary registers.
|
||||
// ZeroAuto will only be called for variables which contain a pointer.
|
||||
ZeroAuto func(n *Node, pp *obj.Prog)
|
||||
}
|
||||
|
||||
var pcloc int32
|
||||
|
@ -72,6 +72,15 @@ func Appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset in
|
||||
return q
|
||||
}
|
||||
|
||||
func AddAsmAfter(as obj.As, p *obj.Prog) *obj.Prog {
|
||||
q := Ctxt.NewProg()
|
||||
Clearp(q)
|
||||
q.As = as
|
||||
q.Link = p.Link
|
||||
p.Link = q
|
||||
return q
|
||||
}
|
||||
|
||||
func ggloblnod(nam *Node) {
|
||||
s := Linksym(nam.Sym)
|
||||
s.Gotype = Linksym(ngotype(nam))
|
||||
|
@ -120,7 +120,30 @@ func Gvarlive(n *Node) {
|
||||
}
|
||||
|
||||
func removevardef(firstp *obj.Prog) {
|
||||
// At VARKILLs, zero variable if it is ambiguously live.
|
||||
// After the VARKILL anything this variable references
|
||||
// might be collected. If it were to become live again later,
|
||||
// the GC will see references to already-collected objects.
|
||||
// See issue 20029.
|
||||
for p := firstp; p != nil; p = p.Link {
|
||||
if p.As != obj.AVARKILL {
|
||||
continue
|
||||
}
|
||||
n := p.To.Node.(*Node)
|
||||
if !n.Name.Needzero {
|
||||
continue
|
||||
}
|
||||
if n.Class != PAUTO {
|
||||
Fatalf("zero of variable which isn't PAUTO %v", n)
|
||||
}
|
||||
if n.Type.Size()%int64(Widthptr) != 0 {
|
||||
Fatalf("zero of variable not a multiple of ptr size %v", n)
|
||||
}
|
||||
Thearch.ZeroAuto(n, p)
|
||||
}
|
||||
|
||||
for p := firstp; p != nil; p = p.Link {
|
||||
|
||||
for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL || p.Link.As == obj.AVARLIVE) {
|
||||
p.Link = p.Link.Link
|
||||
}
|
||||
|
@ -63,6 +63,9 @@ func TestArithmeticConst(t *testing.T) { runTest(t, "arithConst.go") }
|
||||
|
||||
func TestChan(t *testing.T) { runTest(t, "chan.go") }
|
||||
|
||||
// TestComparisonsConst tests results for comparison operations against constants.
|
||||
func TestComparisonsConst(t *testing.T) { runTest(t, "cmpConst.go") }
|
||||
|
||||
func TestCompound(t *testing.T) { runTest(t, "compound.go") }
|
||||
|
||||
func TestCtl(t *testing.T) { runTest(t, "ctl.go") }
|
||||
|
2217
src/cmd/compile/internal/gc/testdata/cmpConst.go
vendored
Normal file
2217
src/cmd/compile/internal/gc/testdata/cmpConst.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
248
src/cmd/compile/internal/gc/testdata/gen/cmpConstGen.go
vendored
Normal file
248
src/cmd/compile/internal/gc/testdata/gen/cmpConstGen.go
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This program generates a test to verify that the standard comparison
|
||||
// operators properly handle one const operand. The test file should be
|
||||
// generated with a known working version of go.
|
||||
// launch with `go run cmpConstGen.go` a file called cmpConst.go
|
||||
// will be written into the parent directory containing the tests
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/big"
|
||||
"sort"
|
||||
)
|
||||
|
||||
const (
|
||||
maxU64 = (1 << 64) - 1
|
||||
maxU32 = (1 << 32) - 1
|
||||
maxU16 = (1 << 16) - 1
|
||||
maxU8 = (1 << 8) - 1
|
||||
|
||||
maxI64 = (1 << 63) - 1
|
||||
maxI32 = (1 << 31) - 1
|
||||
maxI16 = (1 << 15) - 1
|
||||
maxI8 = (1 << 7) - 1
|
||||
|
||||
minI64 = -(1 << 63)
|
||||
minI32 = -(1 << 31)
|
||||
minI16 = -(1 << 15)
|
||||
minI8 = -(1 << 7)
|
||||
)
|
||||
|
||||
func cmp(left *big.Int, op string, right *big.Int) bool {
|
||||
switch left.Cmp(right) {
|
||||
case -1: // less than
|
||||
return op == "<" || op == "<=" || op == "!="
|
||||
case 0: // equal
|
||||
return op == "==" || op == "<=" || op == ">="
|
||||
case 1: // greater than
|
||||
return op == ">" || op == ">=" || op == "!="
|
||||
}
|
||||
panic("unexpected comparison value")
|
||||
}
|
||||
|
||||
func inRange(typ string, val *big.Int) bool {
|
||||
min, max := &big.Int{}, &big.Int{}
|
||||
switch typ {
|
||||
case "uint64":
|
||||
max = max.SetUint64(maxU64)
|
||||
case "uint32":
|
||||
max = max.SetUint64(maxU32)
|
||||
case "uint16":
|
||||
max = max.SetUint64(maxU16)
|
||||
case "uint8":
|
||||
max = max.SetUint64(maxU8)
|
||||
case "int64":
|
||||
min = min.SetInt64(minI64)
|
||||
max = max.SetInt64(maxI64)
|
||||
case "int32":
|
||||
min = min.SetInt64(minI32)
|
||||
max = max.SetInt64(maxI32)
|
||||
case "int16":
|
||||
min = min.SetInt64(minI16)
|
||||
max = max.SetInt64(maxI16)
|
||||
case "int8":
|
||||
min = min.SetInt64(minI8)
|
||||
max = max.SetInt64(maxI8)
|
||||
default:
|
||||
panic("unexpected type")
|
||||
}
|
||||
return cmp(min, "<=", val) && cmp(val, "<=", max)
|
||||
}
|
||||
|
||||
func getValues(typ string) []*big.Int {
|
||||
Uint := func(v uint64) *big.Int { return big.NewInt(0).SetUint64(v) }
|
||||
Int := func(v int64) *big.Int { return big.NewInt(0).SetInt64(v) }
|
||||
values := []*big.Int{
|
||||
// limits
|
||||
Uint(maxU64),
|
||||
Uint(maxU64 - 1),
|
||||
Uint(maxI64 + 1),
|
||||
Uint(maxI64),
|
||||
Uint(maxI64 - 1),
|
||||
Uint(maxU32 + 1),
|
||||
Uint(maxU32),
|
||||
Uint(maxU32 - 1),
|
||||
Uint(maxI32 + 1),
|
||||
Uint(maxI32),
|
||||
Uint(maxI32 - 1),
|
||||
Uint(maxU16 + 1),
|
||||
Uint(maxU16),
|
||||
Uint(maxU16 - 1),
|
||||
Uint(maxI16 + 1),
|
||||
Uint(maxI16),
|
||||
Uint(maxI16 - 1),
|
||||
Uint(maxU8 + 1),
|
||||
Uint(maxU8),
|
||||
Uint(maxU8 - 1),
|
||||
Uint(maxI8 + 1),
|
||||
Uint(maxI8),
|
||||
Uint(maxI8 - 1),
|
||||
Uint(0),
|
||||
Int(minI8 + 1),
|
||||
Int(minI8),
|
||||
Int(minI8 - 1),
|
||||
Int(minI16 + 1),
|
||||
Int(minI16),
|
||||
Int(minI16 - 1),
|
||||
Int(minI32 + 1),
|
||||
Int(minI32),
|
||||
Int(minI32 - 1),
|
||||
Int(minI64 + 1),
|
||||
Int(minI64),
|
||||
|
||||
// other possibly interesting values
|
||||
Uint(1),
|
||||
Int(-1),
|
||||
Uint(0xff << 56),
|
||||
Uint(0xff << 32),
|
||||
Uint(0xff << 24),
|
||||
}
|
||||
sort.Slice(values, func(i, j int) bool { return values[i].Cmp(values[j]) == -1 })
|
||||
var ret []*big.Int
|
||||
for _, val := range values {
|
||||
if !inRange(typ, val) {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, val)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func sigString(v *big.Int) string {
|
||||
var t big.Int
|
||||
t.Abs(v)
|
||||
if v.Sign() == -1 {
|
||||
return "neg" + t.String()
|
||||
}
|
||||
return t.String()
|
||||
}
|
||||
|
||||
func main() {
|
||||
types := []string{
|
||||
"uint64", "uint32", "uint16", "uint8",
|
||||
"int64", "int32", "int16", "int8",
|
||||
}
|
||||
|
||||
w := new(bytes.Buffer)
|
||||
fmt.Fprintf(w, "// run\n")
|
||||
fmt.Fprintf(w, "// Code generated by gen/cmpConstGen.go. DO NOT EDIT.\n\n")
|
||||
fmt.Fprintf(w, "package main;\n")
|
||||
fmt.Fprintf(w, "import (\"fmt\"; \"reflect\"; \"runtime\";)\n")
|
||||
fmt.Fprintf(w, "// results show the expected result for the elements left of, equal to and right of the index.\n")
|
||||
fmt.Fprintf(w, "type result struct{l, e, r bool}\n")
|
||||
fmt.Fprintf(w, "var (\n")
|
||||
fmt.Fprintf(w, " eq = result{l: false, e: true, r: false}\n")
|
||||
fmt.Fprintf(w, " ne = result{l: true, e: false, r: true}\n")
|
||||
fmt.Fprintf(w, " lt = result{l: true, e: false, r: false}\n")
|
||||
fmt.Fprintf(w, " le = result{l: true, e: true, r: false}\n")
|
||||
fmt.Fprintf(w, " gt = result{l: false, e: false, r: true}\n")
|
||||
fmt.Fprintf(w, " ge = result{l: false, e: true, r: true}\n")
|
||||
fmt.Fprintf(w, ")\n")
|
||||
|
||||
operators := []struct{ op, name string }{
|
||||
{"<", "lt"},
|
||||
{"<=", "le"},
|
||||
{">", "gt"},
|
||||
{">=", "ge"},
|
||||
{"==", "eq"},
|
||||
{"!=", "ne"},
|
||||
}
|
||||
|
||||
for _, typ := range types {
|
||||
// generate a slice containing valid values for this type
|
||||
fmt.Fprintf(w, "\n// %v tests\n", typ)
|
||||
values := getValues(typ)
|
||||
fmt.Fprintf(w, "var %v_vals = []%v{\n", typ, typ)
|
||||
for _, val := range values {
|
||||
fmt.Fprintf(w, "%v,\n", val.String())
|
||||
}
|
||||
fmt.Fprintf(w, "}\n")
|
||||
|
||||
// generate test functions
|
||||
for _, r := range values {
|
||||
// TODO: could also test constant on lhs.
|
||||
sig := sigString(r)
|
||||
for _, op := range operators {
|
||||
// no need for go:noinline because the function is called indirectly
|
||||
fmt.Fprintf(w, "func %v_%v_%v(x %v) bool { return x %v %v; }\n", op.name, sig, typ, typ, op.op, r.String())
|
||||
}
|
||||
}
|
||||
|
||||
// generate a table of test cases
|
||||
fmt.Fprintf(w, "var %v_tests = []struct{\n", typ)
|
||||
fmt.Fprintf(w, " idx int // index of the constant used\n")
|
||||
fmt.Fprintf(w, " exp result // expected results\n")
|
||||
fmt.Fprintf(w, " fn func(%v) bool\n", typ)
|
||||
fmt.Fprintf(w, "}{\n")
|
||||
for i, r := range values {
|
||||
sig := sigString(r)
|
||||
for _, op := range operators {
|
||||
fmt.Fprintf(w, "{idx: %v,", i)
|
||||
fmt.Fprintf(w, "exp: %v,", op.name)
|
||||
fmt.Fprintf(w, "fn: %v_%v_%v},\n", op.name, sig, typ)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(w, "}\n")
|
||||
}
|
||||
|
||||
// emit the main function, looping over all test cases
|
||||
fmt.Fprintf(w, "func main() {\n")
|
||||
for _, typ := range types {
|
||||
fmt.Fprintf(w, "for i, test := range %v_tests {\n", typ)
|
||||
fmt.Fprintf(w, " for j, x := range %v_vals {\n", typ)
|
||||
fmt.Fprintf(w, " want := test.exp.l\n")
|
||||
fmt.Fprintf(w, " if j == test.idx {\nwant = test.exp.e\n}")
|
||||
fmt.Fprintf(w, " else if j > test.idx {\nwant = test.exp.r\n}\n")
|
||||
fmt.Fprintf(w, " if test.fn(x) != want {\n")
|
||||
fmt.Fprintf(w, " fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name()\n")
|
||||
fmt.Fprintf(w, " msg := fmt.Sprintf(\"test failed: %%v(%%v) != %%v [type=%v i=%%v j=%%v idx=%%v]\", fn, x, want, i, j, test.idx)\n", typ)
|
||||
fmt.Fprintf(w, " panic(msg)\n")
|
||||
fmt.Fprintf(w, " }\n")
|
||||
fmt.Fprintf(w, " }\n")
|
||||
fmt.Fprintf(w, "}\n")
|
||||
}
|
||||
fmt.Fprintf(w, "}\n")
|
||||
|
||||
// gofmt result
|
||||
b := w.Bytes()
|
||||
src, err := format.Source(b)
|
||||
if err != nil {
|
||||
fmt.Printf("%s\n", b)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// write to file
|
||||
err = ioutil.WriteFile("../cmpConst.go", src, 0666)
|
||||
if err != nil {
|
||||
log.Fatalf("can't write output: %v\n", err)
|
||||
}
|
||||
}
|
@ -23,4 +23,5 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
}
|
||||
|
@ -92,6 +92,23 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
|
||||
return p
|
||||
}
|
||||
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
sym := gc.Linksym(n.Sym)
|
||||
size := n.Type.Size()
|
||||
for i := int64(0); i < size; i += 4 {
|
||||
p := gc.AddAsmAfter(mips.AMOVW, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = mips.REGZERO
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = mips.REGSP
|
||||
p.To.Offset = n.Xoffset + i
|
||||
p.To.Sym = sym
|
||||
}
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
p := gc.Prog(mips.ANOR)
|
||||
p.From.Type = obj.TYPE_REG
|
||||
|
@ -25,4 +25,5 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
}
|
||||
|
@ -95,6 +95,23 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
|
||||
return p
|
||||
}
|
||||
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
sym := gc.Linksym(n.Sym)
|
||||
size := n.Type.Size()
|
||||
for i := int64(0); i < size; i += 8 {
|
||||
p := gc.AddAsmAfter(mips.AMOVV, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = mips.REGZERO
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = mips.REGSP
|
||||
p.To.Offset = n.Xoffset + i
|
||||
p.To.Sym = sym
|
||||
}
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
p := gc.Prog(mips.ANOR)
|
||||
p.From.Type = obj.TYPE_REG
|
||||
|
@ -24,6 +24,7 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = ssaMarkMoves
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
|
||||
initvariants()
|
||||
initproginfo()
|
||||
|
@ -90,6 +90,23 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
|
||||
return p
|
||||
}
|
||||
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
sym := gc.Linksym(n.Sym)
|
||||
size := n.Type.Size()
|
||||
for i := int64(0); i < size; i += 8 {
|
||||
p := gc.AddAsmAfter(ppc64.AMOVD, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = ppc64.REGZERO
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = ppc64.REGSP
|
||||
p.To.Offset = n.Xoffset + i
|
||||
p.To.Sym = sym
|
||||
}
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
p := gc.Prog(ppc64.AOR)
|
||||
p.From.Type = obj.TYPE_REG
|
||||
|
@ -20,4 +20,5 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = ssaMarkMoves
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
}
|
||||
|
@ -143,6 +143,19 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
|
||||
return p
|
||||
}
|
||||
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
p := gc.AddAsmAfter(s390x.ACLEAR, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = n.Type.Size()
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = s390x.REGSP
|
||||
p.To.Offset = n.Xoffset
|
||||
p.To.Sym = gc.Linksym(n.Sym)
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
p := gc.Prog(s390x.AOR)
|
||||
p.From.Type = obj.TYPE_REG
|
||||
|
@ -294,6 +294,39 @@ func checkFunc(f *Func) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that if a tuple has a memory type, it is second.
|
||||
for _, b := range f.Blocks {
|
||||
for _, v := range b.Values {
|
||||
if v.Type.IsTuple() && v.Type.FieldType(0).IsMemory() {
|
||||
f.Fatalf("memory is first in a tuple: %s\n", v.LongString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that only one memory is live at any point.
|
||||
// TODO: make this check examine interblock.
|
||||
if f.scheduled {
|
||||
for _, b := range f.Blocks {
|
||||
var mem *Value // the live memory
|
||||
for _, v := range b.Values {
|
||||
if v.Op != OpPhi {
|
||||
for _, a := range v.Args {
|
||||
if a.Type.IsMemory() || a.Type.IsTuple() && a.Type.FieldType(1).IsMemory() {
|
||||
if mem == nil {
|
||||
mem = a
|
||||
} else if mem != a {
|
||||
f.Fatalf("two live mems @ %s: %s and %s", v, mem, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if v.Type.IsMemory() || v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
|
||||
mem = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// domCheck reports whether x dominates y (including x==y).
|
||||
|
@ -313,9 +313,13 @@ func cmpVal(v, w *Value, auxIDs auxmap) Cmp {
|
||||
// that generate memory.
|
||||
return lt2Cmp(v.ID < w.ID)
|
||||
}
|
||||
|
||||
if tc := v.Type.Compare(w.Type); tc != CMPeq {
|
||||
return tc
|
||||
// OpSelect is a pseudo-op. We need to be more agressive
|
||||
// regarding CSE to keep multiple OpSelect's of the same
|
||||
// argument from existing.
|
||||
if v.Op != OpSelect0 && v.Op != OpSelect1 {
|
||||
if tc := v.Type.Compare(w.Type); tc != CMPeq {
|
||||
return tc
|
||||
}
|
||||
}
|
||||
|
||||
if v.Aux != w.Aux {
|
||||
|
@ -35,8 +35,20 @@ type DummyFrontend struct {
|
||||
func (DummyFrontend) StringData(s string) interface{} {
|
||||
return nil
|
||||
}
|
||||
func (DummyFrontend) Auto(t Type) GCNode {
|
||||
return nil
|
||||
|
||||
type dummyGCNode struct {
|
||||
typ Type
|
||||
name string
|
||||
}
|
||||
|
||||
func (d *dummyGCNode) Typ() Type {
|
||||
return d.typ
|
||||
}
|
||||
func (d *dummyGCNode) String() string {
|
||||
return d.name
|
||||
}
|
||||
func (d DummyFrontend) Auto(t Type) GCNode {
|
||||
return &dummyGCNode{typ: t, name: "dummy"}
|
||||
}
|
||||
func (d DummyFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) {
|
||||
return LocalSlot{s.N, d.TypeBytePtr(), s.Off}, LocalSlot{s.N, d.TypeInt(), s.Off + 8}
|
||||
|
@ -537,8 +537,8 @@
|
||||
(CMP (MOVDconst [c]) x) && is32Bit(c) -> (InvertFlags (CMPconst x [c]))
|
||||
(CMPW x (MOVDconst [c])) -> (CMPWconst x [c])
|
||||
(CMPW (MOVDconst [c]) x) -> (InvertFlags (CMPWconst x [c]))
|
||||
(CMPU x (MOVDconst [c])) && is32Bit(c) -> (CMPUconst x [int64(uint32(c))])
|
||||
(CMPU (MOVDconst [c]) x) && is32Bit(c) -> (InvertFlags (CMPUconst x [int64(uint32(c))]))
|
||||
(CMPU x (MOVDconst [c])) && isU32Bit(c) -> (CMPUconst x [int64(uint32(c))])
|
||||
(CMPU (MOVDconst [c]) x) && isU32Bit(c) -> (InvertFlags (CMPUconst x [int64(uint32(c))]))
|
||||
(CMPWU x (MOVDconst [c])) -> (CMPWUconst x [int64(uint32(c))])
|
||||
(CMPWU (MOVDconst [c]) x) -> (InvertFlags (CMPWUconst x [int64(uint32(c))]))
|
||||
|
||||
|
@ -1699,6 +1699,24 @@ sinking:
|
||||
}
|
||||
p := d.Preds[0].b // block in loop exiting to d.
|
||||
|
||||
// Check that the spill value is still live at the start of d.
|
||||
// If it isn't, we can't move the spill here because some other value
|
||||
// may be using the same stack slot. See issue 20472.
|
||||
// The spill value can't be defined in d, so that makes our lives easier.
|
||||
for _, x := range stacklive[d.ID] {
|
||||
if x == vsp.ID {
|
||||
goto stillLive
|
||||
}
|
||||
}
|
||||
for _, v := range d.Values {
|
||||
if v.Op == OpLoadReg && v.Args[0] == vsp {
|
||||
goto stillLive
|
||||
}
|
||||
}
|
||||
// Spill is not live - abort sinking this spill.
|
||||
continue sinking
|
||||
stillLive:
|
||||
|
||||
endregs := s.endRegs[p.ID]
|
||||
for _, regrec := range endregs {
|
||||
if regrec.v == e && regrec.r != noRegister && regrec.c == e { // TODO: regrec.c != e implies different spill possible.
|
||||
|
@ -31,3 +31,68 @@ func TestLiveControlOps(t *testing.T) {
|
||||
regalloc(f.f)
|
||||
checkFunc(f.f)
|
||||
}
|
||||
|
||||
func TestSpillMove(t *testing.T) {
|
||||
// Test for issue 20472. We shouldn't move a spill out to exit blocks
|
||||
// if there is an exit block where the spill is dead but the pre-spill
|
||||
// value is live.
|
||||
c := testConfig(t)
|
||||
ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
|
||||
arg1Aux := c.fe.Auto(TypeInt64)
|
||||
arg2Aux := c.fe.Auto(ptrType)
|
||||
f := Fun(c, "entry",
|
||||
Bloc("entry",
|
||||
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
||||
Valu("x", OpArg, TypeInt64, 0, arg1Aux),
|
||||
Valu("p", OpArg, ptrType, 0, arg2Aux),
|
||||
Valu("a", OpAMD64TESTQ, TypeFlags, 0, nil, "x", "x"),
|
||||
Goto("loop1"),
|
||||
),
|
||||
Bloc("loop1",
|
||||
Valu("y", OpAMD64MULQ, TypeInt64, 0, nil, "x", "x"),
|
||||
Eq("a", "loop2", "exit1"),
|
||||
),
|
||||
Bloc("loop2",
|
||||
Eq("a", "loop1", "exit2"),
|
||||
),
|
||||
Bloc("exit1",
|
||||
// store before call, y is available in a register
|
||||
Valu("mem2", OpAMD64MOVQstore, TypeMem, 0, nil, "p", "y", "mem"),
|
||||
Valu("mem3", OpAMD64CALLstatic, TypeMem, 0, nil, "mem2"),
|
||||
Exit("mem3"),
|
||||
),
|
||||
Bloc("exit2",
|
||||
// store after call, y must be loaded from a spill location
|
||||
Valu("mem4", OpAMD64CALLstatic, TypeMem, 0, nil, "mem"),
|
||||
Valu("mem5", OpAMD64MOVQstore, TypeMem, 0, nil, "p", "y", "mem4"),
|
||||
Exit("mem5"),
|
||||
),
|
||||
)
|
||||
flagalloc(f.f)
|
||||
regalloc(f.f)
|
||||
checkFunc(f.f)
|
||||
// There should still be a spill in Loop1, and nowhere else.
|
||||
if numSpills(f.blocks["loop1"]) != 1 {
|
||||
t.Errorf("spill missing from loop1")
|
||||
}
|
||||
if numSpills(f.blocks["loop2"]) != 0 {
|
||||
t.Errorf("spill present in loop2")
|
||||
}
|
||||
if numSpills(f.blocks["exit1"]) != 0 {
|
||||
t.Errorf("spill present in exit1")
|
||||
}
|
||||
if numSpills(f.blocks["exit2"]) != 0 {
|
||||
t.Errorf("spill present in exit2")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func numSpills(b *Block) int {
|
||||
n := 0
|
||||
for _, v := range b.Values {
|
||||
if v.Op == OpStoreReg {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
@ -6784,7 +6784,7 @@ func rewriteValueS390X_OpS390XCMPU(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (CMPU x (MOVDconst [c]))
|
||||
// cond: is32Bit(c)
|
||||
// cond: isU32Bit(c)
|
||||
// result: (CMPUconst x [int64(uint32(c))])
|
||||
for {
|
||||
x := v.Args[0]
|
||||
@ -6793,7 +6793,7 @@ func rewriteValueS390X_OpS390XCMPU(v *Value, config *Config) bool {
|
||||
break
|
||||
}
|
||||
c := v_1.AuxInt
|
||||
if !(is32Bit(c)) {
|
||||
if !(isU32Bit(c)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpS390XCMPUconst)
|
||||
@ -6802,7 +6802,7 @@ func rewriteValueS390X_OpS390XCMPU(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (CMPU (MOVDconst [c]) x)
|
||||
// cond: is32Bit(c)
|
||||
// cond: isU32Bit(c)
|
||||
// result: (InvertFlags (CMPUconst x [int64(uint32(c))]))
|
||||
for {
|
||||
v_0 := v.Args[0]
|
||||
@ -6811,7 +6811,7 @@ func rewriteValueS390X_OpS390XCMPU(v *Value, config *Config) bool {
|
||||
}
|
||||
c := v_0.AuxInt
|
||||
x := v.Args[1]
|
||||
if !(is32Bit(c)) {
|
||||
if !(isU32Bit(c)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpS390XInvertFlags)
|
||||
|
@ -148,19 +148,20 @@ func schedule(f *Func) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: make this logic permanent in types.IsMemory?
|
||||
isMem := func(v *Value) bool {
|
||||
return v.Type.IsMemory() || v.Type.IsTuple() && v.Type.FieldType(1).IsMemory()
|
||||
}
|
||||
|
||||
for _, b := range f.Blocks {
|
||||
// Find store chain for block.
|
||||
// Store chains for different blocks overwrite each other, so
|
||||
// the calculated store chain is good only for this block.
|
||||
for _, v := range b.Values {
|
||||
if v.Op != OpPhi && v.Type.IsMemory() {
|
||||
mem := v
|
||||
if v.Op == OpSelect1 {
|
||||
v = v.Args[0]
|
||||
}
|
||||
if v.Op != OpPhi && isMem(v) {
|
||||
for _, w := range v.Args {
|
||||
if w.Type.IsMemory() {
|
||||
nextMem[w.ID] = mem
|
||||
if isMem(w) {
|
||||
nextMem[w.ID] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -179,15 +180,15 @@ func schedule(f *Func) {
|
||||
uses[w.ID]++
|
||||
}
|
||||
// Any load must come before the following store.
|
||||
if v.Type.IsMemory() || !w.Type.IsMemory() {
|
||||
continue // not a load
|
||||
if !isMem(v) && isMem(w) {
|
||||
// v is a load.
|
||||
s := nextMem[w.ID]
|
||||
if s == nil || s.Block != b {
|
||||
continue
|
||||
}
|
||||
additionalArgs[s.ID] = append(additionalArgs[s.ID], v)
|
||||
uses[v.ID]++
|
||||
}
|
||||
s := nextMem[w.ID]
|
||||
if s == nil || s.Block != b {
|
||||
continue
|
||||
}
|
||||
additionalArgs[s.ID] = append(additionalArgs[s.ID], v)
|
||||
uses[v.ID]++
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,4 +31,5 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = ssaMarkMoves
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
}
|
||||
|
@ -84,6 +84,23 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32) *obj.Pr
|
||||
return p
|
||||
}
|
||||
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
sym := gc.Linksym(n.Sym)
|
||||
size := n.Type.Size()
|
||||
for i := int64(0); i < size; i += 4 {
|
||||
p := gc.AddAsmAfter(x86.AMOVL, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = 0
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = x86.REG_SP
|
||||
p.To.Offset = n.Xoffset + i
|
||||
p.To.Sym = sym
|
||||
}
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
p := gc.Prog(x86.AXCHGL)
|
||||
p.From.Type = obj.TYPE_REG
|
||||
|
@ -3073,6 +3073,26 @@ func (b *builder) ccompile(p *Package, outfile string, flags []string, file stri
|
||||
desc := p.ImportPath
|
||||
output, err := b.runOut(p.Dir, desc, nil, compiler, flags, "-o", outfile, "-c", file)
|
||||
if len(output) > 0 {
|
||||
// On FreeBSD 11, when we pass -g to clang 3.8 it
|
||||
// invokes its internal assembler with -dwarf-version=2.
|
||||
// When it sees .section .note.GNU-stack, it warns
|
||||
// "DWARF2 only supports one section per compilation unit".
|
||||
// This warning makes no sense, since the section is empty,
|
||||
// but it confuses people.
|
||||
// We work around the problem by detecting the warning
|
||||
// and dropping -g and trying again.
|
||||
if bytes.Contains(output, []byte("DWARF2 only supports one section per compilation unit")) {
|
||||
newFlags := make([]string, 0, len(flags))
|
||||
for _, f := range flags {
|
||||
if !strings.HasPrefix(f, "-g") {
|
||||
newFlags = append(newFlags, f)
|
||||
}
|
||||
}
|
||||
if len(newFlags) < len(flags) {
|
||||
return b.ccompile(p, outfile, newFlags, file, compiler)
|
||||
}
|
||||
}
|
||||
|
||||
b.showOutput(p.Dir, desc, b.processOutput(output))
|
||||
if err != nil {
|
||||
err = errPrintedOutput
|
||||
|
@ -300,6 +300,29 @@ var p224BaseMultTests = []baseMultTest{
|
||||
},
|
||||
}
|
||||
|
||||
type scalarMultTest struct {
|
||||
k string
|
||||
xIn, yIn string
|
||||
xOut, yOut string
|
||||
}
|
||||
|
||||
var p256MultTests = []scalarMultTest{
|
||||
{
|
||||
"2a265f8bcbdcaf94d58519141e578124cb40d64a501fba9c11847b28965bc737",
|
||||
"023819813ac969847059028ea88a1f30dfbcde03fc791d3a252c6b41211882ea",
|
||||
"f93e4ae433cc12cf2a43fc0ef26400c0e125508224cdb649380f25479148a4ad",
|
||||
"4d4de80f1534850d261075997e3049321a0864082d24a917863366c0724f5ae3",
|
||||
"a22d2b7f7818a3563e0f7a76c9bf0921ac55e06e2e4d11795b233824b1db8cc0",
|
||||
},
|
||||
{
|
||||
"313f72ff9fe811bf573176231b286a3bdb6f1b14e05c40146590727a71c3bccd",
|
||||
"cc11887b2d66cbae8f4d306627192522932146b42f01d3c6f92bd5c8ba739b06",
|
||||
"a2f08a029cd06b46183085bae9248b0ed15b70280c7ef13a457f5af382426031",
|
||||
"831c3f6b5f762d2f461901577af41354ac5f228c2591f84f8a6e51e2e3f17991",
|
||||
"93f90934cd0ef2c698cc471c60a93524e87ab31ca2412252337f364513e43684",
|
||||
},
|
||||
}
|
||||
|
||||
func TestBaseMult(t *testing.T) {
|
||||
p224 := P224()
|
||||
for i, e := range p224BaseMultTests {
|
||||
@ -379,6 +402,19 @@ func TestP256Mult(t *testing.T) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for i, e := range p256MultTests {
|
||||
x, _ := new(big.Int).SetString(e.xIn, 16)
|
||||
y, _ := new(big.Int).SetString(e.yIn, 16)
|
||||
k, _ := new(big.Int).SetString(e.k, 16)
|
||||
expectedX, _ := new(big.Int).SetString(e.xOut, 16)
|
||||
expectedY, _ := new(big.Int).SetString(e.yOut, 16)
|
||||
|
||||
xx, yy := p256.ScalarMult(x, y, k.Bytes())
|
||||
if xx.Cmp(expectedX) != 0 || yy.Cmp(expectedY) != 0 {
|
||||
t.Errorf("#%d: got (%x, %x), want (%x, %x)", i, xx, yy, expectedX, expectedY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInfinity(t *testing.T) {
|
||||
|
@ -1314,12 +1314,12 @@ TEXT p256SubInternal(SB),NOSPLIT,$0
|
||||
ADCQ p256const0<>(SB), acc5
|
||||
ADCQ $0, acc6
|
||||
ADCQ p256const1<>(SB), acc7
|
||||
ADCQ $0, mul0
|
||||
ANDQ $1, mul0
|
||||
|
||||
CMOVQNE acc0, acc4
|
||||
CMOVQNE acc1, acc5
|
||||
CMOVQNE acc2, acc6
|
||||
CMOVQNE acc3, acc7
|
||||
CMOVQEQ acc0, acc4
|
||||
CMOVQEQ acc1, acc5
|
||||
CMOVQEQ acc2, acc6
|
||||
CMOVQEQ acc3, acc7
|
||||
|
||||
RET
|
||||
/* ---------------------------------------*/
|
||||
|
@ -1955,12 +1955,12 @@ func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, er
|
||||
rowsi: rowsi,
|
||||
// releaseConn set below
|
||||
}
|
||||
rows.initContextClose(ctx)
|
||||
s.db.addDep(s, rows)
|
||||
rows.releaseConn = func(err error) {
|
||||
releaseConn(err)
|
||||
s.db.removeDep(s, rows)
|
||||
}
|
||||
rows.initContextClose(ctx)
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
|
@ -322,7 +322,7 @@ func TestQueryContext(t *testing.T) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if err := ctx.Err(); err != context.Canceled {
|
||||
t.Fatalf("context err = %v; want context.Canceled")
|
||||
t.Fatalf("context err = %v; want context.Canceled", ctx.Err())
|
||||
}
|
||||
default:
|
||||
t.Fatalf("context err = nil; want context.Canceled")
|
||||
@ -413,7 +413,8 @@ func TestTxContextWait(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
ctx, _ := context.WithTimeout(context.Background(), time.Millisecond*15)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*15)
|
||||
defer cancel()
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Code generated by golang.org/x/tools/cmd/bundle.
|
||||
// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
|
||||
//go:generate bundle -o h2_bundle.go -prefix http2 -underscore golang.org/x/net/http2
|
||||
|
||||
// Package http2 implements the HTTP/2 protocol.
|
||||
@ -3536,9 +3536,13 @@ func (sc *http2serverConn) serve() {
|
||||
sc.idleTimerCh = sc.idleTimer.C
|
||||
}
|
||||
|
||||
var gracefulShutdownCh <-chan struct{}
|
||||
var gracefulShutdownCh chan struct{}
|
||||
if sc.hs != nil {
|
||||
gracefulShutdownCh = http2h1ServerShutdownChan(sc.hs)
|
||||
ch := http2h1ServerShutdownChan(sc.hs)
|
||||
if ch != nil {
|
||||
gracefulShutdownCh = make(chan struct{})
|
||||
go sc.awaitGracefulShutdown(ch, gracefulShutdownCh)
|
||||
}
|
||||
}
|
||||
|
||||
go sc.readFrames()
|
||||
@ -3587,6 +3591,14 @@ func (sc *http2serverConn) serve() {
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *http2serverConn) awaitGracefulShutdown(sharedCh <-chan struct{}, privateCh chan struct{}) {
|
||||
select {
|
||||
case <-sc.doneServing:
|
||||
case <-sharedCh:
|
||||
close(privateCh)
|
||||
}
|
||||
}
|
||||
|
||||
// readPreface reads the ClientPreface greeting from the peer
|
||||
// or returns an error on timeout or an invalid greeting.
|
||||
func (sc *http2serverConn) readPreface() error {
|
||||
@ -6003,7 +6015,6 @@ func http2commaSeparatedTrailers(req *Request) (string, error) {
|
||||
}
|
||||
if len(keys) > 0 {
|
||||
sort.Strings(keys)
|
||||
|
||||
return strings.Join(keys, ","), nil
|
||||
}
|
||||
return "", nil
|
||||
|
@ -400,10 +400,12 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
|
||||
if p == 0 {
|
||||
return nil
|
||||
}
|
||||
// p can be just about anywhere in the address
|
||||
// space, including before arena_end.
|
||||
if p == h.arena_end {
|
||||
h.arena_end = new_end
|
||||
h.arena_reserved = reserved
|
||||
} else if h.arena_start <= p && p+p_size-h.arena_start-1 <= _MaxArena32 {
|
||||
} else if h.arena_end < p && p+p_size-h.arena_start-1 <= _MaxArena32 {
|
||||
// Keep everything page-aligned.
|
||||
// Our pages are bigger than hardware pages.
|
||||
h.arena_end = p + p_size
|
||||
@ -413,6 +415,16 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
|
||||
h.arena_used = used
|
||||
h.arena_reserved = reserved
|
||||
} else {
|
||||
// We got a mapping, but it's not
|
||||
// linear with our current arena, so
|
||||
// we can't use it.
|
||||
//
|
||||
// TODO: Make it possible to allocate
|
||||
// from this. We can't decrease
|
||||
// arena_used, but we could introduce
|
||||
// a new variable for the current
|
||||
// allocation position.
|
||||
|
||||
// We haven't added this allocation to
|
||||
// the stats, so subtract it from a
|
||||
// fake stat (but avoid underflow).
|
||||
|
@ -374,6 +374,7 @@ func heapBitsForAddr(addr uintptr) heapBits {
|
||||
// heapBitsForSpan returns the heapBits for the span base address base.
|
||||
func heapBitsForSpan(base uintptr) (hbits heapBits) {
|
||||
if base < mheap_.arena_start || base >= mheap_.arena_used {
|
||||
print("runtime: base ", hex(base), " not in range [", hex(mheap_.arena_start), ",", hex(mheap_.arena_used), ")\n")
|
||||
throw("heapBitsForSpan: base out of range")
|
||||
}
|
||||
return heapBitsForAddr(base)
|
||||
|
@ -1918,7 +1918,7 @@ func gchelper() {
|
||||
traceGCScanDone()
|
||||
}
|
||||
|
||||
nproc := work.nproc // work.nproc can change right after we increment work.ndone
|
||||
nproc := atomic.Load(&work.nproc) // work.nproc can change right after we increment work.ndone
|
||||
if atomic.Xadd(&work.ndone, +1) == nproc-1 {
|
||||
notewakeup(&work.alldone)
|
||||
}
|
||||
|
@ -98,15 +98,18 @@ TEXT runtime·usleep(SB),NOSPLIT,$8
|
||||
MOVL $1000000, CX
|
||||
DIVL CX
|
||||
MOVL AX, 0(SP)
|
||||
MOVL $1000, AX // usec to nsec
|
||||
MULL DX
|
||||
MOVL DX, 4(SP)
|
||||
|
||||
// select(0, 0, 0, 0, &tv)
|
||||
MOVL $142, AX
|
||||
// pselect6(0, 0, 0, 0, &ts, 0)
|
||||
MOVL $308, AX
|
||||
MOVL $0, BX
|
||||
MOVL $0, CX
|
||||
MOVL $0, DX
|
||||
MOVL $0, SI
|
||||
LEAL 0(SP), DI
|
||||
MOVL $0, BP
|
||||
INVOKE_SYSCALL
|
||||
RET
|
||||
|
||||
|
@ -82,15 +82,18 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
|
||||
MOVL $1000000, CX
|
||||
DIVL CX
|
||||
MOVQ AX, 0(SP)
|
||||
MOVQ DX, 8(SP)
|
||||
MOVL $1000, AX // usec to nsec
|
||||
MULL DX
|
||||
MOVQ AX, 8(SP)
|
||||
|
||||
// select(0, 0, 0, 0, &tv)
|
||||
// pselect6(0, 0, 0, 0, &ts, 0)
|
||||
MOVL $0, DI
|
||||
MOVL $0, SI
|
||||
MOVL $0, DX
|
||||
MOVL $0, R10
|
||||
MOVQ SP, R8
|
||||
MOVL $23, AX
|
||||
MOVL $0, R9
|
||||
MOVL $270, AX
|
||||
SYSCALL
|
||||
RET
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
||||
#define SYS_gettid (SYS_BASE + 224)
|
||||
#define SYS_tkill (SYS_BASE + 238)
|
||||
#define SYS_sched_yield (SYS_BASE + 158)
|
||||
#define SYS_select (SYS_BASE + 142) // newselect
|
||||
#define SYS_pselect6 (SYS_BASE + 335)
|
||||
#define SYS_ugetrlimit (SYS_BASE + 191)
|
||||
#define SYS_sched_getaffinity (SYS_BASE + 242)
|
||||
#define SYS_clock_gettime (SYS_BASE + 263)
|
||||
@ -387,13 +387,16 @@ TEXT runtime·usleep(SB),NOSPLIT,$12
|
||||
MOVW usec+0(FP), R0
|
||||
CALL runtime·usplitR0(SB)
|
||||
MOVW R0, 4(R13)
|
||||
MOVW $1000, R0 // usec to nsec
|
||||
MUL R0, R1
|
||||
MOVW R1, 8(R13)
|
||||
MOVW $0, R0
|
||||
MOVW $0, R1
|
||||
MOVW $0, R2
|
||||
MOVW $0, R3
|
||||
MOVW $4(R13), R4
|
||||
MOVW $SYS_select, R7
|
||||
MOVW $0, R5
|
||||
MOVW $SYS_pselect6, R7
|
||||
SWI $0
|
||||
RET
|
||||
|
||||
|
32
test/fixedbugs/issue20029.go
Normal file
32
test/fixedbugs/issue20029.go
Normal file
@ -0,0 +1,32 @@
|
||||
// run
|
||||
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Issue 20029: make sure we zero at VARKILLs of
|
||||
// ambiguously live variables.
|
||||
// The ambiguously live variable here is the hiter
|
||||
// for the inner range loop.
|
||||
|
||||
package main
|
||||
|
||||
import "runtime"
|
||||
|
||||
func f(m map[int]int) {
|
||||
outer:
|
||||
for i := 0; i < 10; i++ {
|
||||
for k := range m {
|
||||
if k == 5 {
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
runtime.GC()
|
||||
break
|
||||
}
|
||||
runtime.GC()
|
||||
}
|
||||
func main() {
|
||||
m := map[int]int{1: 2, 2: 3, 3: 4}
|
||||
f(m)
|
||||
}
|
18
test/fixedbugs/issue20097.go
Normal file
18
test/fixedbugs/issue20097.go
Normal file
@ -0,0 +1,18 @@
|
||||
// compile
|
||||
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Issue 20097: ensure that we CSE multiple Select ops with
|
||||
// the same underlying type
|
||||
|
||||
package main
|
||||
|
||||
type T int64
|
||||
|
||||
func f(x, y int64) (int64, T) {
|
||||
a := x / y
|
||||
b := T(x) / T(y)
|
||||
return a, b
|
||||
}
|
19
test/fixedbugs/issue20335.go
Normal file
19
test/fixedbugs/issue20335.go
Normal file
@ -0,0 +1,19 @@
|
||||
// compile
|
||||
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Issue 20335: don't reorder loads with stores.
|
||||
// This test should fail on the ssacheck builder
|
||||
// without the fix in the CL that added this file.
|
||||
// TODO: check the generated assembly?
|
||||
|
||||
package a
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
func f(p, q *int32) bool {
|
||||
x := *q
|
||||
return atomic.AddInt32(p, 1) == x
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user