build: support comments in functions (#41)
This commit is contained in:
@@ -133,6 +133,11 @@ func (c *Context) Label(name string) {
|
|||||||
c.activefunc().AddLabel(ir.Label(name))
|
c.activefunc().AddLabel(ir.Label(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Comment adds comment lines to the active function.
|
||||||
|
func (c *Context) Comment(lines ...string) {
|
||||||
|
c.activefunc().AddComment(lines...)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Context) activefunc() *ir.Function {
|
func (c *Context) activefunc() *ir.Function {
|
||||||
if c.function == nil {
|
if c.function == nil {
|
||||||
c.adderrormessage("no active function")
|
c.adderrormessage("no active function")
|
||||||
|
|||||||
@@ -125,5 +125,8 @@ func AllocLocal(size int) operand.Mem { return ctx.AllocLocal(size) }
|
|||||||
// Label adds a label to the active function.
|
// Label adds a label to the active function.
|
||||||
func Label(name string) { ctx.Label(name) }
|
func Label(name string) { ctx.Label(name) }
|
||||||
|
|
||||||
|
// Comment adds comment lines to the active function.
|
||||||
|
func Comment(lines ...string) { ctx.Comment(lines...) }
|
||||||
|
|
||||||
// ConstData builds a static data section containing just the given constant.
|
// ConstData builds a static data section containing just the given constant.
|
||||||
func ConstData(name string, v operand.Constant) operand.Mem { return ctx.ConstData(name, v) }
|
func ConstData(name string, v operand.Constant) operand.Mem { return ctx.ConstData(name, v) }
|
||||||
|
|||||||
19
ir/ir.go
19
ir/ir.go
@@ -20,6 +20,20 @@ type Label string
|
|||||||
|
|
||||||
func (l Label) node() {}
|
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.
|
// Instruction is a single instruction in a function.
|
||||||
type Instruction struct {
|
type Instruction struct {
|
||||||
Opcode string
|
Opcode string
|
||||||
@@ -176,6 +190,11 @@ func (f *Function) AddLabel(l Label) {
|
|||||||
f.AddNode(l)
|
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.
|
// AddNode appends a Node to f.
|
||||||
func (f *Function) AddNode(n Node) {
|
func (f *Function) AddNode(n Node) {
|
||||||
f.Nodes = append(f.Nodes, n)
|
f.Nodes = append(f.Nodes, n)
|
||||||
|
|||||||
40
pass/cfg.go
40
pass/cfg.go
@@ -11,27 +11,27 @@ import (
|
|||||||
// label name to the following instruction.
|
// label name to the following instruction.
|
||||||
func LabelTarget(fn *ir.Function) error {
|
func LabelTarget(fn *ir.Function) error {
|
||||||
target := map[ir.Label]*ir.Instruction{}
|
target := map[ir.Label]*ir.Instruction{}
|
||||||
for idx := 0; idx < len(fn.Nodes); idx++ {
|
var empty ir.Label
|
||||||
// Is this a label?
|
pending := empty
|
||||||
lbl, ok := fn.Nodes[idx].(ir.Label)
|
for _, node := range fn.Nodes {
|
||||||
if !ok {
|
switch n := node.(type) {
|
||||||
continue
|
case ir.Label:
|
||||||
|
if pending != empty {
|
||||||
|
return errors.New("instruction should follow a label")
|
||||||
|
}
|
||||||
|
pending = n
|
||||||
|
if _, found := target[pending]; found {
|
||||||
|
return fmt.Errorf("duplicate label \"%s\"", pending)
|
||||||
|
}
|
||||||
|
case *ir.Instruction:
|
||||||
|
if pending != empty {
|
||||||
|
target[pending] = n
|
||||||
|
pending = empty
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Check for a duplicate label.
|
}
|
||||||
if _, found := target[lbl]; found {
|
if pending != empty {
|
||||||
return fmt.Errorf("duplicate label \"%s\"", lbl)
|
return errors.New("function ends with label")
|
||||||
}
|
|
||||||
// Advance to next node.
|
|
||||||
if idx == len(fn.Nodes)-1 {
|
|
||||||
return errors.New("function ends with label")
|
|
||||||
}
|
|
||||||
idx++
|
|
||||||
// Should be an instruction.
|
|
||||||
i, ok := fn.Nodes[idx].(*ir.Instruction)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("instruction should follow a label")
|
|
||||||
}
|
|
||||||
target[lbl] = i
|
|
||||||
}
|
}
|
||||||
fn.LabelTarget = target
|
fn.LabelTarget = target
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ func TestLabelTarget(t *testing.T) {
|
|||||||
f := ir.NewFunction("happypath")
|
f := ir.NewFunction("happypath")
|
||||||
for lbl, i := range expect {
|
for lbl, i := range expect {
|
||||||
f.AddLabel(lbl)
|
f.AddLabel(lbl)
|
||||||
|
f.AddComment("comments should be ignored")
|
||||||
f.AddInstruction(i)
|
f.AddInstruction(i)
|
||||||
f.AddInstruction(&ir.Instruction{Opcode: "IDK"})
|
f.AddInstruction(&ir.Instruction{Opcode: "IDK"})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,15 @@ func (p *goasm) function(f *ir.Function) {
|
|||||||
p.Printf(", %s\n", textsize(f))
|
p.Printf(", %s\n", textsize(f))
|
||||||
|
|
||||||
w := p.tabwriter()
|
w := p.tabwriter()
|
||||||
|
clear := true
|
||||||
|
flush := func() {
|
||||||
|
w.Flush()
|
||||||
|
w = p.tabwriter()
|
||||||
|
if !clear {
|
||||||
|
p.NL()
|
||||||
|
clear = true
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, node := range f.Nodes {
|
for _, node := range f.Nodes {
|
||||||
switch n := node.(type) {
|
switch n := node.(type) {
|
||||||
case *ir.Instruction:
|
case *ir.Instruction:
|
||||||
@@ -93,10 +102,15 @@ func (p *goasm) function(f *ir.Function) {
|
|||||||
fmt.Fprintf(w, "\t%s", joinOperands(n.Operands))
|
fmt.Fprintf(w, "\t%s", joinOperands(n.Operands))
|
||||||
}
|
}
|
||||||
fmt.Fprint(w, "\n")
|
fmt.Fprint(w, "\n")
|
||||||
|
clear = false
|
||||||
case ir.Label:
|
case ir.Label:
|
||||||
w.Flush()
|
flush()
|
||||||
w = p.tabwriter()
|
p.Printf("%s:\n", n)
|
||||||
p.Printf("\n%s:\n", n)
|
case *ir.Comment:
|
||||||
|
flush()
|
||||||
|
for _, line := range n.Lines {
|
||||||
|
p.Printf("\t// %s\n", line)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
panic("unexpected node type")
|
panic("unexpected node type")
|
||||||
}
|
}
|
||||||
|
|||||||
26
tests/fmt/asm.go
Normal file
26
tests/fmt/asm.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/mmcloughlin/avo/build"
|
||||||
|
. "github.com/mmcloughlin/avo/reg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
TEXT("Formatting", NOSPLIT, "func()")
|
||||||
|
Doc("Formatting contains various cases to test the formatter.")
|
||||||
|
|
||||||
|
ADDQ(R8, R8)
|
||||||
|
Comment("One comment line between instructions.")
|
||||||
|
ADDQ(R8, R8)
|
||||||
|
|
||||||
|
Comment("Comment before label.")
|
||||||
|
Label("label")
|
||||||
|
Comment("Comment after label.")
|
||||||
|
ADDQ(R8, R8)
|
||||||
|
|
||||||
|
RET()
|
||||||
|
|
||||||
|
Generate()
|
||||||
|
}
|
||||||
16
tests/fmt/fmt.s
Normal file
16
tests/fmt/fmt.s
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// Code generated by command: go run asm.go -out fmt.s -stubs stub.go. DO NOT EDIT.
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// func Formatting()
|
||||||
|
TEXT ·Formatting(SB), NOSPLIT, $0
|
||||||
|
ADDQ R8, R8
|
||||||
|
|
||||||
|
// One comment line between instructions.
|
||||||
|
ADDQ R8, R8
|
||||||
|
|
||||||
|
// Comment before label.
|
||||||
|
label:
|
||||||
|
// Comment after label.
|
||||||
|
ADDQ R8, R8
|
||||||
|
RET
|
||||||
4
tests/fmt/gen.go
Normal file
4
tests/fmt/gen.go
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
// Package fmt tests assembly printer formatting.
|
||||||
|
package fmt
|
||||||
|
|
||||||
|
//go:generate go run asm.go -out fmt.s -stubs stub.go
|
||||||
6
tests/fmt/stub.go
Normal file
6
tests/fmt/stub.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// Code generated by command: go run asm.go -out fmt.s -stubs stub.go. DO NOT EDIT.
|
||||||
|
|
||||||
|
package fmt
|
||||||
|
|
||||||
|
// Formatting contains various cases to test the formatter.
|
||||||
|
func Formatting()
|
||||||
Reference in New Issue
Block a user