summaryrefslogtreecommitdiff
path: root/vendor/github.com/mmcloughlin/avo/ir/ir.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mmcloughlin/avo/ir/ir.go')
-rw-r--r--vendor/github.com/mmcloughlin/avo/ir/ir.go355
1 files changed, 355 insertions, 0 deletions
diff --git a/vendor/github.com/mmcloughlin/avo/ir/ir.go b/vendor/github.com/mmcloughlin/avo/ir/ir.go
new file mode 100644
index 0000000..6fb9216
--- /dev/null
+++ b/vendor/github.com/mmcloughlin/avo/ir/ir.go
@@ -0,0 +1,355 @@
+package ir
+
+import (
+ "errors"
+
+ "github.com/mmcloughlin/avo/attr"
+ "github.com/mmcloughlin/avo/buildtags"
+ "github.com/mmcloughlin/avo/gotypes"
+ "github.com/mmcloughlin/avo/operand"
+ "github.com/mmcloughlin/avo/reg"
+)
+
+// Node is a part of a Function.
+type Node interface {
+ node()
+}
+
+// Label within a function.
+type Label string
+
+func (l Label) node() {}
+
+// Comment represents a multi-line comment.
+type Comment struct {
+ Lines []string
+}
+
+func (c *Comment) node() {}
+
+// NewComment builds a Comment consisting of the provided lines.
+func NewComment(lines ...string) *Comment {
+ return &Comment{
+ Lines: lines,
+ }
+}
+
+// Instruction is a single instruction in a function.
+type Instruction struct {
+ Opcode string
+ Operands []operand.Op
+
+ Inputs []operand.Op
+ Outputs []operand.Op
+
+ IsTerminal bool
+ IsBranch bool
+ IsConditional bool
+ CancellingInputs bool
+
+ // ISA is the list of required instruction set extensions.
+ ISA []string
+
+ // CFG.
+ Pred []*Instruction
+ Succ []*Instruction
+
+ // LiveIn/LiveOut are sets of live register IDs pre/post execution.
+ LiveIn reg.MaskSet
+ LiveOut reg.MaskSet
+}
+
+func (i *Instruction) node() {}
+
+// IsUnconditionalBranch reports whether i is an unconditional branch.
+func (i Instruction) IsUnconditionalBranch() bool {
+ return i.IsBranch && !i.IsConditional
+}
+
+// TargetLabel returns the label referenced by this instruction. Returns nil if
+// no label is referenced.
+func (i Instruction) TargetLabel() *Label {
+ if !i.IsBranch {
+ return nil
+ }
+ if len(i.Operands) == 0 {
+ return nil
+ }
+ if ref, ok := i.Operands[0].(operand.LabelRef); ok {
+ lbl := Label(ref)
+ return &lbl
+ }
+ return nil
+}
+
+// Registers returns all registers involved in the instruction.
+func (i Instruction) Registers() []reg.Register {
+ var rs []reg.Register
+ for _, op := range i.Operands {
+ rs = append(rs, operand.Registers(op)...)
+ }
+ return rs
+}
+
+// InputRegisters returns all registers read by this instruction.
+func (i Instruction) InputRegisters() []reg.Register {
+ var rs []reg.Register
+ for _, op := range i.Inputs {
+ rs = append(rs, operand.Registers(op)...)
+ }
+ if i.CancellingInputs && rs[0] == rs[1] {
+ rs = []reg.Register{}
+ }
+ for _, op := range i.Outputs {
+ if operand.IsMem(op) {
+ rs = append(rs, operand.Registers(op)...)
+ }
+ }
+ return rs
+}
+
+// OutputRegisters returns all registers written by this instruction.
+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
+}
+
+// Section is a part of a file.
+type Section interface {
+ section()
+}
+
+// File represents an assembly file.
+type File struct {
+ Constraints buildtags.Constraints
+ Includes []string
+ Sections []Section
+}
+
+// NewFile initializes an empty file.
+func NewFile() *File {
+ return &File{}
+}
+
+// AddSection appends a Section to the file.
+func (f *File) AddSection(s Section) {
+ f.Sections = append(f.Sections, s)
+}
+
+// Functions returns all functions in the file.
+func (f *File) Functions() []*Function {
+ var fns []*Function
+ for _, s := range f.Sections {
+ if fn, ok := s.(*Function); ok {
+ fns = append(fns, fn)
+ }
+ }
+ return fns
+}
+
+// Pragma represents a function compiler directive.
+type Pragma struct {
+ Directive string
+ Arguments []string
+}
+
+// Function represents an assembly function.
+type Function struct {
+ Name string
+ Attributes attr.Attribute
+ Pragmas []Pragma
+ Doc []string
+ Signature *gotypes.Signature
+ LocalSize int
+
+ Nodes []Node
+
+ // LabelTarget maps from label name to the following instruction.
+ LabelTarget map[Label]*Instruction
+
+ // Register allocation.
+ Allocation reg.Allocation
+
+ // ISA is the list of required instruction set extensions.
+ ISA []string
+}
+
+func (f *Function) section() {}
+
+// NewFunction builds an empty function of the given name.
+func NewFunction(name string) *Function {
+ return &Function{
+ Name: name,
+ Signature: gotypes.NewSignatureVoid(),
+ }
+}
+
+// AddPragma adds a pragma to this function.
+func (f *Function) AddPragma(directive string, args ...string) {
+ f.Pragmas = append(f.Pragmas, Pragma{
+ Directive: directive,
+ Arguments: args,
+ })
+}
+
+// SetSignature sets the function signature.
+func (f *Function) SetSignature(s *gotypes.Signature) {
+ f.Signature = s
+}
+
+// AllocLocal allocates size bytes in this function's stack.
+// Returns a reference to the base pointer for the newly allocated region.
+func (f *Function) AllocLocal(size int) operand.Mem {
+ ptr := operand.NewStackAddr(f.LocalSize)
+ f.LocalSize += size
+ return ptr
+}
+
+// AddInstruction appends an instruction to f.
+func (f *Function) AddInstruction(i *Instruction) {
+ f.AddNode(i)
+}
+
+// AddLabel appends a label to f.
+func (f *Function) AddLabel(l Label) {
+ f.AddNode(l)
+}
+
+// AddComment adds comment lines to f.
+func (f *Function) AddComment(lines ...string) {
+ f.AddNode(NewComment(lines...))
+}
+
+// AddNode appends a Node to f.
+func (f *Function) AddNode(n Node) {
+ f.Nodes = append(f.Nodes, n)
+}
+
+// Instructions returns just the list of instruction nodes.
+func (f *Function) Instructions() []*Instruction {
+ var is []*Instruction
+ for _, n := range f.Nodes {
+ i, ok := n.(*Instruction)
+ if ok {
+ is = append(is, i)
+ }
+ }
+ return is
+}
+
+// Labels returns just the list of label nodes.
+func (f *Function) Labels() []Label {
+ var lbls []Label
+ for _, n := range f.Nodes {
+ lbl, ok := n.(Label)
+ if ok {
+ lbls = append(lbls, lbl)
+ }
+ }
+ return lbls
+}
+
+// Stub returns the Go function declaration.
+func (f *Function) Stub() string {
+ return "func " + f.Name + f.Signature.String()
+}
+
+// FrameBytes returns the size of the stack frame in bytes.
+func (f *Function) FrameBytes() int {
+ return f.LocalSize
+}
+
+// ArgumentBytes returns the size of the arguments in bytes.
+func (f *Function) ArgumentBytes() int {
+ return f.Signature.Bytes()
+}
+
+// Datum represents a data element at a particular offset of a data section.
+type Datum struct {
+ Offset int
+ Value operand.Constant
+}
+
+// NewDatum builds a Datum from the given constant.
+func NewDatum(offset int, v operand.Constant) Datum {
+ return Datum{
+ Offset: offset,
+ Value: v,
+ }
+}
+
+// Interval returns the range of bytes this datum will occupy within its section.
+func (d Datum) Interval() (int, int) {
+ return d.Offset, d.Offset + d.Value.Bytes()
+}
+
+// Overlaps returns true
+func (d Datum) Overlaps(other Datum) bool {
+ s, e := d.Interval()
+ so, eo := other.Interval()
+ return !(eo <= s || e <= so)
+}
+
+// Global represents a DATA section.
+type Global struct {
+ Symbol operand.Symbol
+ Attributes attr.Attribute
+ Data []Datum
+ Size int
+}
+
+// NewGlobal constructs an empty DATA section.
+func NewGlobal(sym operand.Symbol) *Global {
+ return &Global{
+ Symbol: sym,
+ }
+}
+
+// NewStaticGlobal is a convenience for building a static DATA section.
+func NewStaticGlobal(name string) *Global {
+ return NewGlobal(operand.NewStaticSymbol(name))
+}
+
+func (g *Global) section() {}
+
+// Base returns a pointer to the start of the data section.
+func (g *Global) Base() operand.Mem {
+ return operand.NewDataAddr(g.Symbol, 0)
+}
+
+// Grow ensures that the data section has at least the given size.
+func (g *Global) Grow(size int) {
+ if g.Size < size {
+ g.Size = size
+ }
+}
+
+// AddDatum adds d to this data section, growing it if necessary. Errors if the datum overlaps with existing data.
+func (g *Global) AddDatum(d Datum) error {
+ for _, other := range g.Data {
+ if d.Overlaps(other) {
+ return errors.New("overlaps existing datum")
+ }
+ }
+ g.add(d)
+ return nil
+}
+
+// Append the constant to the end of the data section.
+func (g *Global) Append(v operand.Constant) {
+ g.add(Datum{
+ Offset: g.Size,
+ Value: v,
+ })
+}
+
+func (g *Global) add(d Datum) {
+ _, end := d.Interval()
+ g.Grow(end)
+ g.Data = append(g.Data, d)
+}