ast: {Input,Output}Registers()

This commit is contained in:
Michael McLoughlin
2018-12-02 22:29:30 -08:00
parent 59548ee9f6
commit 7d4e18f4f4
4 changed files with 84 additions and 3 deletions

26
ast.go
View File

@@ -2,6 +2,7 @@ package avo
import (
"github.com/mmcloughlin/avo/operand"
"github.com/mmcloughlin/avo/reg"
)
type Asm interface {
@@ -46,6 +47,8 @@ type Instruction struct {
Succ []*Instruction
}
func (i Instruction) node() {}
func (i Instruction) TargetLabel() *Label {
if !i.IsBranch {
return nil
@@ -60,7 +63,28 @@ func (i Instruction) TargetLabel() *Label {
return nil
}
func (i Instruction) node() {}
func (i Instruction) InputRegisters() []reg.Register {
var rs []reg.Register
for _, op := range i.Inputs {
rs = append(rs, operand.Registers(op)...)
}
for _, op := range i.Outputs {
if operand.IsMem(op) {
rs = append(rs, operand.Registers(op)...)
}
}
return rs
}
func (i Instruction) OutputRegisters() []reg.Register {
var rs []reg.Register
for _, op := range i.Outputs {
if r, ok := op.(reg.Register); ok {
rs = append(rs, r)
}
}
return rs
}
// File represents an assembly file.
type File struct {

View File

@@ -6,6 +6,22 @@ import (
"github.com/mmcloughlin/avo/reg"
)
// Pure type assertion checks:
// IsRegister returns whether op has type reg.Register.
func IsRegister(op Op) bool { _, ok := op.(reg.Register); return ok }
// IsMem returns whether op has type Mem.
func IsMem(op Op) bool { _, ok := op.(Mem); return ok }
// IsImm returns whether op has type Imm.
func IsImm(op Op) bool { _, ok := op.(Imm); return ok }
// IsRel returns whether op has type Rel.
func IsRel(op Op) bool { _, ok := op.(Rel); return ok }
// Checks corresponding to specific operand types in the Intel Manual:
// Is1 returns true if op is the immediate constant 1.
func Is1(op Op) bool {
i, ok := op.(Imm)

View File

@@ -12,8 +12,8 @@ type Op interface {
type Mem struct {
Disp int
Base reg.Physical
Index reg.Physical
Base reg.Register
Index reg.Register
Scale uint8
}
@@ -50,3 +50,23 @@ type LabelRef string
func (l LabelRef) Asm() string {
return string(l)
}
// Registers returns the list of all operands involved in the given operand.
func Registers(op Op) []reg.Register {
switch op := op.(type) {
case reg.Register:
return []reg.Register{op}
case Mem:
var r []reg.Register
if op.Base != nil {
r = append(r, op.Base)
}
if op.Index != nil {
r = append(r, op.Index)
}
return r
case Imm, Rel, LabelRef:
return nil
}
panic("unknown operand type")
}

View File

@@ -1,6 +1,7 @@
package operand
import (
"reflect"
"testing"
"github.com/mmcloughlin/avo/reg"
@@ -26,3 +27,23 @@ func TestMemAsm(t *testing.T) {
}
}
}
func TestRegisters(t *testing.T) {
cases := []struct {
Op Op
Expect []reg.Register
}{
{reg.R11, []reg.Register{reg.R11}},
{Mem{Base: reg.EAX}, []reg.Register{reg.EAX}},
{Mem{Base: reg.RBX, Index: reg.R10}, []reg.Register{reg.RBX, reg.R10}},
{Imm(42), nil},
{Rel(42), nil},
{LabelRef("idk"), nil},
}
for _, c := range cases {
got := Registers(c.Op)
if !reflect.DeepEqual(got, c.Expect) {
t.Errorf("Registers(%#v) = %#v expected %#v", c.Op, got, c.Expect)
}
}
}