Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Track register allocations #105

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion pass/alloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package pass

import (
"errors"
"fmt"
"math"
"sort"
"strings"

"github.com/mmcloughlin/avo/reg"
)
Expand Down Expand Up @@ -182,7 +184,17 @@ func (a *Allocator) discardconflicting(v, p reg.ID) {
func (a *Allocator) alloc(v reg.ID) error {
ps := a.possible[v]
if len(ps) == 0 {
return errors.New("failed to allocate registers")
var allocs []string
for i, v := range a.allocation {
if ai, ok := i.(reg.AllocInfoer); ok {
allocs = append(allocs, fmt.Sprintf("%02d: %s (type:%T, kind:%v%d)", v.PhysicalID(), ai.AllocInfo(), i, i.Kind(), i.Size()*8))
} else {
allocs = append(allocs, fmt.Sprintf("%02d: No alloc info. (type:%T, kind:%v%d)", v.PhysicalID(), i, i.Kind(), i.Size()*8))
}
}
sort.Strings(allocs)
err := fmt.Sprintf("failed to allocate registers. %d virtual:\n%s", len(a.allocation), strings.Join(allocs, "\n"))
return errors.New(err)
}
p := ps[0]
a.allocation[v] = p
Expand Down
28 changes: 28 additions & 0 deletions reg/func.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package reg

import (
"fmt"
"runtime"
"strings"
)

// getFnNameFile returns the first file+function in the call stack that is not avo.
func getFnNameFile(depth int) string {
caller := [100]uintptr{0}
runtime.Callers(1+depth, caller[:])
frames := runtime.CallersFrames(caller[:])
for {
f, more := frames.Next()
file := f.File
line := f.Line
fnName := f.Func.Name()

if !strings.Contains(file, "github.com/mmcloughlin/avo") {
return fmt.Sprintf("%s:%d %s()", file, line, fnName)
}
if !more {
break
}
}
return ""
}
41 changes: 37 additions & 4 deletions reg/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,36 +106,54 @@
type virtual struct {
idx Index
kind Kind
Spec
Width

Check failure on line 109 in reg/types.go

View workflow job for this annotation

GitHub Actions / lint

undefined: Width

Check failure on line 109 in reg/types.go

View workflow job for this annotation

GitHub Actions / test (1.22.x)

undefined: Width
mask uint16
allocAt string
}

// NewVirtual builds a Virtual register.
func NewVirtual(idx Index, k Kind, s Spec) Virtual {
return virtual{

Check failure on line 116 in reg/types.go

View workflow job for this annotation

GitHub Actions / lint

cannot use virtual{…} (value of type virtual) as Virtual value in return statement: virtual does not implement Virtual (missing method Mask)

Check failure on line 116 in reg/types.go

View workflow job for this annotation

GitHub Actions / test (1.22.x)

cannot use virtual{…} (value of type virtual) as Virtual value in return statement: virtual does not implement Virtual (missing method Mask)
idx: idx,
kind: k,
Spec: s,
allocAt: getFnNameFile(1),
idx: idx,
kind: k,
Spec: s,

Check failure on line 120 in reg/types.go

View workflow job for this annotation

GitHub Actions / lint

unknown field Spec in struct literal of type virtual

Check failure on line 120 in reg/types.go

View workflow job for this annotation

GitHub Actions / test (1.22.x)

unknown field Spec in struct literal of type virtual
}
}

func (v virtual) ID() ID { return newid(1, v.kind, v.idx) }
func (v virtual) VirtualIndex() Index { return v.idx }
func (v virtual) Kind() Kind { return v.kind }

// AllocInfoer allows to track where resources were allocated.
type AllocInfoer interface {
AllocInfo() string
}

// AllocInfo returns allocation info.
func (v virtual) AllocInfo() string {
return v.allocAt
}

func (v virtual) VirtualID() VID { return v.id }

Check failure on line 138 in reg/types.go

View workflow job for this annotation

GitHub Actions / lint

undefined: VID

Check failure on line 138 in reg/types.go

View workflow job for this annotation

GitHub Actions / lint

v.id undefined (type virtual has no field or method id)

Check failure on line 138 in reg/types.go

View workflow job for this annotation

GitHub Actions / test (1.22.x)

undefined: VID

Check failure on line 138 in reg/types.go

View workflow job for this annotation

GitHub Actions / test (1.22.x)

v.id undefined (type virtual has no field or method id)
func (v virtual) Kind() Kind { return v.kind }

Check failure on line 139 in reg/types.go

View workflow job for this annotation

GitHub Actions / lint

method virtual.Kind already declared at reg/types.go:126:18

Check failure on line 139 in reg/types.go

View workflow job for this annotation

GitHub Actions / test (1.22.x)

method virtual.Kind already declared at reg/types.go:126:18

func (v virtual) Asm() string {
// TODO(mbm): decide on virtual register syntax
return fmt.Sprintf("<virtual:%v:%v:%v>", v.idx, v.Kind(), v.Size())

Check failure on line 143 in reg/types.go

View workflow job for this annotation

GitHub Actions / lint

v.Size undefined (type virtual has no field or method Size)

Check failure on line 143 in reg/types.go

View workflow job for this annotation

GitHub Actions / test (1.22.x)

v.Size undefined (type virtual has no field or method Size)
}

func (v virtual) as(s Spec) Register {
return virtual{

Check failure on line 147 in reg/types.go

View workflow job for this annotation

GitHub Actions / lint

cannot use virtual{…} (value of type virtual) as Register value in return statement: virtual does not implement Register (missing method Mask)

Check failure on line 147 in reg/types.go

View workflow job for this annotation

GitHub Actions / test (1.22.x)

cannot use virtual{…} (value of type virtual) as Register value in return statement: virtual does not implement Register (missing method Mask)
idx: v.idx,
kind: v.kind,
Spec: s,

Check failure on line 150 in reg/types.go

View workflow job for this annotation

GitHub Actions / lint

unknown field Spec in struct literal of type virtual

Check failure on line 150 in reg/types.go

View workflow job for this annotation

GitHub Actions / test (1.22.x)

unknown field Spec in struct literal of type virtual
// Non-breaking space for sorting.
allocAt: fmt.Sprintf("\u00A0- As%v() %s", s.String(), getFnNameFile(2)),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This breaks allocation, hinting that an == is used on this type somewhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect the possible map[reg.Virtual][]reg.Physical is the problem here or with type Allocation map[Register]Physical

}
}

func (v virtual) spec() Spec { return v.Spec }

Check failure on line 156 in reg/types.go

View workflow job for this annotation

GitHub Actions / lint

v.Spec undefined (type virtual has no field or method Spec, but does have spec)

Check failure on line 156 in reg/types.go

View workflow job for this annotation

GitHub Actions / test (1.22.x)

v.Spec undefined (type virtual has no field or method Spec, but does have spec)
func (v virtual) register() {}

// Info is a bitmask of register properties.
Expand Down Expand Up @@ -248,6 +266,21 @@
return LookupPhysical(id.Kind(), id.Index(), s)
}

// Size returns the register width in bytes.
func (s Spec) String() string {
switch s {
case S8H:
return "8H"
default:
return fmt.Sprint(s.Size() * 8)
}
}

// AreConflicting returns whether registers conflict with each other.
func AreConflicting(x, y Physical) bool {
return x.Kind() == y.Kind() && x.PhysicalID() == y.PhysicalID() && (x.Mask()&y.Mask()) != 0
}

// Allocation records a register allocation.
type Allocation map[ID]ID

Expand Down
37 changes: 36 additions & 1 deletion reg/x86.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ var (
}
)

// String returns a human readable representation of the Kind.
func (k Kind) String() string {
switch k {
case KindPseudo:
return "pseudo"
case KindGP:
return "gpr"
case KindVector:
return "vector"
default:
return "invalid"
}
}

var familiesByKind = map[Kind]*Family{}

func init() {
Expand Down Expand Up @@ -81,9 +95,30 @@ type GPVirtual interface {

type gpv struct {
Virtual
GP
allocAt string
}

func newgpv(v Virtual) GPVirtual { return gpv{Virtual: v} }
func newgpv(v Virtual) GPVirtual {
g := gpv{
Virtual: v,
//GP: gpcasts{v},
allocAt: getFnNameFile(1),
}
if ai, ok := v.(AllocInfoer); ok {
parent := ai.AllocInfo()
if g.allocAt != parent {
// Only add ourself if different from parent.
g.allocAt = parent + " -> " + g.allocAt
}
}
return g
}

// AllocInfo returns allocation info.
func (g gpv) AllocInfo() string {
return g.allocAt
}

func (v gpv) As8() Register { return newgpv(v.as(S8).(Virtual)) }
func (v gpv) As8L() Register { return newgpv(v.as(S8L).(Virtual)) }
Expand Down
Loading