examples/complex: and bugfixes

This commit is contained in:
Michael McLoughlin
2018-12-12 00:02:22 -08:00
parent 2189d38d1e
commit b89d211ff4
12 changed files with 179 additions and 34 deletions

View File

@@ -3,8 +3,8 @@
// func Add(x uint64, y uint64) uint64 // func Add(x uint64, y uint64) uint64
TEXT ·Add(SB),0,$0-24 TEXT ·Add(SB),0,$0-24
MOVQ x(FP), CX MOVQ x(FP), AX
MOVQ y+8(FP), AX MOVQ y+8(FP), CX
ADDQ CX, AX ADDQ AX, CX
MOVQ CX, ret+16(FP) MOVQ CX, ret+16(FP)
RET RET

View File

@@ -8,5 +8,8 @@ import (
//go:generate go run asm.go -out add.s -stubs stub.go //go:generate go run asm.go -out add.s -stubs stub.go
func TestAdd(t *testing.T) { 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)
}
} }

View File

@@ -11,7 +11,7 @@ func main() {
x := Load(Param("x"), GP64v()) x := Load(Param("x"), GP64v())
y := Load(Param("y"), GP64v()) y := Load(Param("y"), GP64v())
ADDQ(x, y) ADDQ(x, y)
Store(x, ReturnIndex(0)) Store(y, ReturnIndex(0))
RET() RET()
Generate() Generate()
} }

32
examples/complex/asm.go Normal file
View File

@@ -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()
}

View File

@@ -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

View File

@@ -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)
}
}

5
examples/complex/stub.go Normal file
View File

@@ -0,0 +1,5 @@
package complex
func Real(x complex128) float64
func Imag(x complex128) float64
func Norm(x complex128) float64

View File

@@ -4,15 +4,15 @@
// func Sum(xs []uint64) uint64 // func Sum(xs []uint64) uint64
TEXT ·Sum(SB),0,$0-32 TEXT ·Sum(SB),0,$0-32
MOVQ xs_base(FP), DX MOVQ xs_base(FP), DX
MOVQ xs_len+8(FP), CX MOVQ xs_len+8(FP), AX
XORQ AX, AX XORQ CX, CX
loop: loop:
CMPQ CX, $0x0 CMPQ AX, $0x0
JE done JE done
ADDQ (DX), AX ADDQ (DX), CX
ADDQ $0x8, DX ADDQ $0x8, DX
DECQ CX DECQ AX
JMP loop JMP loop
done: done:
MOVQ AX, ret+24(FP) MOVQ CX, ret+24(FP)
RET RET

View File

@@ -7,14 +7,15 @@ import (
//go:generate go run asm.go -out sum.s -stubs stub.go //go:generate go run asm.go -out sum.s -stubs stub.go
func expect(xs []uint64) uint64 { func TestSum(t *testing.T) {
expect := func(xs []uint64) uint64 {
var s uint64 var s uint64
for _, x := range xs { for _, x := range xs {
s += x s += x
} }
return s return s
} }
if err := quick.CheckEqual(Sum, expect, nil); err != nil {
func TestSum(t *testing.T) { t.Fatal(err)
quick.CheckEqual(Sum, expect, nil) }
} }

View File

@@ -21,6 +21,8 @@ type Component interface {
Base() Component Base() Component
Len() Component Len() Component
Cap() Component Cap() Component
Real() Component
Imag() Component
Index(int) 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) Base() Component { return c }
func (c componenterr) Len() Component { return c } func (c componenterr) Len() Component { return c }
func (c componenterr) Cap() 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 } func (c componenterr) Index(int) Component { return c }
type component struct { type component struct {
@@ -96,6 +100,22 @@ func (c *component) Cap() Component {
return c.sub("_cap", int(slicehdroffsets[2]), types.Typ[types.Int]) 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 { func (c *component) Index(i int) Component {
a, ok := c.typ.(*types.Array) a, ok := c.typ.(*types.Array)
if !ok { if !ok {
@@ -146,6 +166,21 @@ func isstring(t types.Type) bool {
return ok && b.Kind() == types.String 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. // isprimitive returns true if the type cannot be broken into components.
func isprimitive(t types.Type) bool { func isprimitive(t types.Type) bool {
b, ok := t.(*types.Basic) b, ok := t.(*types.Basic)

View File

@@ -46,11 +46,23 @@ func (a *Allocator) AddInterferenceSet(r reg.Register, s reg.Set) {
} }
func (a *Allocator) AddInterference(x, y reg.Register) { func (a *Allocator) AddInterference(x, y reg.Register) {
a.add(x) a.Add(x)
a.add(y) a.Add(y)
a.edges = append(a.edges, &edge{X: x, Y: 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) { func (a *Allocator) Allocate() (reg.Allocation, error) {
for a.remaining() > 0 { for a.remaining() > 0 {
if err := a.update(); err != nil { if err := a.update(); err != nil {
@@ -65,15 +77,6 @@ func (a *Allocator) Allocate() (reg.Allocation, error) {
return a.allocation, nil 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. // update possible allocations based on edges.
func (a *Allocator) update() error { func (a *Allocator) update() error {
var rem []*edge var rem []*edge

View File

@@ -57,11 +57,11 @@ func Liveness(fn *avo.Function) error {
} }
func AllocateRegisters(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{} as := map[reg.Kind]*Allocator{}
for _, i := range fn.Instructions() { for _, i := range fn.Instructions() {
for _, d := range i.OutputRegisters() { for _, r := range i.Registers() {
k := d.Kind() k := r.Kind()
if _, found := as[k]; !found { if _, found := as[k]; !found {
a, err := NewAllocatorForKind(k) a, err := NewAllocatorForKind(k)
if err != nil { if err != nil {
@@ -69,7 +69,14 @@ func AllocateRegisters(fn *avo.Function) error {
} }
as[k] = a 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 := i.LiveOut.OfKind(k)
out.Discard(d) out.Discard(d)
as[k].AddInterferenceSet(d, out) as[k].AddInterferenceSet(d, out)