mirror of
https://github.com/golang/go
synced 2024-10-05 20:31:20 -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:
parent
067e8dfd82
commit
7bdecbf840
@ -25,7 +25,6 @@ Values
|
|||||||
Opcodes
|
Opcodes
|
||||||
- Rename ops to prevent cross-arch conflicts. MOVQ -> MOVQamd64 (or
|
- Rename ops to prevent cross-arch conflicts. MOVQ -> MOVQamd64 (or
|
||||||
MOVQ6?). Other option: build opcode table in Config instead of globally.
|
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
|
- 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
|
opInfo map entry. Specify it one place and use go:generate to
|
||||||
produce both?
|
produce both?
|
||||||
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -65,7 +65,6 @@ var passes = [...]pass{
|
|||||||
{"schedule", schedule}, // schedule values
|
{"schedule", schedule}, // schedule values
|
||||||
{"regalloc", regalloc},
|
{"regalloc", regalloc},
|
||||||
{"stackalloc", stackalloc},
|
{"stackalloc", stackalloc},
|
||||||
{"cgen", cgen},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Double-check phase ordering constraints.
|
// Double-check phase ordering constraints.
|
||||||
@ -85,8 +84,6 @@ var passOrder = [...]constraint{
|
|||||||
{"schedule", "regalloc"},
|
{"schedule", "regalloc"},
|
||||||
// stack allocation requires register allocation
|
// stack allocation requires register allocation
|
||||||
{"regalloc", "stackalloc"},
|
{"regalloc", "stackalloc"},
|
||||||
// code generation requires stack allocation
|
|
||||||
{"stackalloc", "cgen"},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -118,12 +118,6 @@ func (g GlobalOffset) String() string {
|
|||||||
type opInfo struct {
|
type opInfo struct {
|
||||||
flags int32
|
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
|
// 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
|
// for each input, [1] gives a reg constraint for each output. (Values have
|
||||||
// exactly one output for now)
|
// exactly one output for now)
|
||||||
|
@ -123,39 +123,39 @@ var (
|
|||||||
|
|
||||||
// Opcodes that appear in an output amd64 program
|
// Opcodes that appear in an output amd64 program
|
||||||
var amd64Table = map[Op]opInfo{
|
var amd64Table = map[Op]opInfo{
|
||||||
OpADDQ: {flags: OpFlagCommutative, asm: "ADDQ\t%I0,%I1,%O0", reg: gp21}, // TODO: overwrite
|
OpADDQ: {flags: OpFlagCommutative, reg: gp21}, // TODO: overwrite
|
||||||
OpADDQconst: {asm: "ADDQ\t$%A,%I0,%O0", reg: gp11}, // aux = int64 constant to add
|
OpADDQconst: {reg: gp11}, // aux = int64 constant to add
|
||||||
OpSUBQ: {asm: "SUBQ\t%I0,%I1,%O0", reg: gp21},
|
OpSUBQ: {reg: gp21},
|
||||||
OpSUBQconst: {asm: "SUBQ\t$%A,%I0,%O0", reg: gp11},
|
OpSUBQconst: {reg: gp11},
|
||||||
OpMULQ: {asm: "MULQ\t%I0,%I1,%O0", reg: gp21},
|
OpMULQ: {reg: gp21},
|
||||||
OpMULQconst: {asm: "IMULQ\t$%A,%I0,%O0", reg: gp11},
|
OpMULQconst: {reg: gp11},
|
||||||
OpSHLQ: {asm: "SHLQ\t%I0,%I1,%O0", reg: gp21},
|
OpSHLQ: {reg: gp21},
|
||||||
OpSHLQconst: {asm: "SHLQ\t$%A,%I0,%O0", reg: gp11},
|
OpSHLQconst: {reg: gp11},
|
||||||
|
|
||||||
OpCMPQ: {asm: "CMPQ\t%I0,%I1", reg: gp2_flags}, // compute arg[0]-arg[1] and produce flags
|
OpCMPQ: {reg: gp2_flags}, // compute arg[0]-arg[1] and produce flags
|
||||||
OpCMPQconst: {asm: "CMPQ\t$%A,%I0", reg: gp1_flags},
|
OpCMPQconst: {reg: gp1_flags},
|
||||||
OpTESTQ: {asm: "TESTQ\t%I0,%I1", reg: gp2_flags},
|
OpTESTQ: {reg: gp2_flags},
|
||||||
OpTESTB: {asm: "TESTB\t%I0,%I1", 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
|
OpLEAQ: {flags: OpFlagCommutative, reg: gp21}, // aux = int64 constant to add
|
||||||
OpLEAQ2: {asm: "LEAQ\t%A(%I0)(%I1*2),%O0"},
|
OpLEAQ2: {},
|
||||||
OpLEAQ4: {asm: "LEAQ\t%A(%I0)(%I1*4),%O0"},
|
OpLEAQ4: {},
|
||||||
OpLEAQ8: {asm: "LEAQ\t%A(%I0)(%I1*8),%O0"},
|
OpLEAQ8: {},
|
||||||
OpLEAQglobal: {asm: "LEAQ\t%A(SB),%O0", reg: gp01},
|
OpLEAQglobal: {reg: gp01},
|
||||||
|
|
||||||
// loads and stores
|
// loads and stores
|
||||||
OpMOVBload: {asm: "MOVB\t%A(%I0),%O0", reg: gpload},
|
OpMOVBload: {reg: gpload},
|
||||||
OpMOVQload: {asm: "MOVQ\t%A(%I0),%O0", reg: gpload},
|
OpMOVQload: {reg: gpload},
|
||||||
OpMOVQstore: {asm: "MOVQ\t%I1,%A(%I0)", reg: gpstore},
|
OpMOVQstore: {reg: gpstore},
|
||||||
OpMOVQloadidx8: {asm: "MOVQ\t%A(%I0)(%I1*8),%O0", reg: gploadidx},
|
OpMOVQloadidx8: {reg: gploadidx},
|
||||||
OpMOVQstoreidx8: {asm: "MOVQ\t%I2,%A(%I0)(%I1*8)", reg: gpstoreidx},
|
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
|
OpCopy: {reg: gp11}, // TODO: make arch-specific
|
||||||
OpConvNop: {asm: "MOVQ\t%I0,%O0", reg: gp11}, // TODO: make arch-specific. Or get rid of this altogether.
|
OpConvNop: {reg: gp11}, // TODO: make arch-specific. Or get rid of this altogether.
|
||||||
|
|
||||||
// convert from flags back to boolean
|
// convert from flags back to boolean
|
||||||
OpSETL: {},
|
OpSETL: {},
|
||||||
@ -164,10 +164,10 @@ var amd64Table = map[Op]opInfo{
|
|||||||
// unlike regular loads & stores, these take no memory argument.
|
// unlike regular loads & stores, these take no memory argument.
|
||||||
// They are just like OpCopy but we use them during register allocation.
|
// They are just like OpCopy but we use them during register allocation.
|
||||||
// TODO: different widths, float
|
// TODO: different widths, float
|
||||||
OpLoadReg8: {asm: "MOVQ\t%I0,%O0"},
|
OpLoadReg8: {},
|
||||||
OpStoreReg8: {asm: "MOVQ\t%I0,%O0"},
|
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() {
|
func init() {
|
||||||
|
Loading…
Reference in New Issue
Block a user