diff --git a/src/cmd/compile/internal/ppc64/ggen.go b/src/cmd/compile/internal/ppc64/ggen.go index 173e2f0c6c2..195f2b0f66b 100644 --- a/src/cmd/compile/internal/ppc64/ggen.go +++ b/src/cmd/compile/internal/ppc64/ggen.go @@ -71,10 +71,7 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog { for i := int64(0); i < cnt; i += int64(gc.Widthptr) { p = appendpp(p, ppc64.AMOVD, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGSP, 8+frame+lo+i) } - // TODO(dfc): https://golang.org/issue/12108 - // If DUFFZERO is used inside a tail call (see genwrapper) it will - // overwrite the link register. - } else if false && cnt <= int64(128*gc.Widthptr) { + } else if cnt <= int64(128*gc.Widthptr) { p = appendpp(p, ppc64.AADD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, ppc64.REGRT1, 0) p.Reg = ppc64.REGSP p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0) @@ -443,10 +440,7 @@ func clearfat(nl *gc.Node) { // The loop leaves R3 on the last zeroed dword boff = 8 - // TODO(dfc): https://golang.org/issue/12108 - // If DUFFZERO is used inside a tail call (see genwrapper) it will - // overwrite the link register. - } else if false && q >= 4 { + } else if q >= 4 { p := gins(ppc64.ASUB, nil, &dst) p.From.Type = obj.TYPE_CONST p.From.Offset = 8 diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go index 1eddc6fc6cb..d609f98502a 100644 --- a/src/cmd/internal/obj/ppc64/obj9.go +++ b/src/cmd/internal/obj/ppc64/obj9.go @@ -473,18 +473,19 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) { break } - if p.To.Sym != nil { // retjmp - p.As = ABR - p.To.Type = obj.TYPE_BRANCH - break - } + retTarget := p.To.Sym if cursym.Text.Mark&LEAF != 0 { if autosize == 0 { p.As = ABR p.From = obj.Addr{} - p.To.Type = obj.TYPE_REG - p.To.Reg = REG_LR + if retTarget == nil { + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_LR + } else { + p.To.Type = obj.TYPE_BRANCH + p.To.Sym = retTarget + } p.Mark |= BRANCH break } @@ -562,14 +563,18 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) { q1 = ctxt.NewProg() q1.As = ABR q1.Lineno = p.Lineno - q1.To.Type = obj.TYPE_REG - q1.To.Reg = REG_LR + if retTarget == nil { + q1.To.Type = obj.TYPE_REG + q1.To.Reg = REG_LR + } else { + q1.To.Type = obj.TYPE_BRANCH + q1.To.Sym = retTarget + } q1.Mark |= BRANCH q1.Spadj = +autosize q1.Link = q.Link q.Link = q1 - case AADD: if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { p.Spadj = int32(-p.From.Offset) diff --git a/test/fixedbugs/issue12108.go b/test/fixedbugs/issue12108.go new file mode 100644 index 00000000000..c7a742513af --- /dev/null +++ b/test/fixedbugs/issue12108.go @@ -0,0 +1,37 @@ +// 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. + +// A generated method with a return value large enough to be +// initialized by duffzero is not a leaf method, which violated +// assumptions made by cmd/internal/obj/ppc64. + +package main + +const N = 9 // values > 8 cause (Super).Method to use duffzero + +type Base struct { +} + +func (b *Base) Method() (x [N]uintptr) { + return +} + +type Super struct { + Base +} + +type T interface { + Method() [N]uintptr +} + +func f(q T) { + q.Method() +} + +func main() { + var s Super + f(&s) +}