ast: {Input,Output}Registers()
This commit is contained in:
26
ast.go
26
ast.go
@@ -2,6 +2,7 @@ package avo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/mmcloughlin/avo/operand"
|
"github.com/mmcloughlin/avo/operand"
|
||||||
|
"github.com/mmcloughlin/avo/reg"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Asm interface {
|
type Asm interface {
|
||||||
@@ -46,6 +47,8 @@ type Instruction struct {
|
|||||||
Succ []*Instruction
|
Succ []*Instruction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i Instruction) node() {}
|
||||||
|
|
||||||
func (i Instruction) TargetLabel() *Label {
|
func (i Instruction) TargetLabel() *Label {
|
||||||
if !i.IsBranch {
|
if !i.IsBranch {
|
||||||
return nil
|
return nil
|
||||||
@@ -60,7 +63,28 @@ func (i Instruction) TargetLabel() *Label {
|
|||||||
return nil
|
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.
|
// File represents an assembly file.
|
||||||
type File struct {
|
type File struct {
|
||||||
|
|||||||
@@ -6,6 +6,22 @@ import (
|
|||||||
"github.com/mmcloughlin/avo/reg"
|
"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.
|
// Is1 returns true if op is the immediate constant 1.
|
||||||
func Is1(op Op) bool {
|
func Is1(op Op) bool {
|
||||||
i, ok := op.(Imm)
|
i, ok := op.(Imm)
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ type Op interface {
|
|||||||
|
|
||||||
type Mem struct {
|
type Mem struct {
|
||||||
Disp int
|
Disp int
|
||||||
Base reg.Physical
|
Base reg.Register
|
||||||
Index reg.Physical
|
Index reg.Register
|
||||||
Scale uint8
|
Scale uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,3 +50,23 @@ type LabelRef string
|
|||||||
func (l LabelRef) Asm() string {
|
func (l LabelRef) Asm() string {
|
||||||
return string(l)
|
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
|
package operand
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/mmcloughlin/avo/reg"
|
"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