Skip to content

Commit

Permalink
Starting to build xform2 to use the new IR format
Browse files Browse the repository at this point in the history
  • Loading branch information
rj45 committed Dec 21, 2021
1 parent 6c4f66d commit 03be68e
Show file tree
Hide file tree
Showing 8 changed files with 353 additions and 10 deletions.
16 changes: 16 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@
- [x] Get it to parse programs to ir2
- [x] Handle translating tuples to multiple return values
- [x] Can emit IR code in a way that simplifies text, assembly and html generation
- [ ] Emits to ssa.html
- [ ] Implement a simplified type system
- [ ] integer types i/u 8,16,32,64
- [ ] bool type
Expand Down Expand Up @@ -232,6 +233,21 @@
- [ ] Refactor: better package naming
- [ ] Generate unique package names
- [ ] Identifiers in other packages are pkg_name.ident rather than pkg_name__ident
- [ ] Use github.com/nochso/ctxerr for error messages
- [ ] Transform xform pkg to use new IR
- [x] Register func with options for config
- [x] grabs name from passed xform func
- [x] tags
- [x] list of active stages
- [x] activating op
- [x] can be run on each instr
- [ ] can be run on each block
- [x] takes a func that takes an iterator
- [x] xform func responsible for leaving iterator in a resumable position
- [x] iterator tracks changes
- [x] ability to tell the iterator a change was made it can't see
- [ ] A way to run a single transform for testing w/tags
- [ ] A way to run a single stage for testing w/tags

- [ ] Rework xform system

Expand Down
5 changes: 5 additions & 0 deletions compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import (
"github.com/rj45/nanogo/parser"
"github.com/rj45/nanogo/regalloc"
"github.com/rj45/nanogo/xform"
"github.com/rj45/nanogo/xform2"

_ "github.com/rj45/nanogo/xform2/elaboration"
)

