Skip to content

Commit

Permalink
build: support comments in functions (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
mmcloughlin committed Jan 11, 2019
1 parent 27cea3b commit 284ee13
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 23 deletions.
5 changes: 5 additions & 0 deletions build/context.go
Expand Up @@ -133,6 +133,11 @@ func (c *Context) Label(name string) {
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 {
if c.function == nil {
c.adderrormessage("no active function")
Expand Down
3 changes: 3 additions & 0 deletions build/global.go
Expand Up @@ -125,5 +125,8 @@ func AllocLocal(size int) operand.Mem { return ctx.AllocLocal(size) }
// Label adds a label to the active function.
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.
func ConstData(name string, v operand.Constant) operand.Mem { return ctx.ConstData(name, v) }
19 changes: 19 additions & 0 deletions ir/ir.go
Expand Up @@ -20,6 +20,20 @@ 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
Expand Down Expand Up @@ -176,6 +190,11 @@ 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)
Expand Down
40 changes: 20 additions & 20 deletions pass/cfg.go
Expand Up @@ -11,27 +11,27 @@ import (
// label name to the following instruction.
func LabelTarget(fn *ir.Function) error {
target := map[ir.Label]*ir.Instruction{}
for idx := 0; idx < len(fn.Nodes); idx++ {
// Is this a label?
lbl, ok := fn.Nodes[idx].(ir.Label)
if !ok {
continue
}
// Check for a duplicate label.
if _, found := target[lbl]; found {
return fmt.Errorf("duplicate label \"%s\"", lbl)
}
// 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")
var empty ir.Label
pending := empty
for _, node := range fn.Nodes {
switch n := node.(type) {
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
}
}
target[lbl] = i
}
if pending != empty {
return errors.New("function ends with label")
}
fn.LabelTarget = target
return nil
Expand Down
1 change: 1 addition & 0 deletions pass/cfg_test.go
Expand Up @@ -18,6 +18,7 @@ func TestLabelTarget(t *testing.T) {
f := ir.NewFunction("happypath")
for lbl, i := range expect {
f.AddLabel(lbl)
f.AddComment("comments should be ignored")
f.AddInstruction(i)
f.AddInstruction(&ir.Instruction{Opcode: "IDK"})
}
Expand Down
20 changes: 17 additions & 3 deletions printer/goasm.go
Expand Up @@ -84,6 +84,15 @@ func (p *goasm) function(f *ir.Function) {
p.Printf(", %s\n", textsize(f))

w := p.tabwriter()
clear := true
flush := func() {
w.Flush()
w = p.tabwriter()
if !clear {
p.NL()
clear = true
}
}
for _, node := range f.Nodes {
switch n := node.(type) {
case *ir.Instruction:
Expand All @@ -93,10 +102,15 @@ func (p *goasm) function(f *ir.Function) {
fmt.Fprintf(w, "\t%s", joinOperands(n.Operands))
}
fmt.Fprint(w, "\n")
clear = false
case ir.Label:
w.Flush()
w = p.tabwriter()
p.Printf("\n%s:\n", n)
flush()
p.Printf("%s:\n", n)
case *ir.Comment:
flush()
for _, line := range n.Lines {
p.Printf("\t// %s\n", line)
}
default:
panic("unexpected node type")
}
Expand Down
26 changes: 26 additions & 0 deletions tests/fmt/asm.go
@@ -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 changes: 16 additions & 0 deletions tests/fmt/fmt.s
@@ -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 changes: 4 additions & 0 deletions tests/fmt/gen.go
@@ -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 changes: 6 additions & 0 deletions tests/fmt/stub.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 284ee13

Please sign in to comment.