mirror of
https://github.com/golang/go
synced 2024-10-05 20: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:
parent
067e8dfd82
commit
7bdecbf840
@ -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?
|
||||
|
@ -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
|
||||
{"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() {
|
||||
|
@ -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)
|
||||
|
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user