// make sure assembly output has matching offset and base register.
`
func f72(a, b int) int {
- var x [16]byte // use some frame
- _ = x
+ //go:noinline
+ func() {_, _ = a, b} () // use some frame
return b
}
`,
[]string{"b\\+40\\(SP\\)"},
},
+ {
+ // check that stack store is optimized away
+ `
+ func $() int {
+ var x int
+ return *(&x)
+ }
+ `,
+ []string{"TEXT\t.*, [$]0-8"},
+ },
}
var linux386Tests = []*asmTest{
}`,
[]string{"\tADDL\t[$]19", "\tIMULL"}, // (n+19)*a
},
+ {
+ // check that stack store is optimized away
+ `
+ func $() int {
+ var x int
+ return *(&x)
+ }
+ `,
+ []string{"TEXT\t.*, [$]0-4"},
+ },
}
var linuxS390XTests = []*asmTest{
`,
[]string{"\tFLOGR\t"},
},
+ {
+ // check that stack store is optimized away
+ `
+ func $() int {
+ var x int
+ return *(&x)
+ }
+ `,
+ []string{"TEXT\t.*, [$]0-8"},
+ },
}
var linuxARMTests = []*asmTest{
// make sure assembly output has matching offset and base register.
`
func f13(a, b int) int {
- var x [16]byte // use some frame
- _ = x
+ //go:noinline
+ func() {_, _ = a, b} () // use some frame
return b
}
`,
[]string{"b\\+4\\(FP\\)"},
},
+ {
+ // check that stack store is optimized away
+ `
+ func $() int {
+ var x int
+ return *(&x)
+ }
+ `,
+ []string{"TEXT\t.*, [$]-4-4"},
+ },
}
var linuxARM64Tests = []*asmTest{
`,
[]string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(FP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(FP\\)"},
},
+ {
+ // check that stack store is optimized away
+ `
+ func $() int {
+ var x int
+ return *(&x)
+ }
+ `,
+ []string{"TEXT\t.*, [$]-8-8"},
+ },
}
var linuxMIPSTests = []*asmTest{
`,
[]string{"\tCLZ\t"},
},
+ {
+ // check that stack store is optimized away
+ `
+ func $() int {
+ var x int
+ return *(&x)
+ }
+ `,
+ []string{"TEXT\t.*, [$]-4-4"},
+ },
}
var linuxPPC64LETests = []*asmTest{
`,
[]string{"\tROTL\t"},
},
+ {
+ // check that stack store is optimized away
+ `
+ func $() int {
+ var x int
+ return *(&x)
+ }
+ `,
+ []string{"TEXT\t.*, [$]0-8"},
+ },
}
// TestLineNumber checks to make sure the generated assembly has line numbers
return n, ssa.SymWrite
case ssa.OpVarLive:
- return v.Aux.(*Node), ssa.SymRead
+ switch a := v.Aux.(type) {
+ case *ssa.ArgSymbol:
+ return a.Node.(*Node), ssa.SymRead
+ case *ssa.AutoSymbol:
+ return a.Node.(*Node), ssa.SymRead
+ default:
+ Fatalf("unknown VarLive aux type: %s", v.LongString())
+ }
case ssa.OpVarDef, ssa.OpVarKill:
return v.Aux.(*Node), ssa.SymWrite
case ssa.OpKeepAlive:
if !n.Left.Addrtaken() {
s.Fatalf("VARLIVE variable %v must have Addrtaken set", n.Left)
}
- s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, n.Left, s.mem())
+ var aux interface{}
+ switch n.Left.Class() {
+ case PAUTO:
+ aux = s.lookupSymbol(n.Left, &ssa.AutoSymbol{Node: n.Left})
+ case PPARAM, PPARAMOUT:
+ aux = s.lookupSymbol(n.Left, &ssa.ArgSymbol{Node: n.Left})
+ default:
+ s.Fatalf("VARLIVE variable %v must be Auto or Arg", n.Left)
+ }
+ s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, aux, s.mem())
case OCHECKNIL:
p := s.expr(n.Left)
{name: "tighten", fn: tighten}, // move values closer to their uses
{name: "lower", fn: lower, required: true},
{name: "lowered cse", fn: cse},
+ {name: "elim unread autos", fn: elimUnreadAutos},
{name: "lowered deadcode", fn: deadcode, required: true},
{name: "checkLower", fn: checkLower, required: true},
{name: "late phielim", fn: phielim},
}
}
}
+
+// elimUnreadAutos deletes stores to autos that are never read from.
+func elimUnreadAutos(f *Func) {
+ // Loop over all ops that affect autos taking note of which
+ // autos we need and also stores that we might be able to
+ // eliminate.
+ seen := make(map[GCNode]bool)
+ var stores []*Value
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ var sym *AutoSymbol
+ sym, ok := v.Aux.(*AutoSymbol)
+ if !ok {
+ continue
+ }
+
+ effect := v.Op.SymEffect()
+ switch effect {
+ case SymWrite:
+ // If we haven't seen the auto yet
+ // then this might be a store we can
+ // eliminate.
+ if !seen[sym.Node] {
+ stores = append(stores, v)
+ }
+ default:
+ // Assume the auto is needed (loaded,
+ // has its address taken, etc.).
+ // Note we have to check the uses
+ // because dead loads haven't been
+ // eliminated yet.
+ if v.Uses > 0 {
+ seen[sym.Node] = true
+ }
+ }
+ }
+ }
+
+ // Eliminate stores to unread autos.
+ for _, store := range stores {
+ sym, _ := store.Aux.(*AutoSymbol)
+ if seen[sym.Node] {
+ continue
+ }
+
+ // replace store with OpCopy
+ store.SetArgs1(store.MemoryArg())
+ store.Aux = nil
+ store.AuxInt = 0
+ store.Op = OpCopy
+ }
+}
slicevar := make([]string, 0, 16)
slicevar = append(slicevar, mapvar["abc"])
fmt.Println("hi") // line 13
- _ = ptrvar
+ runtime.KeepAlive(ptrvar)
gslice = slicevar
runtime.KeepAlive(mapvar)
}
func g14() string
-func f15() {
- var x string
- _ = &x
- x = g15() // ERROR "live at call to g15: x$"
- printstring(x) // ERROR "live at call to printstring: x$"
-}
-
-func g15() string
-
// Checking that various temporaries do not persist or cause
// ambiguously live values that must be zeroed.
// The exact temporary names are inconsequential but we are
return
}
var x string
- _ = &x
- x = g15() // ERROR "live at call to g15: x$"
- printstring(x) // ERROR "live at call to printstring: x$"
-} // ERROR "live at call to deferreturn: x$"
+ x = g14()
+ printstring(x)
+}
func g25()
m map[int]int
}
+//go:noescape
+func useT40(*T40)
+
func newT40() *T40 {
ret := T40{}
ret.m = make(map[int]int) // ERROR "live at call to makemap: &ret$"
ret.m = make(map[int]int) // ERROR "live at call to makemap: .autotmp_[0-9]+ ret$"
t := &ret
printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ ret$"
- _ = t
+ useT40(t) // ERROR "live at call to useT40: .autotmp_[0-9]+ ret$"
}
func ddd1(x, y *int) { // ERROR "live at entry to ddd1: x y$"
func printnl()
+//go:noescape
+func useT40(*T40)
+
type T40 struct {
m map[int]int
}
func bad40() {
t := newT40() // ERROR "live at call to makemap: .autotmp_[0-9]+ ret$"
printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ ret$"
- _ = t
+ useT40(t) // ERROR "live at call to useT40: .autotmp_[0-9]+ ret$"
}
func good40() {
ret.m = make(map[int]int) // ERROR "live at call to makemap: .autotmp_[0-9]+ ret$"
t := &ret
printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ ret$"
- _ = t
+ useT40(t) // ERROR "live at call to useT40: .autotmp_[0-9]+ ret$"
}