type Arch interface {
Expand Down Expand Up @@ -121,6 +124,8 @@ func Compile(outname, dir string, patterns []string, mode Mode) int {
fe.Scan()
for fn := fe.NextUnparsedFunc(); fn != nil; fn = fe.NextUnparsedFunc() {
fe.ParseFunc(fn)

xform2.Transform(xform2.Elaboration, fn)
}

fe.Program().Emit(finalout, ir2.SSAString{})
Expand Down
2 changes: 1 addition & 1 deletion ir2/instr.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func (in *Instr) Args() []*Value {

// NumArgs returns the number of arguments
func (in *Instr) NumArgs() int {
return len(in.defs)
return len(in.args)
}

// ArgIndex returns the index of the arg, or
Expand Down
84 changes: 75 additions & 9 deletions ir2/iters.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,61 @@ import (
"go/types"
)

// Iter is a iterator over instructions
type Iter interface {
// Instr returns the current instruction
Instr() *Instr

// InstrIndex returns the index of the current instruction in the Block
InstrIndex() int

// Block returns the current block
Block() *Block

// BlockIndex returns the index of the Block within the Func
BlockIndex() int

// HasNext returns whether Next() will succeed
HasNext() bool

// Next increments the position and returns whether that was successful
Next() bool

// HasPrev returns whether Prev() will succeed
HasPrev() bool

// Prev decrements the position and returns whether that was successful
Prev() bool

// Insert inserts an instruction at the cursor position and increments the position
Insert(op Op, typ types.Type, args ...interface{}) *Instr

// Remove will remove the instruction at the current position and decrement the position,
// returning the removed instruction.
// NOTE: this only removes the instruction from the Block, it does not Unlink() it from
// any uses.
Remove() *Instr

// Update updates the instruction at the cursor position
Update(op Op, typ types.Type, args ...interface{}) *Instr

// HasChanged returns true if `Changed()` was called, or one of the mutation methods
HasChanged() bool

// Changed forces `HasChanged()` to return true
Changed()
}

var _ Iter = &BlockIter{}
var _ Iter = &CrossBlockIter{}

/// in-block iterator

// BlockIter is an iterator that iterates over instructions in a Block
type BlockIter struct {
blk *Block
insIdx int
blk *Block
insIdx int
changed bool
}

// InstrIter will return an Iter which iterates over every
Expand Down Expand Up @@ -74,13 +123,25 @@ func (it *BlockIter) HasPrev() bool {
return it.insIdx >= 0 // todo: there is a bug here
}

// HasChanged returns true if `Changed()` was called, or one of the mutation methods
func (it *BlockIter) HasChanged() bool {
return it.changed
}

// Changed forces `HasChanged()` to return true
func (it *BlockIter) Changed() {
it.changed = true
}

// Insert inserts an instruction at the cursor position and increments the position
func (it *BlockIter) Insert(op Op, typ types.Type, args ...interface{}) *Instr {
instr := it.blk.fn.NewInstr(op, typ, args...)

it.blk.InsertInstr(it.insIdx, instr)
it.Next()

it.changed = true

return instr
}

Expand All @@ -95,6 +156,8 @@ func (it *BlockIter) Remove() *Instr {
it.blk.RemoveInstr(instr)
it.Prev()

it.changed = true

return instr
}

Expand All @@ -104,6 +167,8 @@ func (it *BlockIter) Update(op Op, typ types.Type, args ...interface{}) *Instr {

instr.Update(op, typ, args...)

it.changed = true

return instr
}

Expand All @@ -128,24 +193,25 @@ func (fn *Func) InstrIter() *CrossBlockIter {

// HasNext returns whether Next() will succeed
func (it *CrossBlockIter) HasNext() bool {
return it.insIdx < len(it.blk.instrs) && it.blkIdx < len(it.fn.blocks)
return (it.insIdx+1) < len(it.blk.instrs) || (it.blkIdx+1) < len(it.fn.blocks)
}

// Next increments the position and returns whether that was successful
func (it *CrossBlockIter) Next() bool {
if it.insIdx >= len(it.blk.instrs) {
if (it.blkIdx + 1) >= len(it.fn.blocks) {
return false
}
if !it.HasNext() {
return false
}

it.insIdx++

if it.insIdx >= len(it.blk.instrs) {
it.blkIdx++
it.insIdx = 0
it.blk = it.fn.blocks[it.blkIdx]
return true
}

it.insIdx++
return it.insIdx < len(it.blk.instrs)
return true
}

// HasPrev returns whether Prev() will succeed
Expand Down
1 change: 1 addition & 0 deletions ir2/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ const (
VFunc
VTemp
VReg
VArg
VStack
VGlob
VHeap
Expand Down
87 changes: 87 additions & 0 deletions xform2/elaboration/calls.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package elaboration

import (
"go/types"
"log"

"github.com/rj45/nanogo/ir/op"
"github.com/rj45/nanogo/ir/reg"
"github.com/rj45/nanogo/ir2"
"github.com/rj45/nanogo/xform2"
)

var _ = xform2.Register(calls,
xform2.OnlyPass(xform2.Elaboration),
xform2.OnOp(op.Call),
)

func calls(it ir2.Iter) {
instr := it.Instr()
fnType := instr.Arg(0).Type.(*types.Signature)

if instr.NumArgs() > 1 && instr.Arg(1).Def() != nil && instr.Arg(1).Def().Op == op.Copy {
log.Println("arg copy already done")
return
}

if instr.NumDefs() > 0 && instr.Def(0).NumUses() == 1 && instr.Def(0).Use(0).Op == op.Copy {
log.Println("result copy already done")
return
}

// todo:
// - add parallel copy for clobbered regs?

if instr.NumArgs() > 1 {
params := fnType.Params()

args := make([]interface{}, instr.NumArgs()-1)
for i := 1; i < instr.NumArgs(); i++ {
args[i-1] = instr.Arg(i)
}

paramCopy := it.Insert(op.Copy, params, args...)
log.Println(paramCopy.LongString())
for i := 0; i < paramCopy.NumDefs(); i++ {
if i < len(reg.ArgRegs) {
paramCopy.Def(i).Loc = ir2.VReg
paramCopy.Def(i).Index = reg.ArgRegs[i].RegNumber()
} else {
paramCopy.Def(i).Loc = ir2.VArg
paramCopy.Def(i).Index = i - len(reg.ArgRegs)
}
instr.ReplaceArg(i+1, paramCopy.Def(i))
}
}

if instr.NumDefs() > 0 {
results := fnType.Results()

args := make([]interface{}, instr.NumDefs())
for i := 0; i < instr.NumDefs(); i++ {
args[i] = instr.Def(i)
}

it.Next()
resCopy := it.Insert(op.Copy, results, args...)
log.Println(resCopy.LongString())
for i := 0; i < resCopy.NumArgs(); i++ {
if i < len(reg.ArgRegs) {
resCopy.Arg(i).Loc = ir2.VReg
resCopy.Arg(i).Index = reg.ArgRegs[i].RegNumber()
} else {
resCopy.Arg(i).Loc = ir2.VArg
resCopy.Arg(i).Index = i - len(reg.ArgRegs)
}

// todo: could use a version of this that doesn't
// clobber the current instruction or something
instr.Def(i).ReplaceUsesWith(resCopy.Def(i))

// switch this back to what it was
resCopy.ReplaceArg(i, instr.Def(i))
}
}

log.Println(instr.LongString())
}
25 changes: 25 additions & 0 deletions xform2/tag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package xform2

type Tag uint8

const (
Invalid Tag = iota
HasFramePointer

// ...

NumTags
)

var activeTags []bool

type Arch interface {
XformTags() []Tag
}

func SetArch(a Arch) {
activeTags = make([]bool, NumTags)
for _, tag := range a.XformTags() {
activeTags[tag] = true
}
}
Loading

0 comments on commit 03be68e

Please sign in to comment.