blob: 51c72aacd9910e77741d3a6b6af71f67a2d17aad [file] [log] [blame]
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ssa
import (
"bytes"
"fmt"
"os"
)
// cgen selects machine instructions for the function.
// This pass generates assembly output for now, but should
// TODO(khr): generate binary output (via liblink?) instead of text.
func cgen(f *Func) {
fmt.Printf("TEXT %s(SB),0,$0\n", f.Name) // TODO: frame size / arg size
// TODO: prolog, allocate stack frame
for idx, b := range f.Blocks {
fmt.Printf("%d:\n", b.ID)
for _, v := range b.Values {
var buf bytes.Buffer
asm := opcodeTable[v.Op].asm
buf.WriteString(" ")
for i := 0; i < len(asm); i++ {
switch asm[i] {
default:
buf.WriteByte(asm[i])
case '\t':
buf.WriteByte(' ')
for buf.Len()%8 != 0 {
buf.WriteByte(' ')
}
case '%':
i++
switch asm[i] {
case '%':
buf.WriteByte('%')
case 'I':
i++
n := asm[i] - '0'
if f.RegAlloc[v.Args[n].ID] != nil {
buf.WriteString(f.RegAlloc[v.Args[n].ID].Name())
} else {
fmt.Fprintf(&buf, "v%d", v.Args[n].ID)
}
case 'O':
i++
n := asm[i] - '0'
if n != 0 {
panic("can only handle 1 output for now")
}
if f.RegAlloc[v.ID] != nil {
buf.WriteString(f.RegAlloc[v.ID].Name())
} else {
fmt.Fprintf(&buf, "v%d", v.ID)
}
case 'A':
fmt.Fprint(&buf, v.Aux)
}
}
}
for buf.Len() < 40 {
buf.WriteByte(' ')
}
buf.WriteString("; ")
buf.WriteString(v.LongString())
buf.WriteByte('\n')
os.Stdout.Write(buf.Bytes())
}
// find next block in layout sequence
var next *Block
if idx < len(f.Blocks)-1 {
next = f.Blocks[idx+1]
}
// emit end of block code
// TODO: this is machine specific
switch b.Kind {
case BlockPlain:
if b.Succs[0] != next {
fmt.Printf("\tJMP\t%d\n", b.Succs[0].ID)
}
case BlockExit:
// TODO: run defers (if any)
// TODO: deallocate frame
fmt.Println("\tRET")
case BlockCall:
// nothing to emit - call instruction already happened
case BlockEQ:
if b.Succs[0] == next {
fmt.Printf("\tJNE\t%d\n", b.Succs[1].ID)
} else if b.Succs[1] == next {
fmt.Printf("\tJEQ\t%d\n", b.Succs[0].ID)
} else {
fmt.Printf("\tJEQ\t%d\n", b.Succs[0].ID)
fmt.Printf("\tJMP\t%d\n", b.Succs[1].ID)
}
case BlockNE:
if b.Succs[0] == next {
fmt.Printf("\tJEQ\t%d\n", b.Succs[1].ID)
} else if b.Succs[1] == next {
fmt.Printf("\tJNE\t%d\n", b.Succs[0].ID)
} else {
fmt.Printf("\tJNE\t%d\n", b.Succs[0].ID)
fmt.Printf("\tJMP\t%d\n", b.Succs[1].ID)
}
case BlockLT:
if b.Succs[0] == next {
fmt.Printf("\tJGE\t%d\n", b.Succs[1].ID)
} else if b.Succs[1] == next {
fmt.Printf("\tJLT\t%d\n", b.Succs[0].ID)
} else {
fmt.Printf("\tJLT\t%d\n", b.Succs[0].ID)
fmt.Printf("\tJMP\t%d\n", b.Succs[1].ID)
}
case BlockULT:
if b.Succs[0] == next {
fmt.Printf("\tJAE\t%d\n", b.Succs[1].ID)
} else if b.Succs[1] == next {
fmt.Printf("\tJB\t%d\n", b.Succs[0].ID)
} else {
fmt.Printf("\tJB\t%d\n", b.Succs[0].ID)
fmt.Printf("\tJMP\t%d\n", b.Succs[1].ID)
}
default:
fmt.Printf("\t%s ->", b.Kind.String())
for _, s := range b.Succs {
fmt.Printf(" %d", s.ID)
}
fmt.Printf("\n")
}
}
}