Files
avo/operand/types.go

124 lines
2.2 KiB
Go
Raw Normal View History

package operand
import (
"fmt"
"github.com/mmcloughlin/avo/reg"
)
2018-12-02 12:28:33 -08:00
type Op interface {
Asm() string
}
2018-12-06 17:26:33 -08:00
type Symbol struct {
Name string
Static bool
}
func (s Symbol) String() string {
n := s.Name
if s.Static {
n += "<>"
}
return n
}
type Mem struct {
2018-12-06 17:26:33 -08:00
Symbol Symbol
Disp int
Base reg.Register
Index reg.Register
Scale uint8
}
// NewParamAddr is a convenience to build a Mem operand pointing to a function
// parameter, which is a named offset from the frame pointer pseudo register.
func NewParamAddr(name string, offset int) Mem {
return Mem{
Symbol: Symbol{
Name: name,
Static: false,
},
Disp: offset,
Base: reg.FramePointer,
}
}
2018-12-21 00:30:59 -08:00
func NewStackAddr(offset int) Mem {
return Mem{
Disp: offset,
Base: reg.StackPointer,
}
}
func (m Mem) Idx(idx int) Mem {
a := m
a.Disp += idx
return a
}
func (m Mem) Asm() string {
2018-12-06 17:26:33 -08:00
a := m.Symbol.String()
if m.Disp != 0 {
2018-12-06 17:26:33 -08:00
if a == "" {
a += fmt.Sprintf("%d", m.Disp)
} else {
a += fmt.Sprintf("%+d", m.Disp)
}
}
if m.Base != nil {
a += fmt.Sprintf("(%s)", m.Base.Asm())
}
if m.Index != nil && m.Scale != 0 {
a += fmt.Sprintf("(%s*%d)", m.Index.Asm(), m.Scale)
}
return a
}
2018-11-27 22:08:11 -08:00
// Rel is an offset relative to the instruction pointer.
type Rel int32
func (r Rel) Asm() string {
return fmt.Sprintf(".%+d", r)
}
// LabelRef is a reference to a label.
type LabelRef string
func (l LabelRef) Asm() string {
return string(l)
}
2018-12-02 22:29:30 -08:00
// 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
2018-12-26 16:42:39 -08:00
case Constant, Rel, LabelRef:
2018-12-02 22:29:30 -08:00
return nil
}
panic("unknown operand type")
}
// ApplyAllocation returns an operand with allocated registers replaced. Registers missing from the allocation are left alone.
func ApplyAllocation(op Op, a reg.Allocation) Op {
switch op := op.(type) {
case reg.Register:
return a.LookupDefault(op)
case Mem:
op.Base = a.LookupDefault(op.Base)
op.Index = a.LookupDefault(op.Index)
return op
}
return op
}