examples/complex: and bugfixes
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
32
examples/complex/asm.go
Normal 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()
|
||||||
|
}
|
||||||
23
examples/complex/complex.s
Normal file
23
examples/complex/complex.s
Normal 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
|
||||||
36
examples/complex/complex_test.go
Normal file
36
examples/complex/complex_test.go
Normal 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
5
examples/complex/stub.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package complex
|
||||||
|
|
||||||
|
func Real(x complex128) float64
|
||||||
|
func Imag(x complex128) float64
|
||||||
|
func Norm(x complex128) float64
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
|
||||||
var s uint64
|
|
||||||
for _, x := range xs {
|
|
||||||
s += x
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSum(t *testing.T) {
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
13
pass/reg.go
13
pass/reg.go
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user