1
0
mirror of https://github.com/golang/go synced 2024-10-05 18:21:21 -06:00

[dev.ssa] cmd/compile/internal/ssa: remove cgen pass

Code generation is now done in genssa.
Also remove the asm field in opInfo. It's no longer used.

Change-Id: I65fffac267e138fd424b2ef8aa7ed79f0ebb63d5
Reviewed-on: https://go-review.googlesource.com/10539
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Michael Matloob 2015-05-29 13:47:38 -04:00 committed by Keith Randall
parent 067e8dfd82
commit 7bdecbf840
5 changed files with 29 additions and 174 deletions

View File

@ -25,7 +25,6 @@ Values
Opcodes
- Rename ops to prevent cross-arch conflicts. MOVQ -> MOVQamd64 (or
MOVQ6?). Other option: build opcode table in Config instead of globally.
- Remove asm string from opinfo, no longer needed.
- It's annoying to list the opcode both in the opcode list and an
opInfo map entry. Specify it one place and use go:generate to
produce both?

View File

@ -1,135 +0,0 @@
// 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")
}
}
}

View File

@ -65,7 +65,6 @@ var passes = [...]pass{
{"schedule", schedule}, // schedule values
{"regalloc", regalloc},
{"stackalloc", stackalloc},
{"cgen", cgen},
}
// Double-check phase ordering constraints.
@ -85,8 +84,6 @@ var passOrder = [...]constraint{
{"schedule", "regalloc"},
// stack allocation requires register allocation
{"regalloc", "stackalloc"},
// code generation requires stack allocation
{"stackalloc", "cgen"},
}
func init() {

View File

@ -118,12 +118,6 @@ func (g GlobalOffset) String() string {
type opInfo struct {
flags int32
// assembly template
// %In: location of input n
// %On: location of output n
// %A: print aux with fmt.Print
asm string
// returns a reg constraint for the instruction. [0] gives a reg constraint
// for each input, [1] gives a reg constraint for each output. (Values have
// exactly one output for now)

View File

@ -123,39 +123,39 @@ var (
// 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},
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: {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},
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, 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},
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: {},
@ -164,10 +164,10 @@ var amd64Table = map[Op]opInfo{
// 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() {