&& (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
-> (Move {t1} [s] dst src midmem)
+// Same, but for large types that require VarDefs.
+(Move {t1} [s] dst tmp1 midmem:(VarDef (Move {t2} [s] tmp2 src _)))
+ && t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq
+ && isSamePtr(tmp1, tmp2)
+ && isStackPtr(src)
+ && disjoint(src, s, tmp2, s)
+ && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
+ -> (Move {t1} [s] dst src midmem)
+
// Elide self-moves. This only happens rarely (e.g test/fixedbugs/bug277.go).
// However, this rule is needed to prevent the previous rule from looping forever in such cases.
(Move dst src mem) && isSamePtr(dst, src) -> mem
v.AddArg(midmem)
return true
}
+ // match: (Move {t1} [s] dst tmp1 midmem:(VarDef (Move {t2} [s] tmp2 src _)))
+ // cond: t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
+ // result: (Move {t1} [s] dst src midmem)
+ for {
+ s := v.AuxInt
+ t1 := v.Aux
+ _ = v.Args[2]
+ dst := v.Args[0]
+ tmp1 := v.Args[1]
+ midmem := v.Args[2]
+ if midmem.Op != OpVarDef {
+ break
+ }
+ midmem_0 := midmem.Args[0]
+ if midmem_0.Op != OpMove {
+ break
+ }
+ if midmem_0.AuxInt != s {
+ break
+ }
+ t2 := midmem_0.Aux
+ _ = midmem_0.Args[2]
+ tmp2 := midmem_0.Args[0]
+ src := midmem_0.Args[1]
+ if !(t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))) {
+ break
+ }
+ v.reset(OpMove)
+ v.AuxInt = s
+ v.Aux = t1
+ v.AddArg(dst)
+ v.AddArg(src)
+ v.AddArg(midmem)
+ return true
+ }
// match: (Move dst src mem)
// cond: isSamePtr(dst, src)
// result: mem
// We have a limit of 1GB for stack frames.
// Make sure we include the callee args section.
-// (The dispatch wrapper which implements (*S).f
-// copies the return value from f to a stack temp, then
-// from that stack temp to the return value of (*S).f.
-// It uses ~800MB for each section.)
package main
-type S struct {
- i interface {
- f() [800e6]byte
- }
+func f() { // ERROR "stack frame too large"
+ var x [800e6]byte
+ g(x)
+ return
}
+
+//go:noinline
+func g([800e6]byte) {}