+++ /dev/null
-// 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")
- }
- }
-}
// Opcodes that appear in an output amd64 program
var amd64Table = map[Op]opInfo{
- OpADDQ: {flags: OpFlagCommutative, asm: "ADDQ\t%I0,%I1,%O0", reg: gp21}, // TODO: overwrite
- OpADDQconst: {asm: "ADDQ\t$%A,%I0,%O0", reg: gp11}, // aux = int64 constant to add
- OpSUBQ: {asm: "SUBQ\t%I0,%I1,%O0", reg: gp21},
- OpSUBQconst: {asm: "SUBQ\t$%A,%I0,%O0", reg: gp11},
- OpMULQ: {asm: "MULQ\t%I0,%I1,%O0", reg: gp21},
- OpMULQconst: {asm: "IMULQ\t$%A,%I0,%O0", reg: gp11},
- OpSHLQ: {asm: "SHLQ\t%I0,%I1,%O0", reg: gp21},
- OpSHLQconst: {asm: "SHLQ\t$%A,%I0,%O0", reg: gp11},
-
- OpCMPQ: {asm: "CMPQ\t%I0,%I1", reg: gp2_flags}, // compute arg[0]-arg[1] and produce flags
- OpCMPQconst: {asm: "CMPQ\t$%A,%I0", reg: gp1_flags},
- OpTESTQ: {asm: "TESTQ\t%I0,%I1", reg: gp2_flags},
- OpTESTB: {asm: "TESTB\t%I0,%I1", reg: gp2_flags},
-
- OpLEAQ: {flags: OpFlagCommutative, asm: "LEAQ\t%A(%I0)(%I1*1),%O0", reg: gp21}, // aux = int64 constant to add
- OpLEAQ2: {asm: "LEAQ\t%A(%I0)(%I1*2),%O0"},
- OpLEAQ4: {asm: "LEAQ\t%A(%I0)(%I1*4),%O0"},
- OpLEAQ8: {asm: "LEAQ\t%A(%I0)(%I1*8),%O0"},
- OpLEAQglobal: {asm: "LEAQ\t%A(SB),%O0", reg: gp01},
+ OpADDQ: {flags: OpFlagCommutative, reg: gp21}, // TODO: overwrite
+ OpADDQconst: {reg: gp11}, // aux = int64 constant to add
+ OpSUBQ: {reg: gp21},
+ OpSUBQconst: {reg: gp11},
+ OpMULQ: {reg: gp21},
+ OpMULQconst: {reg: gp11},
+ OpSHLQ: {reg: gp21},
+ OpSHLQconst: {reg: gp11},
+
+ OpCMPQ: {reg: gp2_flags}, // compute arg[0]-arg[1] and produce flags
+ OpCMPQconst: {reg: gp1_flags},
+ OpTESTQ: {reg: gp2_flags},
+ OpTESTB: {reg: gp2_flags},
+
+ OpLEAQ: {flags: OpFlagCommutative, reg: gp21}, // aux = int64 constant to add
+ OpLEAQ2: {},
+ OpLEAQ4: {},
+ OpLEAQ8: {},
+ OpLEAQglobal: {reg: gp01},
// loads and stores
- OpMOVBload: {asm: "MOVB\t%A(%I0),%O0", reg: gpload},
- OpMOVQload: {asm: "MOVQ\t%A(%I0),%O0", reg: gpload},
- OpMOVQstore: {asm: "MOVQ\t%I1,%A(%I0)", reg: gpstore},
- OpMOVQloadidx8: {asm: "MOVQ\t%A(%I0)(%I1*8),%O0", reg: gploadidx},
- OpMOVQstoreidx8: {asm: "MOVQ\t%I2,%A(%I0)(%I1*8)", reg: gpstoreidx},
+ OpMOVBload: {reg: gpload},
+ OpMOVQload: {reg: gpload},
+ OpMOVQstore: {reg: gpstore},
+ OpMOVQloadidx8: {reg: gploadidx},
+ OpMOVQstoreidx8: {reg: gpstoreidx},
- OpMOVQconst: {asm: "MOVQ\t$%A,%O0", reg: gp01},
+ OpMOVQconst: {reg: gp01},
- OpStaticCall: {asm: "CALL\t%A(SB)"},
+ OpStaticCall: {},
- OpCopy: {asm: "MOVQ\t%I0,%O0", reg: gp11}, // TODO: make arch-specific
- OpConvNop: {asm: "MOVQ\t%I0,%O0", reg: gp11}, // TODO: make arch-specific. Or get rid of this altogether.
+ OpCopy: {reg: gp11}, // TODO: make arch-specific
+ OpConvNop: {reg: gp11}, // TODO: make arch-specific. Or get rid of this altogether.
// convert from flags back to boolean
OpSETL: {},
// unlike regular loads & stores, these take no memory argument.
// They are just like OpCopy but we use them during register allocation.
// TODO: different widths, float
- OpLoadReg8: {asm: "MOVQ\t%I0,%O0"},
- OpStoreReg8: {asm: "MOVQ\t%I0,%O0"},
+ OpLoadReg8: {},
+ OpStoreReg8: {},
- OpREPMOVSB: {asm: "REP MOVSB", reg: [2][]regMask{{di, si, cx, 0}, {0}}}, // TODO: record that si/di/cx are clobbered
+ OpREPMOVSB: {reg: [2][]regMask{{di, si, cx, 0}, {0}}}, // TODO: record that si/di/cx are clobbered
}
func init() {