Skip to content

Commit 284ee13

Browse files
committed
build: support comments in functions (mmcloughlin#41)
1 parent 27cea3b commit 284ee13

10 files changed

Lines changed: 117 additions & 23 deletions

File tree

build/context.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ func (c *Context) Label(name string) {
133133
c.activefunc().AddLabel(ir.Label(name))
134134
}
135135

136+
// Comment adds comment lines to the active function.
137+
func (c *Context) Comment(lines ...string) {
138+
c.activefunc().AddComment(lines...)
139+
}
140+
136141
func (c *Context) activefunc() *ir.Function {
137142
if c.function == nil {
138143
c.adderrormessage("no active function")

build/global.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,5 +125,8 @@ func AllocLocal(size int) operand.Mem { return ctx.AllocLocal(size) }
125125
// Label adds a label to the active function.
126126
func Label(name string) { ctx.Label(name) }
127127

128+
// Comment adds comment lines to the active function.
129+
func Comment(lines ...string) { ctx.Comment(lines...) }
130+
128131
// ConstData builds a static data section containing just the given constant.
129132
func ConstData(name string, v operand.Constant) operand.Mem { return ctx.ConstData(name, v) }

ir/ir.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@ type Label string
2020

2121
func (l Label) node() {}
2222

23+
// Comment represents a multi-line comment.
24+
type Comment struct {
25+
Lines []string
26+
}
27+
28+
func (c *Comment) node() {}
29+
30+
// NewComment builds a Comment consisting of the provided lines.
31+
func NewComment(lines ...string) *Comment {
32+
return &Comment{
33+
Lines: lines,
34+
}
35+
}
36+
2337
// Instruction is a single instruction in a function.
2438
type Instruction struct {
2539
Opcode string
@@ -176,6 +190,11 @@ func (f *Function) AddLabel(l Label) {
176190
f.AddNode(l)
177191
}
178192

193+
// AddComment adds comment lines to f.
194+
func (f *Function) AddComment(lines ...string) {
195+
f.AddNode(NewComment(lines...))
196+
}
197+
179198
// AddNode appends a Node to f.
180199
func (f *Function) AddNode(n Node) {
181200
f.Nodes = append(f.Nodes, n)

pass/cfg.go

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,27 @@ import (
1111
// label name to the following instruction.
1212
func LabelTarget(fn *ir.Function) error {
1313
target := map[ir.Label]*ir.Instruction{}
14-
for idx := 0; idx < len(fn.Nodes); idx++ {
15-
// Is this a label?
16-
lbl, ok := fn.Nodes[idx].(ir.Label)
17-
if !ok {
18-
continue
19-
}
20-
// Check for a duplicate label.
21-
if _, found := target[lbl]; found {
22-
return fmt.Errorf("duplicate label \"%s\"", lbl)
23-
}
24-
// Advance to next node.
25-
if idx == len(fn.Nodes)-1 {
26-
return errors.New("function ends with label")
27-
}
28-
idx++
29-
// Should be an instruction.
30-
i, ok := fn.Nodes[idx].(*ir.Instruction)
31-
if !ok {
32-
return errors.New("instruction should follow a label")
14+
var empty ir.Label
15+
pending := empty
16+
for _, node := range fn.Nodes {
17+
switch n := node.(type) {
18+
case ir.Label:
19+
if pending != empty {
20+
return errors.New("instruction should follow a label")
21+
}
22+
pending = n
23+
if _, found := target[pending]; found {
24+
return fmt.Errorf("duplicate label \"%s\"", pending)
25+
}
26+
case *ir.Instruction:
27+
if pending != empty {
28+
target[pending] = n
29+
pending = empty
30+
}
3331
}
34-
target[lbl] = i
32+
}
33+
if pending != empty {
34+
return errors.New("function ends with label")
3535
}
3636
fn.LabelTarget = target
3737
return nil

pass/cfg_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ func TestLabelTarget(t *testing.T) {
1818
f := ir.NewFunction("happypath")
1919
for lbl, i := range expect {
2020
f.AddLabel(lbl)
21+
f.AddComment("comments should be ignored")
2122
f.AddInstruction(i)
2223
f.AddInstruction(&ir.Instruction{Opcode: "IDK"})
2324
}

printer/goasm.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ func (p *goasm) function(f *ir.Function) {
8484
p.Printf(", %s\n", textsize(f))
8585

8686
w := p.tabwriter()
87+
clear := true
88+
flush := func() {
89+
w.Flush()
90+
w = p.tabwriter()
91+
if !clear {
92+
p.NL()
93+
clear = true
94+
}
95+
}
8796
for _, node := range f.Nodes {
8897
switch n := node.(type) {
8998
case *ir.Instruction:
@@ -93,10 +102,15 @@ func (p *goasm) function(f *ir.Function) {
93102
fmt.Fprintf(w, "\t%s", joinOperands(n.Operands))
94103
}
95104
fmt.Fprint(w, "\n")
105+
clear = false
96106
case ir.Label:
97-
w.Flush()
98-
w = p.tabwriter()
99-
p.Printf("\n%s:\n", n)
107+
flush()
108+
p.Printf("%s:\n", n)
109+
case *ir.Comment:
110+
flush()
111+
for _, line := range n.Lines {
112+
p.Printf("\t// %s\n", line)
113+
}
100114
default:
101115
panic("unexpected node type")
102116
}

tests/fmt/asm.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// +build ignore
2+
3+
package main
4+
5+
import (
6+
. "github.com/mmcloughlin/avo/build"
7+
. "github.com/mmcloughlin/avo/reg"
8+
)
9+
10+
func main() {
11+
TEXT("Formatting", NOSPLIT, "func()")
12+
Doc("Formatting contains various cases to test the formatter.")
13+
14+
ADDQ(R8, R8)
15+
Comment("One comment line between instructions.")
16+
ADDQ(R8, R8)
17+
18+
Comment("Comment before label.")
19+
Label("label")
20+
Comment("Comment after label.")
21+
ADDQ(R8, R8)
22+
23+
RET()
24+
25+
Generate()
26+
}

tests/fmt/fmt.s

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Code generated by command: go run asm.go -out fmt.s -stubs stub.go. DO NOT EDIT.
2+
3+
#include "textflag.h"
4+
5+
// func Formatting()
6+
TEXT ·Formatting(SB), NOSPLIT, $0
7+
ADDQ R8, R8
8+
9+
// One comment line between instructions.
10+
ADDQ R8, R8
11+
12+
// Comment before label.
13+
label:
14+
// Comment after label.
15+
ADDQ R8, R8
16+
RET

tests/fmt/gen.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Package fmt tests assembly printer formatting.
2+
package fmt
3+
4+
//go:generate go run asm.go -out fmt.s -stubs stub.go

tests/fmt/stub.go

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)