Commit a6fb2aed authored by Gerrit Code Review's avatar Gerrit Code Review

Merge "Merge branch 'dev.ssa' into mergebranch"

parents 998aaf8a 9d854fd4
......@@ -127,6 +127,9 @@ var amd64OperandTests = []operandTest{
{"(SI)(BX*1)", "(SI)(BX*1)"},
{"(SI)(DX*1)", "(SI)(DX*1)"},
{"(SP)", "(SP)"},
{"(SP)(AX*4)", "(SP)(AX*4)"},
{"32(SP)(BX*2)", "32(SP)(BX*2)"},
{"32323(SP)(R8*4)", "32323(SP)(R8*4)"},
{"+3(PC)", "3(PC)"},
{"-1(DI)(BX*1)", "-1(DI)(BX*1)"},
{"-3(PC)", "-3(PC)"},
......
......@@ -127,5 +127,19 @@ loop:
MOVNTDQ X1, (AX) // MOVNTO X1, (AX)
MOVOA (AX), X1 // MOVO (AX), X1
// Tests for SP indexed addresses.
MOVQ foo(SP)(AX*1), BX // 488b1c04
MOVQ foo+32(SP)(CX*2), DX // 488b544c20
MOVQ foo+32323(SP)(R8*4), R9 // 4e8b8c84437e0000
MOVL foo(SP)(SI*8), DI // 8b3cf4
MOVL foo+32(SP)(R10*1), R11 // 468b5c1420
MOVL foo+32323(SP)(R12*2), R13 // 468bac64437e0000
MOVW foo(SP)(AX*4), R8 // 66448b0484
MOVW foo+32(SP)(R9*8), CX // 66428b4ccc20
MOVW foo+32323(SP)(AX*1), DX // 668b9404437e0000
MOVB foo(SP)(AX*2), AL // 8a0444
MOVB foo+32(SP)(CX*4), AH // 8a648c20
MOVB foo+32323(SP)(CX*8), R9 // 448a8ccc437e0000
// LTYPE0 nonnon { outcode($1, &$2); }
RET // c3
......@@ -3,5 +3,6 @@
// license that can be found in the LICENSE file.
TEXT errors(SB),$0
MOVL foo<>(SB)(AX), AX // ERROR "invalid instruction"
MOVL foo<>(SB)(AX), AX // ERROR "invalid instruction"
MOVL (AX)(SP*1), AX // ERROR "invalid instruction"
RET
......@@ -458,6 +458,7 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) {
}
fmt.Fprint(fgo2, "\n")
fmt.Fprint(fgo2, "//go:cgo_unsafe_args\n")
conf.Fprint(fgo2, fset, d)
fmt.Fprint(fgo2, " {\n")
......
......@@ -117,6 +117,7 @@ var progtable = [x86.ALAST]obj.ProgInfo{
x86.AJPL: {Flags: gc.Cjmp | gc.UseCarry},
x86.AJPS: {Flags: gc.Cjmp | gc.UseCarry},
obj.AJMP: {Flags: gc.Jump | gc.Break | gc.KillCarry},
x86.ALEAW: {Flags: gc.LeftAddr | gc.RightWrite},
x86.ALEAL: {Flags: gc.LeftAddr | gc.RightWrite},
x86.ALEAQ: {Flags: gc.LeftAddr | gc.RightWrite},
x86.AMOVBLSX: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
......@@ -167,6 +168,7 @@ var progtable = [x86.ALAST]obj.ProgInfo{
x86.AORW: {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
x86.APOPQ: {Flags: gc.SizeQ | gc.RightWrite},
x86.APUSHQ: {Flags: gc.SizeQ | gc.LeftRead},
x86.APXOR: {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
x86.ARCLB: {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
x86.ARCLL: {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
x86.ARCLQ: {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
......
......@@ -588,6 +588,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
ptr.Ullman = 1
ptr.Used = true
ptr.Name.Curfn = xfunc
ptr.Xoffset = 0
xfunc.Func.Dcl = append(xfunc.Func.Dcl, ptr)
var body []*Node
if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) {
......
......@@ -403,6 +403,7 @@ var etnames = []string{
TFORW: "FORW",
TFIELD: "FIELD",
TSTRING: "STRING",
TUNSAFEPTR: "TUNSAFEPTR",
TANY: "ANY",
}
......
......@@ -142,6 +142,8 @@ func newlab(n *Node) *Label {
return lab
}
// There is a copy of checkgoto in the new SSA backend.
// Please keep them in sync.
func checkgoto(from *Node, to *Node) {
if from.Sym == to.Sym {
return
......@@ -840,7 +842,7 @@ func gen(n *Node) {
cgen_dcl(n.Left)
case OAS:
if gen_as_init(n) {
if gen_as_init(n, false) {
break
}
Cgen_as(n.Left, n.Right)
......
......@@ -131,7 +131,7 @@ type Type struct {
Note *string // literal string annotation
// TARRAY
Bound int64 // negative is dynamic array
Bound int64 // negative is slice
// TMAP
Bucket *Type // internal type representing a hash bucket
......@@ -759,4 +759,13 @@ var Panicindex *Node
var panicslice *Node
var panicdivide *Node
var throwreturn *Node
var growslice *Node
var writebarrierptr *Node
var typedmemmove *Node
var panicdottype *Node
......@@ -530,6 +530,16 @@ func newplist() *obj.Plist {
return pl
}
// nodarg does something that depends on the value of
// fp (this was previously completely undocumented).
//
// fp=1 corresponds to input args
// fp=0 corresponds to output args
// fp=-1 is a special case of output args for a
// specific call from walk that previously (and
// incorrectly) passed a 1; the behavior is exactly
// the same as it is for 1, except that PARAMOUT is
// generated instead of PARAM.
func nodarg(t *Type, fp int) *Node {
var n *Node
......@@ -555,7 +565,7 @@ func nodarg(t *Type, fp int) *Node {
Fatalf("nodarg: not field %v", t)
}
if fp == 1 {
if fp == 1 || fp == -1 {
for _, n := range Curfn.Func.Dcl {
if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym {
return n
......@@ -592,6 +602,9 @@ fp:
case 1: // input arg
n.Class = PPARAM
case -1: // output arg from paramstoheap
n.Class = PPARAMOUT
case 2: // offset output arg
Fatalf("shouldn't be used")
}
......
......@@ -33,10 +33,10 @@ func renameinit() *Sym {
// hand-craft the following initialization code
// var initdone· uint8 (1)
// func init() (2)
// if initdone· != 0 { (3)
// if initdone· == 2 (4)
// return
// throw(); (5)
// if initdone· > 1 { (3)
// return (3a)
// if initdone· == 1 { (4)
// throw(); (4a)
// }
// initdone· = 1; (6)
// // over all matching imported symbols
......@@ -118,22 +118,21 @@ func fninit(n *NodeList) {
// (3)
a := Nod(OIF, nil, nil)
a.Left = Nod(ONE, gatevar, Nodintconst(0))
a.Left = Nod(OGT, gatevar, Nodintconst(1))
a.Likely = 1
r = append(r, a)
// (3a)
a.Nbody.Set([]*Node{Nod(ORETURN, nil, nil)})
// (4)
b := Nod(OIF, nil, nil)
b.Left = Nod(OEQ, gatevar, Nodintconst(2))
b.Nbody.Set([]*Node{Nod(ORETURN, nil, nil)})
a.Nbody.Set([]*Node{b})
// (5)
b = syslook("throwinit", 0)
b = Nod(OCALL, b, nil)
a.Nbody.Append(b)
b.Left = Nod(OEQ, gatevar, Nodintconst(1))
// this actually isn't likely, but code layout is better
// like this: no JMP needed after the call.
b.Likely = 1
r = append(r, b)
// (4a)
b.Nbody.Set([]*Node{Nod(OCALL, syslook("throwinit", 0), nil)})
// (6)
a = Nod(OAS, gatevar, Nodintconst(1))
......
......@@ -7,6 +7,7 @@
package gc
import (
"cmd/compile/internal/ssa"
"cmd/internal/obj"
"flag"
"fmt"
......@@ -286,6 +287,23 @@ func Main() {
}
}
}
// special case for ssa for now
if strings.HasPrefix(name, "ssa/") {
// expect form ssa/phase/flag
// e.g. -d=ssa/generic_cse/time
// _ in phase name also matches space
phase := name[4:]
flag := "debug" // default flag is debug
if i := strings.Index(phase, "/"); i >= 0 {
flag = phase[i+1:]
phase = phase[:i]
}
err := ssa.PhaseOption(phase, flag, val)
if err != "" {
log.Fatalf(err)
}
continue Split
}
log.Fatalf("unknown debug key -d %s\n", name)
}
}
......@@ -844,7 +862,7 @@ func plan9quote(s string) string {
return s
}
type Pragma uint8
type Pragma uint16
const (
Nointerface Pragma = 1 << iota
......@@ -855,6 +873,7 @@ const (
Systemstack // func must run on system stack
Nowritebarrier // emit compiler error instead of write barrier
Nowritebarrierrec // error on write barrier in this or recursive callees
CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all
)
type lexer struct {
......@@ -1677,6 +1696,8 @@ func (l *lexer) getlinepragma() rune {
Yyerror("//go:nowritebarrierrec only allowed in runtime")
}
l.pragma |= Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
case "go:cgo_unsafe_args":
l.pragma |= CgoUnsafeArgs
}
return c
}
......
......@@ -160,5 +160,9 @@ var opnames = []string{
OLROT: "LROT",
ORROTC: "RROTC",
ORETJMP: "RETJMP",
OPS: "OPS",
OPC: "OPC",
OSQRT: "OSQRT",
OGETG: "OGETG",
OEND: "END",
}
......@@ -230,6 +230,7 @@ func cleantempnopop(mark ordermarker, order *Order, out *[]*Node) {
n := order.temp[i]
if n.Name.Keepalive {
n.Name.Keepalive = false
n.Addrtaken = true // ensure SSA keeps the n variable
kill = Nod(OVARLIVE, n, nil)
typecheck(&kill, Etop)
*out = append(*out, kill)
......
......@@ -5,6 +5,7 @@
package gc
import (
"cmd/compile/internal/ssa"
"cmd/internal/obj"
"crypto/md5"
"fmt"
......@@ -341,7 +342,12 @@ func compile(fn *Node) {
Deferreturn = Sysfunc("deferreturn")
Panicindex = Sysfunc("panicindex")
panicslice = Sysfunc("panicslice")
panicdivide = Sysfunc("panicdivide")
throwreturn = Sysfunc("throwreturn")
growslice = Sysfunc("growslice")
writebarrierptr = Sysfunc("writebarrierptr")
typedmemmove = Sysfunc("typedmemmove")
panicdottype = Sysfunc("panicdottype")
}
lno := setlineno(fn)
......@@ -358,6 +364,7 @@ func compile(fn *Node) {
var nam *Node
var gcargs *Sym
var gclocals *Sym
var ssafn *ssa.Func
if len(fn.Nbody.Slice()) == 0 {
if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
......@@ -409,6 +416,11 @@ func compile(fn *Node) {
goto ret
}
// Build an SSA backend function.
if shouldssa(Curfn) {
ssafn = buildssa(Curfn)
}
continpc = nil
breakpc = nil
......@@ -471,6 +483,14 @@ func compile(fn *Node) {
}
}
if ssafn != nil {
genssa(ssafn, ptxt, gcargs, gclocals)
if Curfn.Func.Endlineno != 0 {
lineno = Curfn.Func.Endlineno
}
ssafn.Free()
return
}
Genslice(Curfn.Func.Enter.Slice())
Genslice(Curfn.Nbody.Slice())
gclean()
......
......@@ -19,6 +19,7 @@ import (
"cmd/internal/obj"
"fmt"
"sort"
"strings"
)
const (
......@@ -410,7 +411,7 @@ func newcfg(firstp *obj.Prog) []*BasicBlock {
bb := newblock(firstp)
cfg = append(cfg, bb)
for p := firstp; p != nil; p = p.Link {
for p := firstp; p != nil && p.As != obj.AEND; p = p.Link {
Thearch.Proginfo(p)
if p.To.Type == obj.TYPE_BRANCH {
if p.To.Val == nil {
......@@ -438,7 +439,7 @@ func newcfg(firstp *obj.Prog) []*BasicBlock {
// contained instructions until a label is reached. Add edges
// for branches and fall-through instructions.
for _, bb := range cfg {
for p := bb.last; p != nil; p = p.Link {
for p := bb.last; p != nil && p.As != obj.AEND; p = p.Link {
if p.Opt != nil && p != bb.last {
break
}
......@@ -447,6 +448,8 @@ func newcfg(firstp *obj.Prog) []*BasicBlock {
// Stop before an unreachable RET, to avoid creating
// unreachable control flow nodes.
if p.Link != nil && p.Link.As == obj.ARET && p.Link.Mode == 1 {
// TODO: remove after SSA is done. SSA does not
// generate any unreachable RET instructions.
break
}
......@@ -1364,7 +1367,7 @@ func livenessepilogue(lv *Liveness) {
}
n = lv.vars[j]
if n.Class != PPARAM {
yyerrorl(int(p.Lineno), "internal error: %v %v recorded as live on entry", Curfn.Func.Nname, Nconv(n, obj.FmtLong))
yyerrorl(int(p.Lineno), "internal error: %v %v recorded as live on entry, p.Pc=%v", Curfn.Func.Nname, Nconv(n, obj.FmtLong), p.Pc)
}
}
}
......@@ -1389,8 +1392,13 @@ func livenessepilogue(lv *Liveness) {
if msg != nil {
fmt_ = ""
fmt_ += fmt.Sprintf("%v: live at ", p.Line())
if p.As == obj.ACALL && p.To.Node != nil {
fmt_ += fmt.Sprintf("call to %s:", ((p.To.Node).(*Node)).Sym.Name)
if p.As == obj.ACALL && p.To.Sym != nil {
name := p.To.Sym.Name
i := strings.Index(name, ".")
if i >= 0 {
name = name[i+1:]
}
fmt_ += fmt.Sprintf("call to %s:", name)
} else if p.As == obj.ACALL {
fmt_ += "indirect call:"
} else {
......
......@@ -13,7 +13,7 @@ import (
//
// For flag_race it modifies the function as follows:
//
// 1. It inserts a call to racefuncenter at the beginning of each function.
// 1. It inserts a call to racefuncenterfp at the beginning of each function.
// 2. It inserts a call to racefuncexit at the end of each function.
// 3. It inserts a call to raceread before each memory read.
// 4. It inserts a call to racewrite before each memory write.
......@@ -33,7 +33,7 @@ import (
// at best instrumentation would cause infinite recursion.
var omit_pkgs = []string{"runtime/internal/atomic", "runtime/internal/sys", "runtime", "runtime/race", "runtime/msan"}
// Only insert racefuncenter/racefuncexit into the following packages.
// Only insert racefuncenterfp/racefuncexit into the following packages.
// Memory accesses in the packages are either uninteresting or will cause false positives.
var norace_inst_pkgs = []string{"sync", "sync/atomic"}
......
......@@ -55,8 +55,7 @@ const (
func makefield(name string, t *Type) *Type {
f := typ(TFIELD)
f.Type = t
f.Sym = new(Sym)
f.Sym.Name = name
f.Sym = nopkg.Lookup(name)
return f
}
......
......@@ -1209,6 +1209,7 @@ func getlit(lit *Node) int {
return -1
}
// stataddr sets nam to the static address of n and reports whether it succeeeded.
func stataddr(nam *Node, n *Node) bool {
if n == nil {
return false
......@@ -1376,7 +1377,9 @@ func entry(p *InitPlan) *InitEntry {
return &p.E[len(p.E)-1]
}
func gen_as_init(n *Node) bool {
// gen_as_init attempts to emit static data for n and reports whether it succeeded.
// If reportOnly is true, it does not emit static data and does not modify the AST.
func gen_as_init(n *Node, reportOnly bool) bool {
var nr *Node
var nl *Node
var nam Node
......@@ -1425,7 +1428,6 @@ func gen_as_init(n *Node) bool {
case OSLICEARR:
if nr.Right.Op == OKEY && nr.Right.Left == nil && nr.Right.Right == nil {
nr = nr.Left
gused(nil) // in case the data is the dest of a goto
nl := nr
if nr == nil || nr.Op != OADDR {
goto no
......@@ -1440,16 +1442,18 @@ func gen_as_init(n *Node) bool {
goto no
}
nam.Xoffset += int64(Array_array)
gdata(&nam, nl, int(Types[Tptr].Width))
if !reportOnly {
nam.Xoffset += int64(Array_array)
gdata(&nam, nl, int(Types[Tptr].Width))
nam.Xoffset += int64(Array_nel) - int64(Array_array)
var nod1 Node
Nodconst(&nod1, Types[TINT], nr.Type.Bound)
gdata(&nam, &nod1, Widthint)
nam.Xoffset += int64(Array_nel) - int64(Array_array)
var nod1 Node
Nodconst(&nod1, Types[TINT], nr.Type.Bound)
gdata(&nam, &nod1, Widthint)
nam.Xoffset += int64(Array_cap) - int64(Array_nel)
gdata(&nam, &nod1, Widthint)
nam.Xoffset += int64(Array_cap) - int64(Array_nel)
gdata(&nam, &nod1, Widthint)
}
return true
}
......@@ -1480,13 +1484,19 @@ func gen_as_init(n *Node) bool {
TPTR64,
TFLOAT32,
TFLOAT64:
gdata(&nam, nr, int(nr.Type.Width))
if !reportOnly {
gdata(&nam, nr, int(nr.Type.Width))
}
case TCOMPLEX64, TCOMPLEX128:
gdatacomplex(&nam, nr.Val().U.(*Mpcplx))
if !reportOnly {
gdatacomplex(&nam, nr.Val().U.(*Mpcplx))
}
case TSTRING:
gdatastring(&nam, nr.Val().U.(string))
if !reportOnly {
gdatastring(&nam, nr.Val().U.(string))
}
}
return true
......
This diff is collapsed.
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gc
import (
"bytes"
"internal/testenv"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
)
// TODO: move all these tests elsewhere?
// Perhaps teach test/run.go how to run them with a new action verb.
func runTest(t *testing.T, filename string) {
doTest(t, filename, "run")
}
func buildTest(t *testing.T, filename string) {
doTest(t, filename, "build")
}
func doTest(t *testing.T, filename string, kind string) {
if runtime.GOARCH != "amd64" {
t.Skipf("skipping SSA tests on %s for now", runtime.GOARCH)
}
testenv.MustHaveGoBuild(t)
var stdout, stderr bytes.Buffer
cmd := exec.Command("go", kind, filepath.Join("testdata", filename))
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
t.Fatalf("Failed: %v:\nOut: %s\nStderr: %s\n", err, &stdout, &stderr)
}
if s := stdout.String(); s != "" {
t.Errorf("Stdout = %s\nWant empty", s)
}
if s := stderr.String(); strings.Contains(s, "SSA unimplemented") {
t.Errorf("Unimplemented message found in stderr:\n%s", s)
}
}
// TestShortCircuit tests OANDAND and OOROR expressions and short circuiting.
func TestShortCircuit(t *testing.T) { runTest(t, "short_ssa.go") }
// TestBreakContinue tests that continue and break statements do what they say.
func TestBreakContinue(t *testing.T) { runTest(t, "break_ssa.go") }
// TestTypeAssertion tests type assertions.
func TestTypeAssertion(t *testing.T) { runTest(t, "assert_ssa.go") }
// TestArithmetic tests that both backends have the same result for arithmetic expressions.
func TestArithmetic(t *testing.T) { runTest(t, "arith_ssa.go") }
// TestFP tests that both backends have the same result for floating point expressions.
func TestFP(t *testing.T) { runTest(t, "fp_ssa.go") }
// TestArithmeticBoundary tests boundary results for arithmetic operations.
func TestArithmeticBoundary(t *testing.T) { runTest(t, "arithBoundary_ssa.go") }
// TestArithmeticConst tests results for arithmetic operations against constants.
func TestArithmeticConst(t *testing.T) { runTest(t, "arithConst_ssa.go") }
func TestChan(t *testing.T) { runTest(t, "chan_ssa.go") }
func TestCompound(t *testing.T) { runTest(t, "compound_ssa.go") }
func TestCtl(t *testing.T) { runTest(t, "ctl_ssa.go") }
func TestFp(t *testing.T) { runTest(t, "fp_ssa.go") }
func TestLoadStore(t *testing.T) { runTest(t, "loadstore_ssa.go") }
func TestMap(t *testing.T) { runTest(t, "map_ssa.go") }
func TestRegalloc(t *testing.T) { runTest(t, "regalloc_ssa.go") }
func TestString(t *testing.T) { runTest(t, "string_ssa.go") }
func TestDeferNoReturn(t *testing.T) { buildTest(t, "deferNoReturn_ssa.go") }
// TestClosure tests closure related behavior.
func TestClosure(t *testing.T) { runTest(t, "closure_ssa.go") }
func TestArray(t *testing.T) { runTest(t, "array_ssa.go") }
func TestAppend(t *testing.T) { runTest(t, "append_ssa.go") }
func TestZero(t *testing.T) { runTest(t, "zero_ssa.go") }
func TestAddressed(t *testing.T) { runTest(t, "addressed_ssa.go") }
func TestCopy(t *testing.T) { runTest(t, "copy_ssa.go") }
func TestUnsafe(t *testing.T) { runTest(t, "unsafe_ssa.go") }
func TestPhi(t *testing.T) { runTest(t, "phi_ssa.go") }
......@@ -149,7 +149,7 @@ type Param struct {
// Func holds Node fields used only with function-like nodes.
type Func struct {
Shortname *Node
Enter Nodes
Enter Nodes // for example, allocate and initialize memory for escaping parameters
Exit Nodes
Cvars Nodes // closure params
Dcl []*Node // autodcl for this func/closure
......
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "fmt"
var output string
func mypanic(s string) {
fmt.Printf(output)
panic(s)
}
func assertEqual(x, y int) {
if x != y {
mypanic("assertEqual failed")
}
}
func main() {
x := f1_ssa(2, 3)
output += fmt.Sprintln("*x is", *x)
output += fmt.Sprintln("Gratuitously use some stack")
output += fmt.Sprintln("*x is", *x)
assertEqual(*x, 9)
w := f3a_ssa(6)
output += fmt.Sprintln("*w is", *w)
output += fmt.Sprintln("Gratuitously use some stack")
output += fmt.Sprintln("*w is", *w)
assertEqual(*w, 6)
y := f3b_ssa(12)
output += fmt.Sprintln("*y.(*int) is", *y.(*int))
output += fmt.Sprintln("Gratuitously use some stack")
output += fmt.Sprintln("*y.(*int) is", *y.(*int))
assertEqual(*y.(*int), 12)
z := f3c_ssa(8)
output += fmt.Sprintln("*z.(*int) is", *z.(*int))
output += fmt.Sprintln("Gratuitously use some stack")
output += fmt.Sprintln("*z.(*int) is", *z.(*int))
assertEqual(*z.(*int), 8)
args()
test_autos()
}
func f1_ssa(x, y int) *int {
switch {
} //go:noinline
x = x*y + y
return &x
}
func f3a_ssa(x int) *int {
switch {
} //go:noinline
return &x
}
func f3b_ssa(x int) interface{} { // ./foo.go:15: internal error: f3b_ssa ~r1 (type interface {}) recorded as live on entry
switch {
} //go:noinline
return &x
}
func f3c_ssa(y int) interface{} {
switch {
} //go:noinline
x := y
return &x
}
type V struct {
p *V
w, x int64
}
func args() {
v := V{p: nil, w: 1, x: 1}
a := V{p: &v, w: 2, x: 2}
b := V{p: &v, w: 0, x: 0}
i := v.args_ssa(a, b)
output += fmt.Sprintln("i=", i)
assertEqual(int(i), 2)
}
func (v V) args_ssa(a, b V) int64 {
switch {
} //go:noinline
if v.w == 0 {
return v.x
}
if v.w == 1 {
return a.x
}
if v.w == 2 {
return b.x
}
b.p.p = &a // v.p in caller = &a
return -1
}
func test_autos() {
test(11)
test(12)
test(13)
test(21)
test(22)
test(23)
test(31)
test(32)
}
func test(which int64) {
output += fmt.Sprintln("test", which)
v1 := V{w: 30, x: 3, p: nil}
v2, v3 := v1.autos_ssa(which, 10, 1, 20, 2)
if which != v2.val() {
output += fmt.Sprintln("Expected which=", which, "got v2.val()=", v2.val())
mypanic("Failure of expected V value")
}
if v2.p.val() != v3.val() {
output += fmt.Sprintln("Expected v2.p.val()=", v2.p.val(), "got v3.val()=", v3.val())
mypanic("Failure of expected V.p value")
}
if which != v3.p.p.p.p.p.p.p.val() {
output += fmt.Sprintln("Expected which=", which, "got v3.p.p.p.p.p.p.p.val()=", v3.p.p.p.p.p.p.p.val())
mypanic("Failure of expected V.p value")
}
}
func (v V) val() int64 {
return v.w + v.x
}
// autos_ssa uses contents of v and parameters w1, w2, x1, x2
// to initialize a bunch of locals, all of which have their
// address taken to force heap allocation, and then based on
// the value of which a pair of those locals are copied in
// various ways to the two results y, and z, which are also
// addressed. Which is expected to be one of 11-13, 21-23, 31, 32,
// and y.val() should be equal to which and y.p.val() should
// be equal to z.val(). Also, x(.p)**8 == x; that is, the
// autos are all linked into a ring.
func (v V) autos_ssa(which, w1, x1, w2, x2 int64) (y, z V) {
switch {
} //go:noinline
fill_ssa(v.w, v.x, &v, v.p) // gratuitous no-op to force addressing
var a, b, c, d, e, f, g, h V
fill_ssa(w1, x1, &a, &b)
fill_ssa(w1, x2, &b, &c)
fill_ssa(w1, v.x, &c, &d)
fill_ssa(w2, x1, &d, &e)
fill_ssa(w2, x2, &e, &f)
fill_ssa(w2, v.x, &f, &g)
fill_ssa(v.w, x1, &g, &h)
fill_ssa(v.w, x2, &h, &a)
switch which {
case 11:
y = a
z.getsI(&b)
case 12:
y.gets(&b)
z = c
case 13:
y.gets(&c)
z = d
case 21:
y.getsI(&d)
z.gets(&e)
case 22:
y = e
z = f
case 23:
y.gets(&f)
z.getsI(&g)
case 31:
y = g
z.gets(&h)
case 32:
y.getsI(&h)
z = a
default:
panic("")
}
return
}
// gets is an address-mentioning way of implementing
// structure assignment.
func (to *V) gets(from *V) {
switch {
} //go:noinline
*to = *from
}
// gets is an address-and-interface-mentioning way of
// implementing structure assignment.
func (to *V) getsI(from interface{}) {
switch {
} //go:noinline
*to = *from.(*V)
}
// fill_ssa initializes r with V{w:w, x:x, p:p}
func fill_ssa(w, x int64, r, p *V) {
switch {
} //go:noinline
*r = V{w: w, x: x, p: p}
}
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// append_ssa.go tests append operations.
package main
import "fmt"
var failed = false
//go:noinline
func appendOne_ssa(a []int, x int) []int {
return append(a, x)
}
//go:noinline
func appendThree_ssa(a []int, x, y, z int) []int {
return append(a, x, y, z)
}
func eq(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
func expect(got, want []int) {
if eq(got, want) {
return
}
fmt.Printf("expected %v, got %v\n", want, got)
failed = true
}
func testAppend() {
var store [7]int
a := store[:0]
a = appendOne_ssa(a, 1)
expect(a, []int{1})
a = appendThree_ssa(a, 2, 3, 4)
expect(a, []int{1, 2, 3, 4})
a = appendThree_ssa(a, 5, 6, 7)
expect(a, []int{1, 2, 3, 4, 5, 6, 7})
if &a[0] != &store[0] {
fmt.Println("unnecessary grow")
failed = true
}
a = appendOne_ssa(a, 8)
expect(a, []int{1, 2, 3, 4, 5, 6, 7, 8})
if &a[0] == &store[0] {
fmt.Println("didn't grow")
failed = true
}
}
func main() {
testAppend()
if failed {
panic("failed")
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
package main
var failed = false
//go:noinline
func testSliceLenCap12_ssa(a [10]int, i, j int) (int, int) {
b := a[i:j]
return len(b), cap(b)
}
//go:noinline
func testSliceLenCap1_ssa(a [10]int, i, j int) (int, int) {
b := a[i:]
return len(b), cap(b)
}
//go:noinline
func testSliceLenCap2_ssa(a [10]int, i, j int) (int, int) {
b := a[:j]
return len(b), cap(b)
}
func testSliceLenCap() {
a := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
tests := [...]struct {
fn func(a [10]int, i, j int) (int, int)
i, j int // slice range
l, c int // len, cap
}{
// -1 means the value is not used.
{testSliceLenCap12_ssa, 0, 0, 0, 10},
{testSliceLenCap12_ssa, 0, 1, 1, 10},
{testSliceLenCap12_ssa, 0, 10, 10, 10},
{testSliceLenCap12_ssa, 10, 10, 0, 0},
{testSliceLenCap12_ssa, 0, 5, 5, 10},
{testSliceLenCap12_ssa, 5, 5, 0, 5},
{testSliceLenCap12_ssa, 5, 10, 5, 5},
{testSliceLenCap1_ssa, 0, -1, 0, 10},
{testSliceLenCap1_ssa, 5, -1, 5, 5},
{testSliceLenCap1_ssa, 10, -1, 0, 0},
{testSliceLenCap2_ssa, -1, 0, 0, 10},
{testSliceLenCap2_ssa, -1, 5, 5, 10},
{testSliceLenCap2_ssa, -1, 10, 10, 10},
}
for i, t := range tests {
if l, c := t.fn(a, t.i, t.j); l != t.l && c != t.c {
println("#", i, " len(a[", t.i, ":", t.j, "]), cap(a[", t.i, ":", t.j, "]) =", l, c,
", want", t.l, t.c)
failed = true
}
}
}
//go:noinline
func testSliceGetElement_ssa(a [10]int, i, j, p int) int {
return a[i:j][p]
}
func testSliceGetElement() {
a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90}
tests := [...]struct {
i, j, p int
want int // a[i:j][p]
}{
{0, 10, 2, 20},
{0, 5, 4, 40},
{5, 10, 3, 80},
{1, 9, 7, 80},
}
for i, t := range tests {
if got := testSliceGetElement_ssa(a, t.i, t.j, t.p); got != t.want {
println("#", i, " a[", t.i, ":", t.j, "][", t.p, "] = ", got, " wanted ", t.want)
failed = true
}
}
}
//go:noinline
func testSliceSetElement_ssa(a *[10]int, i, j, p, x int) {
(*a)[i:j][p] = x
}
func testSliceSetElement() {
a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90}
tests := [...]struct {
i, j, p int
want int // a[i:j][p]
}{
{0, 10, 2, 17},
{0, 5, 4, 11},
{5, 10, 3, 28},
{1, 9, 7, 99},
}
for i, t := range tests {
testSliceSetElement_ssa(&a, t.i, t.j, t.p, t.want)
if got := a[t.i+t.p]; got != t.want {
println("#", i, " a[", t.i, ":", t.j, "][", t.p, "] = ", got, " wanted ", t.want)
failed = true
}
}
}
func testSlicePanic1() {
defer func() {
if r := recover(); r != nil {
println("paniced as expected")
}
}()
a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90}
testSliceLenCap12_ssa(a, 3, 12)
println("expected to panic, but didn't")
failed = true
}
func testSlicePanic2() {
defer func() {
if r := recover(); r != nil {
println("paniced as expected")
}
}()
a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90}
testSliceGetElement_ssa(a, 3, 7, 4)
println("expected to panic, but didn't")
failed = true
}
func main() {
testSliceLenCap()
testSliceGetElement()
testSliceSetElement()
testSlicePanic1()
testSlicePanic2()
if failed {
panic("failed")
}
}
// run
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Tests type assertion expressions and statements
package main
import (
"fmt"
"runtime"
)
type (
S struct{}
T struct{}
I interface {
F()
}
)
var (
s *S
t *T
)
func (s *S) F() {}
func (t *T) F() {}
func e2t_ssa(e interface{}) *T {
return e.(*T)
}
func i2t_ssa(i I) *T {
return i.(*T)
}
func testAssertE2TOk() {
if got := e2t_ssa(t); got != t {
fmt.Printf("e2t_ssa(t)=%v want %v", got, t)
failed = true
}
}
func testAssertE2TPanic() {
var got *T
defer func() {
if got != nil {
fmt.Printf("e2t_ssa(s)=%v want nil", got)
failed = true
}
e := recover()
err, ok := e.(*runtime.TypeAssertionError)
if !ok {
fmt.Printf("e2t_ssa(s) panic type %T", e)
failed = true
}
want := "interface conversion: interface {} is *main.S, not *main.T"
if err.Error() != want {
fmt.Printf("e2t_ssa(s) wrong error, want '%s', got '%s'\n", want, err.Error())
failed = true
}
}()
got = e2t_ssa(s)
fmt.Printf("e2t_ssa(s) should panic")
failed = true
}
func testAssertI2TOk() {
if got := i2t_ssa(t); got != t {
fmt.Printf("i2t_ssa(t)=%v want %v", got, t)
failed = true
}
}
func testAssertI2TPanic() {
var got *T
defer func() {
if got != nil {
fmt.Printf("i2t_ssa(s)=%v want nil", got)
failed = true
}
e := recover()
err, ok := e.(*runtime.TypeAssertionError)
if !ok {
fmt.Printf("i2t_ssa(s) panic type %T", e)
failed = true
}
want := "interface conversion: main.I is *main.S, not *main.T"
if err.Error() != want {
fmt.Printf("i2t_ssa(s) wrong error, want '%s', got '%s'\n", want, err.Error())
failed = true
}
}()
got = i2t_ssa(s)
fmt.Printf("i2t_ssa(s) should panic")
failed = true
}
func e2t2_ssa(e interface{}) (*T, bool) {
t, ok := e.(*T)
return t, ok
}
func i2t2_ssa(i I) (*T, bool) {
t, ok := i.(*T)
return t, ok
}
func testAssertE2T2() {
if got, ok := e2t2_ssa(t); !ok || got != t {
fmt.Printf("e2t2_ssa(t)=(%v, %v) want (%v, %v)", got, ok, t, true)
failed = true
}
if got, ok := e2t2_ssa(s); ok || got != nil {
fmt.Printf("e2t2_ssa(s)=(%v, %v) want (%v, %v)", got, ok, nil, false)
failed = true
}
}
func testAssertI2T2() {
if got, ok := i2t2_ssa(t); !ok || got != t {
fmt.Printf("i2t2_ssa(t)=(%v, %v) want (%v, %v)", got, ok, t, true)
failed = true
}
if got, ok := i2t2_ssa(s); ok || got != nil {
fmt.Printf("i2t2_ssa(s)=(%v, %v) want (%v, %v)", got, ok, nil, false)
failed = true
}
}
var failed = false
func main() {
testAssertE2TOk()
testAssertE2TPanic()
testAssertI2TOk()
testAssertI2TPanic()
testAssertE2T2()
testAssertI2T2()
if failed {
panic("failed")
}
}
// run
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Tests continue and break.
package main
func continuePlain_ssa() int {
var n int
for i := 0; i < 10; i++ {
if i == 6 {
continue
}
n = i
}
return n
}
func continueLabeled_ssa() int {
var n int
Next:
for i := 0; i < 10; i++ {
if i == 6 {
continue Next
}
n = i
}
return n
}
func continuePlainInner_ssa() int {
var n int
for j := 0; j < 30; j += 10 {
for i := 0; i < 10; i++ {
if i == 6 {
continue
}
n = i
}
n += j
}
return n
}
func continueLabeledInner_ssa() int {
var n int
for j := 0; j < 30; j += 10 {
Next:
for i := 0; i < 10; i++ {
if i == 6 {
continue Next
}
n = i
}
n += j
}
return n
}
func continueLabeledOuter_ssa() int {
var n int
Next:
for j := 0; j < 30; j += 10 {
for i := 0; i < 10; i++ {
if i == 6 {
continue Next
}
n = i
}
n += j
}
return n
}
func breakPlain_ssa() int {
var n int
for i := 0; i < 10; i++ {
if i == 6 {
break
}
n = i
}
return n
}
func breakLabeled_ssa() int {
var n int
Next:
for i := 0; i < 10; i++ {
if i == 6 {
break Next
}
n = i
}
return n
}
func breakPlainInner_ssa() int {
var n int
for j := 0; j < 30; j += 10 {
for i := 0; i < 10; i++ {
if i == 6 {
break
}
n = i
}
n += j
}
return n
}
func breakLabeledInner_ssa() int {
var n int
for j := 0; j < 30; j += 10 {
Next:
for i := 0; i < 10; i++ {
if i == 6 {
break Next
}
n = i
}
n += j
}
return n
}
func breakLabeledOuter_ssa() int {
var n int
Next:
for j := 0; j < 30; j += 10 {
for i := 0; i < 10; i++ {
if i == 6 {
break Next
}
n = i
}
n += j
}
return n
}
var g, h int // globals to ensure optimizations don't collapse our switch statements
func switchPlain_ssa() int {
var n int
switch g {
case 0:
n = 1
break
n = 2
}
return n
}
func switchLabeled_ssa() int {
var n int
Done:
switch g {
case 0:
n = 1
break Done
n = 2
}
return n
}
func switchPlainInner_ssa() int {
var n int
switch g {
case 0:
n = 1
switch h {
case 0:
n += 10
break
}
n = 2
}
return n
}
func switchLabeledInner_ssa() int {
var n int
switch g {
case 0:
n = 1
Done:
switch h {
case 0:
n += 10
break Done
}
n = 2
}
return n
}
func switchLabeledOuter_ssa() int {
var n int
Done:
switch g {
case 0:
n = 1
switch h {
case 0:
n += 10
break Done
}
n = 2
}
return n
}
func main() {
tests := [...]struct {
name string
fn func() int
want int
}{
{"continuePlain_ssa", continuePlain_ssa, 9},
{"continueLabeled_ssa", continueLabeled_ssa, 9},
{"continuePlainInner_ssa", continuePlainInner_ssa, 29},
{"continueLabeledInner_ssa", continueLabeledInner_ssa, 29},
{"continueLabeledOuter_ssa", continueLabeledOuter_ssa, 5},
{"breakPlain_ssa", breakPlain_ssa, 5},
{"breakLabeled_ssa", breakLabeled_ssa, 5},
{"breakPlainInner_ssa", breakPlainInner_ssa, 25},
{"breakLabeledInner_ssa", breakLabeledInner_ssa, 25},
{"breakLabeledOuter_ssa", breakLabeledOuter_ssa, 5},
{"switchPlain_ssa", switchPlain_ssa, 1},
{"switchLabeled_ssa", switchLabeled_ssa, 1},
{"switchPlainInner_ssa", switchPlainInner_ssa, 2},
{"switchLabeledInner_ssa", switchLabeledInner_ssa, 2},
{"switchLabeledOuter_ssa", switchLabeledOuter_ssa, 11},
// no select tests; they're identical to switch
}
var failed bool
for _, test := range tests {
if got := test.fn(); test.fn() != test.want {
print(test.name, "()=", got, ", want ", test.want, "\n")
failed = true
}
}
if failed {
panic("failed")
}
}
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// chan_ssa.go tests chan operations.
package main
import "fmt"
var failed = false
//go:noinline
func lenChan_ssa(v chan int) int {
return len(v)
}
//go:noinline
func capChan_ssa(v chan int) int {
return cap(v)
}
func testLenChan() {
v := make(chan int, 10)
v <- 1
v <- 1
v <- 1
if want, got := 3, lenChan_ssa(v); got != want {
fmt.Printf("expected len(chan) = %d, got %d", want, got)
failed = true
}
}
func testLenNilChan() {
var v chan int
if want, got := 0, lenChan_ssa(v); got != want {
fmt.Printf("expected len(nil) = %d, got %d", want, got)
failed = true
}
}
func testCapChan() {
v := make(chan int, 25)
if want, got := 25, capChan_ssa(v); got != want {
fmt.Printf("expected cap(chan) = %d, got %d", want, got)
failed = true
}
}
func testCapNilChan() {
var v chan int
if want, got := 0, capChan_ssa(v); got != want {
fmt.Printf("expected cap(nil) = %d, got %d", want, got)
failed = true
}
}
func main() {
testLenChan()
testLenNilChan()
testCapChan()
testCapNilChan()
if failed {
panic("failed")
}
}
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// map_ssa.go tests map operations.
package main
import "fmt"
var failed = false
//go:noinline
func testCFunc_ssa() int {
a := 0
b := func() {
switch {
}
a++
}
b()
b()
return a
}
func testCFunc() {
if want, got := 2, testCFunc_ssa(); got != want {
fmt.Printf("expected %d, got %d", want, got)
failed = true
}
}
func main() {
testCFunc()
if failed {
panic("failed")
}
}
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// cmp_ssa.go tests compare simplification operations.
package main
import "fmt"
var failed = false
//go:noinline
func eq_ssa(a int64) bool {
return 4+a == 10
}
//go:noinline
func neq_ssa(a int64) bool {
return 10 != a+4
}
func testCmp() {
if wanted, got := true, eq_ssa(6); wanted != got {
fmt.Printf("eq_ssa: expected %v, got %v\n", wanted, got)
failed = true
}
if wanted, got := false, eq_ssa(7); wanted != got {
fmt.Printf("eq_ssa: expected %v, got %v\n", wanted, got)
failed = true
}
if wanted, got := false, neq_ssa(6); wanted != got {
fmt.Printf("neq_ssa: expected %v, got %v\n", wanted, got)
failed = true
}
if wanted, got := true, neq_ssa(7); wanted != got {
fmt.Printf("neq_ssa: expected %v, got %v\n", wanted, got)
failed = true
}
}
func main() {
testCmp()
if failed {
panic("failed")
}
}
// run
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test compound objects
package main
import "fmt"
func string_ssa(a, b string, x bool) string {
s := ""
if x {
s = a
} else {
s = b
}
return s
}
func testString() {
a := "foo"
b := "barz"
if want, got := a, string_ssa(a, b, true); got != want {
fmt.Printf("string_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
failed = true
}
if want, got := b, string_ssa(a, b, false); got != want {
fmt.Printf("string_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want)
failed = true
}
}
func complex64_ssa(a, b complex64, x bool) complex64 {
switch {
}
var c complex64
if x {
c = a
} else {
c = b
}
return c
}
func complex128_ssa(a, b complex128, x bool) complex128 {
switch {
}
var c complex128
if x {
c = a
} else {
c = b
}
return c
}
func testComplex64() {
var a complex64 = 1 + 2i
var b complex64 = 3 + 4i
if want, got := a, complex64_ssa(a, b, true); got != want {
fmt.Printf("complex64_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
failed = true
}
if want, got := b, complex64_ssa(a, b, false); got != want {
fmt.Printf("complex64_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
failed = true
}
}
func testComplex128() {
var a complex128 = 1 + 2i
var b complex128 = 3 + 4i
if want, got := a, complex128_ssa(a, b, true); got != want {
fmt.Printf("complex128_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
failed = true
}
if want, got := b, complex128_ssa(a, b, false); got != want {
fmt.Printf("complex128_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
failed = true
}
}
func slice_ssa(a, b []byte, x bool) []byte {
var s []byte
if x {
s = a
} else {
s = b
}
return s
}
func testSlice() {
a := []byte{3, 4, 5}
b := []byte{7, 8, 9}
if want, got := byte(3), slice_ssa(a, b, true)[0]; got != want {
fmt.Printf("slice_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
failed = true
}
if want, got := byte(7), slice_ssa(a, b, false)[0]; got != want {
fmt.Printf("slice_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want)
failed = true
}
}
func interface_ssa(a, b interface{}, x bool) interface{} {
var s interface{}
if x {
s = a
} else {
s = b
}
return s
}
func testInterface() {
a := interface{}(3)
b := interface{}(4)
if want, got := 3, interface_ssa(a, b, true).(int); got != want {
fmt.Printf("interface_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
failed = true
}
if want, got := 4, interface_ssa(a, b, false).(int); got != want {
fmt.Printf("interface_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want)
failed = true
}
}
var failed = false
func main() {
testString()
testSlice()
testInterface()
testComplex64()
testComplex128()
if failed {
panic("failed")
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
// run
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test control flow
package main
// nor_ssa calculates NOR(a, b).
// It is implemented in a way that generates
// phi control values.
func nor_ssa(a, b bool) bool {
var c bool
if a {
c = true
}
if b {
c = true
}
if c {
return false
}
return true
}
func testPhiControl() {
tests := [...][3]bool{ // a, b, want
{false, false, true},
{true, false, false},
{false, true, false},
{true, true, false},
}
for _, test := range tests {
a, b := test[0], test[1]
got := nor_ssa(a, b)
want := test[2]
if want != got {
print("nor(", a, ", ", b, ")=", want, " got ", got, "\n")
failed = true
}
}
}
func emptyRange_ssa(b []byte) bool {
for _, x := range b {
_ = x
}
return true
}
func testEmptyRange() {
if !emptyRange_ssa([]byte{}) {
println("emptyRange_ssa([]byte{})=false, want true")
failed = true
}
}
func switch_ssa(a int) int {
ret := 0
switch a {
case 5:
ret += 5
case 4:
ret += 4
case 3:
ret += 3
case 2:
ret += 2
case 1:
ret += 1
}
return ret
}
func fallthrough_ssa(a int) int {
ret := 0
switch a {
case 5:
ret++
fallthrough
case 4:
ret++
fallthrough
case 3:
ret++
fallthrough
case 2:
ret++
fallthrough
case 1:
ret++
}
return ret
}
func testFallthrough() {
for i := 0; i < 6; i++ {
if got := fallthrough_ssa(i); got != i {
println("fallthrough_ssa(i) =", got, "wanted", i)
failed = true
}
}
}
func testSwitch() {
for i := 0; i < 6; i++ {
if got := switch_ssa(i); got != i {
println("switch_ssa(i) =", got, "wanted", i)
failed = true
}
}
}
type junk struct {
step int
}
// flagOverwrite_ssa is intended to reproduce an issue seen where a XOR
// was scheduled between a compare and branch, clearing flags.
func flagOverwrite_ssa(s *junk, c int) int {
switch {
}
if '0' <= c && c <= '9' {
s.step = 0
return 1
}
if c == 'e' || c == 'E' {
s.step = 0
return 2
}
s.step = 0
return 3
}
func testFlagOverwrite() {
j := junk{}
if got := flagOverwrite_ssa(&j, ' '); got != 3 {
println("flagOverwrite_ssa =", got, "wanted 3")
failed = true
}
}
var failed = false
func main() {
testPhiControl()
testEmptyRange()
testSwitch()
testFallthrough()
testFlagOverwrite()
if failed {
panic("failed")
}
}
// compile
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test that a defer in a function with no return
// statement will compile correctly.
package foo
func deferNoReturn_ssa() {
defer func() { println("returned") }()
for {
println("loop")
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"fmt"
"go/format"
"io/ioutil"
"log"
)
// This program generates tests to verify that copying operations
// copy the data they are supposed to and clobber no adjacent values.
// run as `go run copyGen.go`. A file called copy_ssa.go
// will be written into the parent directory containing the tests.
var sizes = [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 23, 24, 25, 31, 32, 33, 63, 64, 65, 1023, 1024, 1025, 1024 + 7, 1024 + 8, 1024 + 9, 1024 + 15, 1024 + 16, 1024 + 17}
func main() {
w := new(bytes.Buffer)
fmt.Fprintf(w, "// run\n")
fmt.Fprintf(w, "// autogenerated from gen/copyGen.go - do not edit!\n")
fmt.Fprintf(w, "package main\n")
fmt.Fprintf(w, "import \"fmt\"\n")
for _, s := range sizes {
// type for test
fmt.Fprintf(w, "type T%d struct {\n", s)
fmt.Fprintf(w, " pre [8]byte\n")
fmt.Fprintf(w, " mid [%d]byte\n", s)
fmt.Fprintf(w, " post [8]byte\n")
fmt.Fprintf(w, "}\n")
// function being tested
fmt.Fprintf(w, "func t%dcopy_ssa(y, x *[%d]byte) {\n", s, s)
fmt.Fprintf(w, " switch{}\n")
fmt.Fprintf(w, " *y = *x\n")
fmt.Fprintf(w, "}\n")
// testing harness
fmt.Fprintf(w, "func testCopy%d() {\n", s)
fmt.Fprintf(w, " a := T%d{[8]byte{201, 202, 203, 204, 205, 206, 207, 208},[%d]byte{", s, s)
for i := 0; i < s; i++ {
fmt.Fprintf(w, "%d,", i%100)
}
fmt.Fprintf(w, "},[8]byte{211, 212, 213, 214, 215, 216, 217, 218}}\n")
fmt.Fprintf(w, " x := [%d]byte{", s)
for i := 0; i < s; i++ {
fmt.Fprintf(w, "%d,", 100+i%100)
}
fmt.Fprintf(w, "}\n")
fmt.Fprintf(w, " t%dcopy_ssa(&a.mid, &x)\n", s)
fmt.Fprintf(w, " want := T%d{[8]byte{201, 202, 203, 204, 205, 206, 207, 208},[%d]byte{", s, s)
for i := 0; i < s; i++ {
fmt.Fprintf(w, "%d,", 100+i%100)
}
fmt.Fprintf(w, "},[8]byte{211, 212, 213, 214, 215, 216, 217, 218}}\n")
fmt.Fprintf(w, " if a != want {\n")
fmt.Fprintf(w, " fmt.Printf(\"t%dcopy got=%%v, want %%v\\n\", a, want)\n", s)
fmt.Fprintf(w, " failed=true\n")
fmt.Fprintf(w, " }\n")
fmt.Fprintf(w, "}\n")
}
// boilerplate at end
fmt.Fprintf(w, "var failed bool\n")
fmt.Fprintf(w, "func main() {\n")
for _, s := range sizes {
fmt.Fprintf(w, " testCopy%d()\n", s)
}
fmt.Fprintf(w, " if failed {\n")
fmt.Fprintf(w, " panic(\"failed\")\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("../copy_ssa.go", src, 0666)
if err != nil {
log.Fatalf("can't write output: %v\n", err)
}
}
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"fmt"
"go/format"
"io/ioutil"
"log"
)
// This program generates tests to verify that zeroing operations
// zero the data they are supposed to and clobber no adjacent values.
// run as `go run zeroGen.go`. A file called zero_ssa.go
// will be written into the parent directory containing the tests.
var sizes = [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 23, 24, 25, 31, 32, 33, 63, 64, 65, 1023, 1024, 1025}
func main() {
w := new(bytes.Buffer)
fmt.Fprintf(w, "// run\n")
fmt.Fprintf(w, "// autogenerated from gen/zeroGen.go - do not edit!\n")
fmt.Fprintf(w, "package main\n")
fmt.Fprintf(w, "import \"fmt\"\n")
for _, s := range sizes {
// type for test
fmt.Fprintf(w, "type T%d struct {\n", s)
fmt.Fprintf(w, " pre [8]byte\n")
fmt.Fprintf(w, " mid [%d]byte\n", s)
fmt.Fprintf(w, " post [8]byte\n")
fmt.Fprintf(w, "}\n")
// function being tested
fmt.Fprintf(w, "func zero%d_ssa(x *[%d]byte) {\n", s, s)
fmt.Fprintf(w, " switch{}\n")
fmt.Fprintf(w, " *x = [%d]byte{}\n", s)
fmt.Fprintf(w, "}\n")
// testing harness
fmt.Fprintf(w, "func testZero%d() {\n", s)
fmt.Fprintf(w, " a := T%d{[8]byte{255,255,255,255,255,255,255,255},[%d]byte{", s, s)
for i := 0; i < s; i++ {
fmt.Fprintf(w, "255,")
}
fmt.Fprintf(w, "},[8]byte{255,255,255,255,255,255,255,255}}\n")
fmt.Fprintf(w, " zero%d_ssa(&a.mid)\n", s)
fmt.Fprintf(w, " want := T%d{[8]byte{255,255,255,255,255,255,255,255},[%d]byte{", s, s)
for i := 0; i < s; i++ {
fmt.Fprintf(w, "0,")
}
fmt.Fprintf(w, "},[8]byte{255,255,255,255,255,255,255,255}}\n")
fmt.Fprintf(w, " if a != want {\n")
fmt.Fprintf(w, " fmt.Printf(\"zero%d got=%%v, want %%v\\n\", a, want)\n", s)
fmt.Fprintf(w, " failed=true\n")
fmt.Fprintf(w, " }\n")
fmt.Fprintf(w, "}\n")
}
// boilerplate at end
fmt.Fprintf(w, "var failed bool\n")
fmt.Fprintf(w, "func main() {\n")
for _, s := range sizes {
fmt.Fprintf(w, " testZero%d()\n", s)
}
fmt.Fprintf(w, " if failed {\n")
fmt.Fprintf(w, " panic(\"failed\")\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("../zero_ssa.go", src, 0666)
if err != nil {
log.Fatalf("can't write output: %v\n", err)
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -2566,7 +2566,7 @@ func paramstoheap(argin **Type, out int) []*Node {
// Defer might stop a panic and show the
// return values as they exist at the time of panic.
// Make sure to zero them on entry to the function.
nn = append(nn, Nod(OAS, nodarg(t, 1), nil))
nn = append(nn, Nod(OAS, nodarg(t, -1), nil))
}
if v == nil || v.Class&PHEAP == 0 {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
This package generates opcode tables, rewrite rules, etc. for the ssa compiler.
Run it with:
go run *.go
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ssa
// machine-independent optimization
func opt(f *Func) {
applyRewrite(f, rewriteBlockgeneric, rewriteValuegeneric)
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment