From b89d211ff44c654667a49741522c93488920e6ac Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 12 Dec 2018 00:02:22 -0800 Subject: [PATCH] examples/complex: and bugfixes --- examples/add/add.s | 6 +++--- examples/add/add_test.go | 5 ++++- examples/add/asm.go | 2 +- examples/complex/asm.go | 32 ++++++++++++++++++++++++++++ examples/complex/complex.s | 23 ++++++++++++++++++++ examples/complex/complex_test.go | 36 ++++++++++++++++++++++++++++++++ examples/complex/stub.go | 5 +++++ examples/sum/sum.s | 12 +++++------ examples/sum/sum_test.go | 19 +++++++++-------- gotypes/components.go | 35 +++++++++++++++++++++++++++++++ pass/alloc.go | 25 ++++++++++++---------- pass/reg.go | 13 +++++++++--- 12 files changed, 179 insertions(+), 34 deletions(-) create mode 100644 examples/complex/asm.go create mode 100644 examples/complex/complex.s create mode 100644 examples/complex/complex_test.go create mode 100644 examples/complex/stub.go diff --git a/examples/add/add.s b/examples/add/add.s index 82520ba..e2ceb12 100644 --- a/examples/add/add.s +++ b/examples/add/add.s @@ -3,8 +3,8 @@ // func Add(x uint64, y uint64) uint64 TEXT ·Add(SB),0,$0-24 - MOVQ x(FP), CX - MOVQ y+8(FP), AX - ADDQ CX, AX + MOVQ x(FP), AX + MOVQ y+8(FP), CX + ADDQ AX, CX MOVQ CX, ret+16(FP) RET diff --git a/examples/add/add_test.go b/examples/add/add_test.go index 6252306..9c50b46 100644 --- a/examples/add/add_test.go +++ b/examples/add/add_test.go @@ -8,5 +8,8 @@ import ( //go:generate go run asm.go -out add.s -stubs stub.go func TestAdd(t *testing.T) { - quick.CheckEqual(Add, func(x, y uint64) uint64 { return x + y }, nil) + expect := func(x, y uint64) uint64 { return x + y } + if err := quick.CheckEqual(Add, expect, nil); err != nil { + t.Fatal(err) + } } diff --git a/examples/add/asm.go b/examples/add/asm.go index 4505854..07c0f98 100644 --- a/examples/add/asm.go +++ b/examples/add/asm.go @@ -11,7 +11,7 @@ func main() { x := Load(Param("x"), GP64v()) y := Load(Param("y"), GP64v()) ADDQ(x, y) - Store(x, ReturnIndex(0)) + Store(y, ReturnIndex(0)) RET() Generate() } diff --git a/examples/complex/asm.go b/examples/complex/asm.go new file mode 100644 index 0000000..f57ad1f --- /dev/null +++ b/examples/complex/asm.go @@ -0,0 +1,32 @@ +// +build ignore + +package main + +import ( + . "github.com/mmcloughlin/avo/build" +) + +func main() { + TEXT("Real", "func(x complex128) float64") + r := Load(Param("x").Real(), Xv()) + Store(r, ReturnIndex(0)) + RET() + + TEXT("Imag", "func(x complex128) float64") + i := Load(Param("x").Imag(), Xv()) + Store(i, ReturnIndex(0)) + RET() + + TEXT("Norm", "func(x complex128) float64") + r = Load(Param("x").Real(), Xv()) + i = Load(Param("x").Imag(), Xv()) + MULSD(r, r) + MULSD(i, i) + ADDSD(i, r) + n := Xv() + SQRTSD(r, n) + Store(n, ReturnIndex(0)) + RET() + + Generate() +} diff --git a/examples/complex/complex.s b/examples/complex/complex.s new file mode 100644 index 0000000..7296085 --- /dev/null +++ b/examples/complex/complex.s @@ -0,0 +1,23 @@ + +#include "textflag.h" + +// func Real(x complex128) float64 +TEXT ·Real(SB),0,$0-24 + MOVSD x_real(FP), X0 + MOVSD X0, ret+16(FP) + RET +// func Imag(x complex128) float64 +TEXT ·Imag(SB),0,$0-24 + MOVSD x_imag+8(FP), X0 + MOVSD X0, ret+16(FP) + RET +// func Norm(x complex128) float64 +TEXT ·Norm(SB),0,$0-24 + MOVSD x_real(FP), X0 + MOVSD x_imag+8(FP), X1 + MULSD X0, X0 + MULSD X1, X1 + ADDSD X1, X0 + SQRTSD X0, X2 + MOVSD X2, ret+16(FP) + RET diff --git a/examples/complex/complex_test.go b/examples/complex/complex_test.go new file mode 100644 index 0000000..572c831 --- /dev/null +++ b/examples/complex/complex_test.go @@ -0,0 +1,36 @@ +package complex + +import ( + "math" + "testing" + "testing/quick" +) + +//go:generate go run asm.go -out complex.s -stubs stub.go + +func TestReal(t *testing.T) { + expect := func(x complex128) float64 { + return real(x) + } + if err := quick.CheckEqual(Real, expect, nil); err != nil { + t.Fatal(err) + } +} + +func TestImag(t *testing.T) { + expect := func(x complex128) float64 { + return imag(x) + } + if err := quick.CheckEqual(Imag, expect, nil); err != nil { + t.Fatal(err) + } +} + +func TestNorm(t *testing.T) { + expect := func(x complex128) float64 { + return math.Sqrt(real(x)*real(x) + imag(x)*imag(x)) + } + if err := quick.CheckEqual(Norm, expect, nil); err != nil { + t.Fatal(err) + } +} diff --git a/examples/complex/stub.go b/examples/complex/stub.go new file mode 100644 index 0000000..aac8dfe --- /dev/null +++ b/examples/complex/stub.go @@ -0,0 +1,5 @@ +package complex + +func Real(x complex128) float64 +func Imag(x complex128) float64 +func Norm(x complex128) float64 diff --git a/examples/sum/sum.s b/examples/sum/sum.s index 7bbe334..82945d1 100644 --- a/examples/sum/sum.s +++ b/examples/sum/sum.s @@ -4,15 +4,15 @@ // func Sum(xs []uint64) uint64 TEXT ·Sum(SB),0,$0-32 MOVQ xs_base(FP), DX - MOVQ xs_len+8(FP), CX - XORQ AX, AX + MOVQ xs_len+8(FP), AX + XORQ CX, CX loop: - CMPQ CX, $0x0 + CMPQ AX, $0x0 JE done - ADDQ (DX), AX + ADDQ (DX), CX ADDQ $0x8, DX - DECQ CX + DECQ AX JMP loop done: - MOVQ AX, ret+24(FP) + MOVQ CX, ret+24(FP) RET diff --git a/examples/sum/sum_test.go b/examples/sum/sum_test.go index 6178198..6ea0610 100644 --- a/examples/sum/sum_test.go +++ b/examples/sum/sum_test.go @@ -7,14 +7,15 @@ import ( //go:generate go run asm.go -out sum.s -stubs stub.go -func expect(xs []uint64) uint64 { - var s uint64 - for _, x := range xs { - s += x - } - return s -} - func TestSum(t *testing.T) { - quick.CheckEqual(Sum, expect, nil) + expect := func(xs []uint64) uint64 { + var s uint64 + for _, x := range xs { + s += x + } + return s + } + if err := quick.CheckEqual(Sum, expect, nil); err != nil { + t.Fatal(err) + } } diff --git a/gotypes/components.go b/gotypes/components.go index 6362134..25c394f 100644 --- a/gotypes/components.go +++ b/gotypes/components.go @@ -21,6 +21,8 @@ type Component interface { Base() Component Len() Component Cap() Component + Real() Component + Imag() Component Index(int) Component } @@ -31,6 +33,8 @@ func (c componenterr) Resolve() (*Basic, error) { return nil, c } func (c componenterr) Base() Component { return c } func (c componenterr) Len() Component { return c } func (c componenterr) Cap() Component { return c } +func (c componenterr) Real() Component { return c } +func (c componenterr) Imag() Component { return c } func (c componenterr) Index(int) Component { return c } type component struct { @@ -96,6 +100,22 @@ func (c *component) Cap() Component { return c.sub("_cap", int(slicehdroffsets[2]), types.Typ[types.Int]) } +func (c *component) Real() Component { + if !iscomplex(c.typ) { + return componenterr("only complex types have real values") + } + f := complextofloat(c.typ) + return c.sub("_real", 0, f) +} + +func (c *component) Imag() Component { + if !iscomplex(c.typ) { + return componenterr("only complex types have imaginary values") + } + f := complextofloat(c.typ) + return c.sub("_imag", int(Sizes.Sizeof(f)), f) +} + func (c *component) Index(i int) Component { a, ok := c.typ.(*types.Array) if !ok { @@ -146,6 +166,21 @@ func isstring(t types.Type) bool { return ok && b.Kind() == types.String } +func iscomplex(t types.Type) bool { + b, ok := t.(*types.Basic) + return ok && (b.Info()&types.IsComplex) != 0 +} + +func complextofloat(t types.Type) types.Type { + switch Sizes.Sizeof(t) { + case 16: + return types.Typ[types.Float64] + case 8: + return types.Typ[types.Float32] + } + panic("bad") +} + // isprimitive returns true if the type cannot be broken into components. func isprimitive(t types.Type) bool { b, ok := t.(*types.Basic) diff --git a/pass/alloc.go b/pass/alloc.go index ab88b9f..b5170a5 100644 --- a/pass/alloc.go +++ b/pass/alloc.go @@ -46,11 +46,23 @@ func (a *Allocator) AddInterferenceSet(r reg.Register, s reg.Set) { } func (a *Allocator) AddInterference(x, y reg.Register) { - a.add(x) - a.add(y) + a.Add(x) + a.Add(y) a.edges = append(a.edges, &edge{X: x, Y: y}) } +// Add adds a register to be allocated. Does nothing if the register has already been added. +func (a *Allocator) Add(r reg.Register) { + v, ok := r.(reg.Virtual) + if !ok { + return + } + if _, found := a.possible[v]; found { + return + } + a.possible[v] = a.registersofsize(v.Bytes()) +} + func (a *Allocator) Allocate() (reg.Allocation, error) { for a.remaining() > 0 { if err := a.update(); err != nil { @@ -65,15 +77,6 @@ func (a *Allocator) Allocate() (reg.Allocation, error) { return a.allocation, nil } -// add adds a register. -func (a *Allocator) add(r reg.Register) { - v, ok := r.(reg.Virtual) - if !ok { - return - } - a.possible[v] = a.registersofsize(v.Bytes()) -} - // update possible allocations based on edges. func (a *Allocator) update() error { var rem []*edge diff --git a/pass/reg.go b/pass/reg.go index e0e6f17..853fa6e 100644 --- a/pass/reg.go +++ b/pass/reg.go @@ -57,11 +57,11 @@ func Liveness(fn *avo.Function) error { } func AllocateRegisters(fn *avo.Function) error { - // Build one allocator per register kind and record register interferences. + // Populate allocators (one per kind). as := map[reg.Kind]*Allocator{} for _, i := range fn.Instructions() { - for _, d := range i.OutputRegisters() { - k := d.Kind() + for _, r := range i.Registers() { + k := r.Kind() if _, found := as[k]; !found { a, err := NewAllocatorForKind(k) if err != nil { @@ -69,7 +69,14 @@ func AllocateRegisters(fn *avo.Function) error { } as[k] = a } + as[k].Add(r) + } + } + // Record register interferences. + for _, i := range fn.Instructions() { + for _, d := range i.OutputRegisters() { + k := d.Kind() out := i.LiveOut.OfKind(k) out.Discard(d) as[k].AddInterferenceSet(d, out)