diff --git a/examples/returns/asm.go b/examples/returns/asm.go new file mode 100644 index 0000000..a3b8623 --- /dev/null +++ b/examples/returns/asm.go @@ -0,0 +1,66 @@ +// +build ignore + +package main + +import ( + . "github.com/mmcloughlin/avo/build" + . "github.com/mmcloughlin/avo/operand" +) + +func main() { + Package("github.com/mmcloughlin/avo/examples/returns") + + // Multiple unnamed return values. + TEXT("Interval", "func(start, size uint64) (uint64, uint64)") + start := Load(Param("start"), GP64v()) + size := Load(Param("size"), GP64v()) + end := size + ADDQ(start, end) + Store(start, ReturnIndex(0)) + Store(end, ReturnIndex(1)) + RET() + + // Butterfly demonstrates multiple named return values. + TEXT("Butterfly", "func(x0, x1 float64) (y0, y1 float64)") + x0 := Load(Param("x0"), Xv()) + x1 := Load(Param("x1"), Xv()) + y0, y1 := Xv(), Xv() + MOVSD(x0, y0) + ADDSD(x1, y0) + MOVSD(x0, y1) + SUBSD(x1, y1) + Store(y0, Return("y0")) + Store(y1, Return("y1")) + RET() + + // Septuple returns an array of seven of the given byte. + TEXT("Septuple", "func(byte) [7]byte") + b := Load(ParamIndex(0), GP8v()) + for i := 0; i < 7; i++ { + Store(b, ReturnIndex(0).Index(i)) + } + RET() + + // CriticalLine returns the complex value 0.5 + it on Riemann's critical line. + TEXT("CriticalLine", "func(t float64) complex128") + t := Load(Param("t"), Xv()) + half := Xv() + MOVSD(ConstData("half", F64(0.5)), half) + Store(half, ReturnIndex(0).Real()) + Store(t, ReturnIndex(0).Imag()) + RET() + + // NewStruct initializes a Struct value. + TEXT("NewStruct", "func(w uint16, p [2]float64, q uint64) Struct") + w := Load(Param("w"), GP16v()) + x := Load(Param("p").Index(0), Xv()) + y := Load(Param("p").Index(1), Xv()) + q := Load(Param("q"), GP64v()) + Store(w, ReturnIndex(0).Field("Word")) + Store(x, ReturnIndex(0).Field("Point").Index(0)) + Store(y, ReturnIndex(0).Field("Point").Index(1)) + Store(q, ReturnIndex(0).Field("Quad")) + RET() + + Generate() +} diff --git a/examples/returns/returns.go b/examples/returns/returns.go new file mode 100644 index 0000000..dcfd52a --- /dev/null +++ b/examples/returns/returns.go @@ -0,0 +1,7 @@ +package returns + +type Struct struct { + Word uint16 + Point [2]float64 + Quad uint64 +} diff --git a/examples/returns/returns.s b/examples/returns/returns.s new file mode 100644 index 0000000..1d1c545 --- /dev/null +++ b/examples/returns/returns.s @@ -0,0 +1,59 @@ +// Code generated by command: go run asm.go -out returns.s -stubs stub.go. DO NOT EDIT. + +#include "textflag.h" + +// func Interval(start uint64, size uint64) (uint64, uint64) +TEXT ·Interval(SB), 0, $0-32 + MOVQ start(FP), AX + MOVQ size+8(FP), CX + ADDQ AX, CX + MOVQ AX, ret+16(FP) + MOVQ CX, ret1+24(FP) + RET + +// func Butterfly(x0 float64, x1 float64) (y0 float64, y1 float64) +TEXT ·Butterfly(SB), 0, $0-32 + MOVSD x0(FP), X0 + MOVSD x1+8(FP), X1 + MOVSD X0, X2 + ADDSD X1, X2 + MOVSD X0, X3 + SUBSD X1, X3 + MOVSD X2, y0+16(FP) + MOVSD X3, y1+24(FP) + RET + +// func Septuple(byte) [7]byte +TEXT ·Septuple(SB), 0, $0-15 + MOVB arg(FP), AL + MOVB AL, ret_0+8(FP) + MOVB AL, ret_1+9(FP) + MOVB AL, ret_2+10(FP) + MOVB AL, ret_3+11(FP) + MOVB AL, ret_4+12(FP) + MOVB AL, ret_5+13(FP) + MOVB AL, ret_6+14(FP) + RET + +// func CriticalLine(t float64) complex128 +TEXT ·CriticalLine(SB), 0, $0-24 + MOVSD t(FP), X0 + MOVSD half<>(SB), X1 + MOVSD X1, ret_real+8(FP) + MOVSD X0, ret_imag+16(FP) + RET + +DATA half<>(SB)/8, $(0.5) +GLOBL half<>(SB), RODATA, $8 + +// func NewStruct(w uint16, p [2]float64, q uint64) Struct +TEXT ·NewStruct(SB), 0, $0-64 + MOVW w(FP), AX + MOVSD p_0+8(FP), X0 + MOVSD p_1+16(FP), X1 + MOVQ q+24(FP), CX + MOVW AX, ret_Word+32(FP) + MOVSD X0, ret_Point_0+40(FP) + MOVSD X1, ret_Point_1+48(FP) + MOVQ CX, ret_Quad+56(FP) + RET diff --git a/examples/returns/returns_test.go b/examples/returns/returns_test.go new file mode 100644 index 0000000..ba06491 --- /dev/null +++ b/examples/returns/returns_test.go @@ -0,0 +1,25 @@ +package returns + +import ( + "testing" + "testing/quick" +) + +//go:generate go run asm.go -out returns.s -stubs stub.go + +func TestFunctionsEqual(t *testing.T) { + cases := []struct { + f, g interface{} + }{ + {Interval, func(s, n uint64) (uint64, uint64) { return s, s + n }}, + {Butterfly, func(x0, x1 float64) (float64, float64) { return x0 + x1, x0 - x1 }}, + {Septuple, func(b byte) [7]byte { return [...]byte{b, b, b, b, b, b, b} }}, + {CriticalLine, func(t float64) complex128 { return complex(0.5, t) }}, + {NewStruct, func(w uint16, p [2]float64, q uint64) Struct { return Struct{Word: w, Point: p, Quad: q} }}, + } + for _, c := range cases { + if err := quick.CheckEqual(c.f, c.g, nil); err != nil { + t.Fatal(err) + } + } +} diff --git a/examples/returns/stub.go b/examples/returns/stub.go new file mode 100644 index 0000000..6988403 --- /dev/null +++ b/examples/returns/stub.go @@ -0,0 +1,13 @@ +// Code generated by command: go run asm.go -out returns.s -stubs stub.go. DO NOT EDIT. + +package returns + +func Interval(start uint64, size uint64) (uint64, uint64) + +func Butterfly(x0 float64, x1 float64) (y0 float64, y1 float64) + +func Septuple(byte) [7]byte + +func CriticalLine(t float64) complex128 + +func NewStruct(w uint16, p [2]float64, q uint64) Struct diff --git a/gotypes/signature.go b/gotypes/signature.go index 667b717..fbb39b2 100644 --- a/gotypes/signature.go +++ b/gotypes/signature.go @@ -73,10 +73,13 @@ func (s *Signature) init() { // Result offsets. vs = tuplevars(r) resultsoffsets := Sizes.Offsetsof(vs) + var resultssize int64 + if n := len(vs); n > 0 { + resultssize = resultsoffsets[n-1] + Sizes.Sizeof(vs[n-1].Type()) + } for i := range resultsoffsets { resultsoffsets[i] += paramssize } - resultssize := Sizes.Sizeof(types.NewStruct(vs, nil)) s.results = newTuple(r, resultsoffsets, resultssize, "ret") } diff --git a/gotypes/signature_test.go b/gotypes/signature_test.go index eeec311..aa40051 100644 --- a/gotypes/signature_test.go +++ b/gotypes/signature_test.go @@ -102,6 +102,7 @@ func TestSignatureSizes(t *testing.T) { {"func()", 0}, {"func(uint64) uint64", 16}, {"func([7]byte) byte", 9}, + {"func(uint64, uint64) (uint64, uint64)", 32}, } for _, c := range cases { s, err := ParseSignature(c.Expr)