ast: {Input,Output}Registers()
This commit is contained in:
26
ast.go
26
ast.go
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user