Files
avo/operand/types.go

154 lines
3.1 KiB
Go
Raw Normal View History

package operand
import (
"fmt"
"github.com/mmcloughlin/avo/reg"
)
2019-01-04 21:38:23 -08:00
// Op is an operand.
2018-12-02 12:28:33 -08:00
type Op interface {
Asm() string
}
2019-01-04 21:38:23 -08:00
// Symbol represents a symbol name.
2018-12-06 17:26:33 -08:00
type Symbol struct {
Name string
2019-01-04 21:38:23 -08:00
Static bool // only visible in current source file
2018-12-06 17:26:33 -08:00
}
2019-01-04 21:38:23 -08:00
// NewStaticSymbol builds a static Symbol. Static symbols are only visible in the current source file.
2018-12-27 11:57:46 -08:00
func NewStaticSymbol(name string) Symbol {
return Symbol{Name: name, Static: true}
}
2018-12-06 17:26:33 -08:00
func (s Symbol) String() string {
n := s.Name
if s.Static {
n += "<>"
}
return n
}
2019-01-04 21:38:23 -08:00
// Mem represents a memory reference.
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,
}
}
2019-01-04 21:38:23 -08:00
// NewStackAddr returns a memory reference relative to the stack pointer.
2018-12-21 00:30:59 -08:00
func NewStackAddr(offset int) Mem {
return Mem{
Disp: offset,
Base: reg.StackPointer,
}
}
2019-01-04 21:38:23 -08:00
// NewDataAddr returns a memory reference relative to the named data symbol.
2018-12-27 11:57:46 -08:00
func NewDataAddr(sym Symbol, offset int) Mem {
return Mem{
Symbol: sym,
Disp: offset,
Base: reg.StaticBase,
}
}
2019-01-04 21:38:23 -08:00
// Offset returns a reference to m plus idx bytes.
2018-12-27 11:57:46 -08:00
func (m Mem) Offset(idx int) Mem {
2018-12-21 00:30:59 -08:00
a := m
a.Disp += idx
return a
}
2019-01-04 21:38:23 -08:00
// Idx returns a new memory reference with (Index, Scale) set to (r, s).
2018-12-27 11:57:46 -08:00
func (m Mem) Idx(r reg.Register, s uint8) Mem {
a := m
a.Index = r
a.Scale = s
return a
}
2019-01-04 21:38:23 -08:00
// Asm returns an assembly syntax representation of m.
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
2019-01-04 21:38:23 -08:00
// Asm returns an assembly syntax representation of r.
2018-11-27 22:08:11 -08:00
func (r Rel) Asm() string {
return fmt.Sprintf(".%+d", r)
}
// LabelRef is a reference to a label.
type LabelRef string
2019-01-04 21:38:23 -08:00
// Asm returns an assembly syntax representation of l.
2018-11-27 22:08:11 -08:00
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
}