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 2 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
15 changes: 14 additions & 1 deletion pass/alloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package pass

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

"github.com/mmcloughlin/avo/reg"
)
Expand Down Expand Up @@ -156,7 +159,17 @@ func (a *Allocator) discardconflicting(v reg.Virtual, p reg.Physical) {
func (a *Allocator) alloc(v reg.Virtual) 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 ""
}
32 changes: 28 additions & 4 deletions reg/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,18 +106,30 @@ type virtual struct {
id VID
kind Kind
Width
mask uint16
mask uint16
allocAt string
}

// NewVirtual builds a Virtual register.
func NewVirtual(id VID, k Kind, w Width) Virtual {
return virtual{
id: id,
kind: k,
Width: w,
allocAt: getFnNameFile(1),
id: id,
kind: k,
Width: w,
}
}

// 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 }
func (v virtual) Kind() Kind { return v.kind }

Expand All @@ -136,6 +148,8 @@ func (v virtual) as(s Spec) Register {
kind: v.kind,
Width: Width(s.Size()),
mask: s.Mask(),
// 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

}
}

Expand Down Expand Up @@ -235,6 +249,16 @@ func (s Spec) Size() uint {
return (x >> 1) + (x & 1)
}

// 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
Expand Down
36 changes: 35 additions & 1 deletion reg/x86.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,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 @@ -84,9 +98,29 @@ type GPVirtual interface {
type gpv struct {
Virtual
GP
allocAt string
}

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
}

func newgpv(v Virtual) GPVirtual { return gpv{Virtual: v, GP: gpcasts{v}} }
// AllocInfo returns allocation info.
func (g gpv) AllocInfo() string {
return g.allocAt
}

func gp(s Spec, id PID, name string, flags ...Info) GPPhysical {
r := newgpp(newregister(GeneralPurpose, s, id, name, flags...))
Expand Down