Commit 4c9a470d authored by Keith Randall's avatar Keith Randall

cmd/compile: start on ARM port

Start working on arm port.  Gets close to correct
code for fibonacci:
    func fib(n int) int {
        if n < 2 {
            return n
        }
        return fib(n-1) + fib(n-2)
    }

Still a lot to do, but this is a good starting point.

Cleaned up some arch-specific dependencies in regalloc.

Change-Id: I4301c6c31a8402168e50dcfee8bcf7aee73ea9d5
Reviewed-on: https://go-review.googlesource.com/21000Reviewed-by: 's avatarDavid Chase <drchase@google.com>
parent 44d3f89e
......@@ -6,6 +6,7 @@ package arm
import (
"cmd/compile/internal/gc"
"cmd/compile/internal/ssa"
"cmd/internal/obj/arm"
)
......@@ -65,6 +66,11 @@ func Main() {
gc.Thearch.Doregbits = doregbits
gc.Thearch.Regnames = regnames
gc.Thearch.SSARegToReg = ssaRegToReg
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
gc.Thearch.SSAGenValue = ssaGenValue
gc.Thearch.SSAGenBlock = ssaGenBlock
gc.Main()
gc.Exit(0)
}
// Copyright 2016 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 arm
import (
"cmd/compile/internal/gc"
"cmd/compile/internal/ssa"
"cmd/internal/obj"
"cmd/internal/obj/arm"
)
var ssaRegToReg = []int16{
arm.REG_R0,
arm.REG_R1,
arm.REG_R2,
arm.REG_R3,
arm.REGSP, // aka R13
}
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line)
switch v.Op {
case ssa.OpInitMem:
// memory arg needs no code
case ssa.OpArg:
// input args need no code
case ssa.OpSP, ssa.OpSB:
// nothing to do
case ssa.OpCopy:
case ssa.OpLoadReg:
// TODO: by type
p := gc.Prog(arm.AMOVW)
n, off := gc.AutoVar(v.Args[0])
p.From.Type = obj.TYPE_MEM
p.From.Node = n
p.From.Sym = gc.Linksym(n.Sym)
p.From.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.From.Name = obj.NAME_PARAM
p.From.Offset += n.Xoffset
} else {
p.From.Name = obj.NAME_AUTO
}
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
case ssa.OpStoreReg:
// TODO: by type
p := gc.Prog(arm.AMOVW)
p.From.Type = obj.TYPE_REG
p.From.Reg = gc.SSARegNum(v.Args[0])
n, off := gc.AutoVar(v)
p.To.Type = obj.TYPE_MEM
p.To.Node = n
p.To.Sym = gc.Linksym(n.Sym)
p.To.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.To.Name = obj.NAME_PARAM
p.To.Offset += n.Xoffset
} else {
p.To.Name = obj.NAME_AUTO
}
case ssa.OpARMADD:
r := gc.SSARegNum(v)
r1 := gc.SSARegNum(v.Args[0])
r2 := gc.SSARegNum(v.Args[1])
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = r1
p.Reg = r2
p.To.Type = obj.TYPE_REG
p.To.Reg = r
case ssa.OpARMADDconst:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt
if v.Aux != nil {
panic("can't handle symbolic constant yet")
}
p.Reg = gc.SSARegNum(v.Args[0])
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
case ssa.OpARMMOVWconst:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt2Int64()
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
case ssa.OpARMCMP:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = gc.SSARegNum(v.Args[0])
p.Reg = gc.SSARegNum(v.Args[1])
case ssa.OpARMMOVWload:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_MEM
p.From.Reg = gc.SSARegNum(v.Args[0])
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
case ssa.OpARMMOVWstore:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = gc.SSARegNum(v.Args[1])
p.To.Type = obj.TYPE_MEM
p.To.Reg = gc.SSARegNum(v.Args[0])
gc.AddAux(&p.To, v)
case ssa.OpARMCALLstatic:
// TODO: deferreturn
p := gc.Prog(obj.ACALL)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
p.To.Sym = gc.Linksym(v.Aux.(*gc.Sym))
if gc.Maxarg < v.AuxInt {
gc.Maxarg = v.AuxInt
}
case ssa.OpVarDef:
gc.Gvardef(v.Aux.(*gc.Node))
case ssa.OpVarKill:
gc.Gvarkill(v.Aux.(*gc.Node))
case ssa.OpVarLive:
gc.Gvarlive(v.Aux.(*gc.Node))
case ssa.OpARMLessThan:
v.Fatalf("pseudo-op made it to output: %s", v.LongString())
default:
v.Unimplementedf("genValue not implemented: %s", v.LongString())
}
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line)
switch b.Kind {
case ssa.BlockCall:
if b.Succs[0] != next {
p := gc.Prog(obj.AJMP)
p.To.Type = obj.TYPE_BRANCH
s.Branches = append(s.Branches, gc.Branch{p, b.Succs[0]})
}
case ssa.BlockRet:
gc.Prog(obj.ARET)
case ssa.BlockARMLT:
p := gc.Prog(arm.ABGE)
p.To.Type = obj.TYPE_BRANCH
s.Branches = append(s.Branches, gc.Branch{p, b.Succs[0]})
p = gc.Prog(obj.AJMP)
p.To.Type = obj.TYPE_BRANCH
s.Branches = append(s.Branches, gc.Branch{p, b.Succs[1]})
}
}
......@@ -30,8 +30,14 @@ func initssa() *ssa.Config {
}
func shouldssa(fn *Node) bool {
if Thearch.Thestring != "amd64" {
return false
switch Thearch.Thestring {
default:
// Only available for testing.
if os.Getenv("SSATEST") == "" {
return false
}
// Generally available.
case "amd64":
}
if !ssaEnabled {
return false
......
......@@ -18,6 +18,7 @@ type Config struct {
PtrSize int64 // 4 or 8
lowerBlock func(*Block) bool // lowering function
lowerValue func(*Value, *Config) bool // lowering function
registers []Register // machine registers
fe Frontend // callbacks into compiler frontend
HTML *HTMLWriter // html writer, for debugging
ctxt *obj.Link // Generic arch information
......@@ -112,11 +113,18 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
c.PtrSize = 8
c.lowerBlock = rewriteBlockAMD64
c.lowerValue = rewriteValueAMD64
c.registers = registersAMD64[:]
case "386":
c.IntSize = 4
c.PtrSize = 4
c.lowerBlock = rewriteBlockAMD64
c.lowerValue = rewriteValueAMD64 // TODO(khr): full 32-bit support
case "arm":
c.IntSize = 4
c.PtrSize = 4
c.lowerBlock = rewriteBlockARM
c.lowerValue = rewriteValueARM
c.registers = registersARM[:]
default:
fe.Unimplementedf(0, "arch %s not implemented", arch)
}
......
// Copyright 2016 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.
(Add32 x y) -> (ADD x y)
(Const32 [val]) -> (MOVWconst [val])
(Less32 x y) -> (LessThan (CMP x y))
(OffPtr [off] ptr) -> (ADD (MOVWconst <config.Frontend().TypeInt32()> [off]) ptr)
(Addr {sym} base) -> (ADDconst {sym} base)
(Load <t> ptr mem) && is32BitInt(t) -> (MOVWload ptr mem)
(Store [4] ptr val mem) -> (MOVWstore ptr val mem)
(StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem)
// Absorb LessThan into blocks.
(If (LessThan cc) yes no) -> (LT cc yes no)
// Optimizations
(ADD (MOVWconst [c]) x) -> (ADDconst [c] x)
(ADD x (MOVWconst [c])) -> (ADDconst [c] x)
(MOVWload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
(MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVWstore [off1] {sym1} (ADDconst [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
// Copyright 2016 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 main
func init() {
var (
gp01 = regInfo{inputs: []regMask{}, outputs: []regMask{31}}
gp11 = regInfo{inputs: []regMask{31}, outputs: []regMask{31}}
gp21 = regInfo{inputs: []regMask{31, 31}, outputs: []regMask{31}}
gp2flags = regInfo{inputs: []regMask{31, 31}, outputs: []regMask{32}}
gpload = regInfo{inputs: []regMask{31}, outputs: []regMask{31}}
gpstore = regInfo{inputs: []regMask{31, 31}, outputs: []regMask{}}
flagsgp = regInfo{inputs: []regMask{32}, outputs: []regMask{31}}
callerSave = regMask(15)
)
ops := []opData{
{name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0 + arg1
{name: "ADDconst", argLength: 1, reg: gp11, asm: "ADD", aux: "SymOff"}, // arg0 + auxInt + aux.(*gc.Sym)
{name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", rematerializeable: true}, // 32 low bits of auxint
{name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1
{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW"}, // load from arg0 + auxInt + aux. arg1=mem.
{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff"}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
// pseudo-ops
{name: "LessThan", argLength: 2, reg: flagsgp}, // bool, 1 flags encode x<y 0 otherwise.
}
blocks := []blockData{
{name: "EQ"},
{name: "NE"},
{name: "LT"},
{name: "LE"},
{name: "GT"},
{name: "GE"},
{name: "ULT"},
{name: "ULE"},
{name: "UGT"},
{name: "UGE"},
}
regNames := []string{
"R0",
"R1",
"R2",
"R3",
"SP",
"FLAGS",
"SB",
}
archs = append(archs, arch{
name: "ARM",
pkg: "cmd/internal/obj/arm",
genfile: "../../arm/ssa.go",
ops: ops,
blocks: blocks,
regnames: regNames,
})
}
......@@ -10,8 +10,9 @@ var decBlocks = []blockData{}
func init() {
archs = append(archs, arch{
name: "dec",
ops: decOps,
blocks: decBlocks,
name: "dec",
ops: decOps,
blocks: decBlocks,
generic: true,
})
}
......@@ -414,8 +414,9 @@ var genericBlocks = []blockData{
func init() {
archs = append(archs, arch{
name: "generic",
ops: genericOps,
blocks: genericBlocks,
name: "generic",
ops: genericOps,
blocks: genericBlocks,
generic: true,
})
}
......@@ -26,6 +26,7 @@ type arch struct {
ops []opData
blocks []blockData
regnames []string
generic bool
}
type opData struct {
......@@ -205,6 +206,18 @@ func genOp() {
// generate op string method
fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }")
// generate registers
for _, a := range archs {
if a.generic {
continue
}
fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name)
for i, r := range a.regnames {
fmt.Fprintf(w, " {%d, \"%s\"},\n", i, r)
}
fmt.Fprintln(w, "}")
}
// gofmt result
b := w.Bytes()
var err error
......
......@@ -55,6 +55,8 @@ const (
auxSym // aux is a symbol
auxSymOff // aux is a symbol, auxInt is an offset
auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff
auxSymInt32 // aux is a symbol, auxInt is a 32-bit integer
)
// A ValAndOff is used by the several opcodes. It holds
......
......@@ -5,6 +5,7 @@ package ssa
import (
"cmd/internal/obj"
"cmd/internal/obj/arm"
"cmd/internal/obj/x86"
)
......@@ -26,6 +27,17 @@ const (
BlockAMD64ORD
BlockAMD64NAN
BlockARMEQ
BlockARMNE
BlockARMLT
BlockARMLE
BlockARMGT
BlockARMGE
BlockARMULT
BlockARMULE
BlockARMUGT
BlockARMUGE
BlockPlain
BlockIf
BlockCall
......@@ -56,6 +68,17 @@ var blockString = [...]string{
BlockAMD64ORD: "ORD",
BlockAMD64NAN: "NAN",
BlockARMEQ: "EQ",
BlockARMNE: "NE",
BlockARMLT: "LT",
BlockARMLE: "LE",
BlockARMGT: "GT",
BlockARMGE: "GE",
BlockARMULT: "ULT",
BlockARMULE: "ULE",
BlockARMUGT: "UGT",
BlockARMUGE: "UGE",
BlockPlain: "Plain",
BlockIf: "If",
BlockCall: "Call",
......@@ -309,6 +332,15 @@ const (
OpAMD64FlagGT_UGT
OpAMD64FlagGT_ULT
OpARMADD
OpARMADDconst
OpARMMOVWconst
OpARMCMP
OpARMMOVWload
OpARMMOVWstore
OpARMCALLstatic
OpARMLessThan
OpAdd8
OpAdd16
OpAdd32
......@@ -3915,6 +3947,106 @@ var opcodeTable = [...]opInfo{
reg: regInfo{},
},
{
name: "ADD",
argLen: 2,
commutative: true,
asm: arm.AADD,
reg: regInfo{
inputs: []inputInfo{
{0, 31}, // R0 R1 R2 R3 SP
{1, 31}, // R0 R1 R2 R3 SP
},
outputs: []regMask{
31, // R0 R1 R2 R3 SP
},
},
},
{
name: "ADDconst",
auxType: auxSymOff,
argLen: 1,
asm: arm.AADD,
reg: regInfo{
inputs: []inputInfo{
{0, 31}, // R0 R1 R2 R3 SP
},
outputs: []regMask{
31, // R0 R1 R2 R3 SP
},
},
},
{
name: "MOVWconst",
auxType: auxInt32,
argLen: 0,
rematerializeable: true,
asm: arm.AMOVW,
reg: regInfo{
outputs: []regMask{
31, // R0 R1 R2 R3 SP
},
},
},
{
name: "CMP",
argLen: 2,
asm: arm.ACMP,
reg: regInfo{
inputs: []inputInfo{
{0, 31}, // R0 R1 R2 R3 SP
{1, 31}, // R0 R1 R2 R3 SP
},
outputs: []regMask{
32, // FLAGS
},
},
},
{
name: "MOVWload",
argLen: 2,
asm: arm.AMOVW,
reg: regInfo{
inputs: []inputInfo{
{0, 31}, // R0 R1 R2 R3 SP
},
outputs: []regMask{
31, // R0 R1 R2 R3 SP
},
},
},
{
name: "MOVWstore",
argLen: 3,
asm: arm.AMOVW,
reg: regInfo{
inputs: []inputInfo{
{0, 31}, // R0 R1 R2 R3 SP
{1, 31}, // R0 R1 R2 R3 SP
},
},
},
{
name: "CALLstatic",
auxType: auxSymOff,
argLen: 1,
reg: regInfo{
clobbers: 15, // R0 R1 R2 R3
},
},
{
name: "LessThan",
argLen: 2,
reg: regInfo{
inputs: []inputInfo{
{0, 32}, // FLAGS
},
outputs: []regMask{
31, // R0 R1 R2 R3 SP
},
},
},
{
name: "Add8",
argLen: 2,
......@@ -5343,3 +5475,49 @@ var opcodeTable = [...]opInfo{
func (o Op) Asm() obj.As { return opcodeTable[o].asm }
func (o Op) String() string { return opcodeTable[o].name }
var registersAMD64 = [...]Register{
{0, "AX"},
{1, "CX"},
{2, "DX"},
{3, "BX"},
{4, "SP"},
{5, "BP"},
{6, "SI"},
{7, "DI"},
{8, "R8"},
{9, "R9"},
{10, "R10"},
{11, "R11"},
{12, "R12"},
{13, "R13"},
{14, "R14"},
{15, "R15"},
{16, "X0"},
{17, "X1"},
{18, "X2"},
{19, "X3"},
{20, "X4"},
{21, "X5"},
{22, "X6"},
{23, "X7"},
{24, "X8"},
{25, "X9"},
{26, "X10"},
{27, "X11"},
{28, "X12"},
{29, "X13"},
{30, "X14"},
{31, "X15"},
{32, "SB"},
{33, "FLAGS"},
}
var registersARM = [...]Register{
{0, "R0"},
{1, "R1"},
{2, "R2"},
{3, "R3"},
{4, "SP"},
{5, "FLAGS"},
{6, "SB"},
}
......@@ -129,10 +129,11 @@ type regMask uint64
func (m regMask) String() string {
s := ""
for r := register(0); r < numRegs; r++ {
for r := register(0); m != 0; r++ {
if m>>r&1 == 0 {
continue
}
m &^= regMask(1) << r
if s != "" {
s += " "
}
......@@ -141,47 +142,6 @@ func (m regMask) String() string {
return s
}
// TODO: make arch-dependent
var numRegs register = 64
var registers = [...]Register{
Register{0, "AX"},
Register{1, "CX"},
Register{2, "DX"},
Register{3, "BX"},
Register{4, "SP"},
Register{5, "BP"},
Register{6, "SI"},
Register{7, "DI"},
Register{8, "R8"},
Register{9, "R9"},
Register{10, "R10"},
Register{11, "R11"},
Register{12, "R12"},
Register{13, "R13"},
Register{14, "R14"},
Register{15, "R15"},
Register{16, "X0"},
Register{17, "X1"},
Register{18, "X2"},
Register{19, "X3"},
Register{20, "X4"},
Register{21, "X5"},
Register{22, "X6"},
Register{23, "X7"},
Register{24, "X8"},
Register{25, "X9"},
Register{26, "X10"},
Register{27, "X11"},
Register{28, "X12"},
Register{29, "X13"},
Register{30, "X14"},
Register{31, "X15"},
Register{32, "SB"}, // pseudo-register for global base pointer (aka %rip)
// TODO: make arch-dependent
}
// countRegs returns the number of set bits in the register mask.
func countRegs(r regMask) int {
n := 0
......@@ -231,6 +191,11 @@ type regState struct {
type regAllocState struct {
f *Func
registers []Register
numRegs register
SPReg register
SBReg register
// for each block, its primary predecessor.
// A predecessor of b is primary if it is the closest
// predecessor that appears before b in the layout order.
......@@ -298,7 +263,7 @@ func (s *regAllocState) freeReg(r register) {
// Mark r as unused.
if s.f.pass.debug > regDebug {
fmt.Printf("freeReg %s (dump %s/%s)\n", registers[r].Name(), v, s.regs[r].c)
fmt.Printf("freeReg %s (dump %s/%s)\n", s.registers[r].Name(), v, s.regs[r].c)
}
s.regs[r] = regState{}
s.values[v.ID].regs &^= regMask(1) << r
......@@ -328,7 +293,7 @@ func (s *regAllocState) setOrig(c *Value, v *Value) {
// r must be unused.
func (s *regAllocState) assignReg(r register, v *Value, c *Value) {
if s.f.pass.debug > regDebug {
fmt.Printf("assignReg %s %s/%s\n", registers[r].Name(), v, c)
fmt.Printf("assignReg %s %s/%s\n", s.registers[r].Name(), v, c)
}
if s.regs[r].v != nil {
s.f.Fatalf("tried to assign register %d to %s/%s but it is already used by %s", r, v, c, s.regs[r].v)
......@@ -338,7 +303,7 @@ func (s *regAllocState) assignReg(r register, v *Value, c *Value) {
s.regs[r] = regState{v, c}
s.values[v.ID].regs |= regMask(1) << r
s.used |= regMask(1) << r
s.f.setHome(c, &registers[r])
s.f.setHome(c, &s.registers[r])
}
// allocReg chooses a register for v from the set of registers in mask.
......@@ -377,14 +342,14 @@ func (s *regAllocState) allocReg(v *Value, mask regMask) register {
// SP and SB are allocated specially. No regular value should
// be allocated to them.
mask &^= 1<<4 | 1<<32
mask &^= 1<<s.SPReg | 1<<s.SBReg
// Find a register to spill. We spill the register containing the value
// whose next use is as far in the future as possible.
// https://en.wikipedia.org/wiki/Page_replacement_algorithm#The_theoretically_optimal_page_replacement_algorithm
var r register
maxuse := int32(-1)
for t := register(0); t < numRegs; t++ {
for t := register(0); t < s.numRegs; t++ {
if mask>>t&1 == 0 {
continue
}
......@@ -425,10 +390,10 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
}
if v.Op != OpSP {
mask &^= 1 << 4 // dont' spill SP
mask &^= 1 << s.SPReg // dont' spill SP
}
if v.Op != OpSB {
mask &^= 1 << 32 // don't spill SB
mask &^= 1 << s.SBReg // don't spill SB
}
mask &^= s.reserved()
......@@ -469,12 +434,22 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
}
func (s *regAllocState) init(f *Func) {
if numRegs > noRegister || numRegs > register(unsafe.Sizeof(regMask(0))*8) {
s.registers = f.Config.registers
s.numRegs = register(len(s.registers))
if s.numRegs > noRegister || s.numRegs > register(unsafe.Sizeof(regMask(0))*8) {
panic("too many registers")
}
for r := register(0); r < s.numRegs; r++ {
if s.registers[r].Name() == "SP" {
s.SPReg = r
}
if s.registers[r].Name() == "SB" {
s.SBReg = r
}
}
s.f = f
s.regs = make([]regState, numRegs)
s.regs = make([]regState, s.numRegs)
s.values = make([]valState, f.NumValues())
s.orig = make([]*Value, f.NumValues())
for _, b := range f.Blocks {
......@@ -663,7 +638,7 @@ func (s *regAllocState) regalloc(f *Func) {
// Drop any values which are no longer live.
// This may happen because at the end of p, a value may be
// live but only used by some other successor of p.
for r := register(0); r < numRegs; r++ {
for r := register(0); r < s.numRegs; r++ {
v := s.regs[r].v
if v != nil && !liveSet.contains(v.ID) {
s.freeReg(r)
......@@ -687,7 +662,7 @@ func (s *regAllocState) regalloc(f *Func) {
if s.f.pass.debug > regDebug {
fmt.Printf("starting merge block %s with end state of %s:\n", b, p)
for _, x := range s.endRegs[p.ID] {
fmt.Printf(" %s: orig:%s cache:%s\n", registers[x.r].Name(), x.v, x.c)
fmt.Printf(" %s: orig:%s cache:%s\n", s.registers[x.r].Name(), x.v, x.c)
}
}
......@@ -769,7 +744,7 @@ func (s *regAllocState) regalloc(f *Func) {
// Save the starting state for use by merge edges.
var regList []startReg
for r := register(0); r < numRegs; r++ {
for r := register(0); r < s.numRegs; r++ {
v := s.regs[r].v
if v == nil {
continue
......@@ -786,7 +761,7 @@ func (s *regAllocState) regalloc(f *Func) {
if s.f.pass.debug > regDebug {
fmt.Printf("after phis\n")
for _, x := range s.startRegs[b.ID] {
fmt.Printf(" %s: v%d\n", registers[x.r].Name(), x.vid)
fmt.Printf(" %s: v%d\n", s.registers[x.r].Name(), x.vid)
}
}
}
......@@ -866,13 +841,13 @@ func (s *regAllocState) regalloc(f *Func) {
f.Fatalf("phi %s not at start of block", v)
}
if v.Op == OpSP {
s.assignReg(4, v, v) // TODO: arch-dependent
s.assignReg(s.SPReg, v, v)
b.Values = append(b.Values, v)
s.advanceUses(v)
continue
}
if v.Op == OpSB {
s.assignReg(32, v, v) // TODO: arch-dependent
s.assignReg(s.SBReg, v, v)
b.Values = append(b.Values, v)
s.advanceUses(v)
continue
......@@ -1030,7 +1005,7 @@ func (s *regAllocState) regalloc(f *Func) {
// Save end-of-block register state.
// First count how many, this cuts allocations in half.
k := 0
for r := register(0); r < numRegs; r++ {
for r := register(0); r < s.numRegs; r++ {
v := s.regs[r].v
if v == nil {
continue
......@@ -1038,7 +1013,7 @@ func (s *regAllocState) regalloc(f *Func) {
k++
}
regList := make([]endReg, 0, k)
for r := register(0); r < numRegs; r++ {
for r := register(0); r < s.numRegs; r++ {
v := s.regs[r].v
if v == nil {
continue
......@@ -1053,7 +1028,7 @@ func (s *regAllocState) regalloc(f *Func) {
for _, x := range s.live[b.ID] {
liveSet.add(x.ID)
}
for r := register(0); r < numRegs; r++ {
for r := register(0); r < s.numRegs; r++ {
v := s.regs[r].v
if v == nil {
continue
......@@ -1214,7 +1189,7 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
// Live registers can be sources.
for _, x := range srcReg {
e.set(&registers[x.r], x.v.ID, x.c, false)
e.set(&e.s.registers[x.r], x.v.ID, x.c, false)
}
// So can all of the spill locations.
for _, spillID := range stacklive {
......@@ -1226,7 +1201,7 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
// Figure out all the destinations we need.
dsts := e.destinations[:0]
for _, x := range dstReg {
dsts = append(dsts, dstRecord{&registers[x.r], x.vid, nil})
dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.vid, nil})
}
// Phis need their args to end up in a specific location.
for _, v := range e.b.Values {
......@@ -1519,15 +1494,15 @@ func (e *edgeState) findRegFor(typ Type) Location {
// 3) a non-unique register
x := m &^ e.usedRegs
if x != 0 {
return &registers[pickReg(x)]
return &e.s.registers[pickReg(x)]
}
x = m &^ e.uniqueRegs &^ e.finalRegs
if x != 0 {
return &registers[pickReg(x)]
return &e.s.registers[pickReg(x)]
}
x = m &^ e.uniqueRegs
if x != 0 {
return &registers[pickReg(x)]
return &e.s.registers[pickReg(x)]
}
// No register is available. Allocate a temp location to spill a register to.
......
// autogenerated from gen/ARM.rules: do not edit!
// generated with: cd gen; go run *.go
package ssa
import "math"
var _ = math.MinInt8 // in case not otherwise used
func rewriteValueARM(v *Value, config *Config) bool {
switch v.Op {
case OpARMADD:
return rewriteValueARM_OpARMADD(v, config)
case OpAdd32:
return rewriteValueARM_OpAdd32(v, config)
case OpAddr:
return rewriteValueARM_OpAddr(v, config)
case OpConst32:
return rewriteValueARM_OpConst32(v, config)
case OpLess32:
return rewriteValueARM_OpLess32(v, config)
case OpLoad:
return rewriteValueARM_OpLoad(v, config)
case OpARMMOVWload:
return rewriteValueARM_OpARMMOVWload(v, config)
case OpARMMOVWstore:
return rewriteValueARM_OpARMMOVWstore(v, config)
case OpOffPtr:
return rewriteValueARM_OpOffPtr(v, config)
case OpStaticCall:
return rewriteValueARM_OpStaticCall(v, config)
case OpStore:
return rewriteValueARM_OpStore(v, config)
}
return false
}
func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (ADD (MOVWconst [c]) x)
// cond:
// result: (ADDconst [c] x)
for {
v_0 := v.Args[0]
if v_0.Op != OpARMMOVWconst {
break
}
c := v_0.AuxInt
x := v.Args[1]
v.reset(OpARMADDconst)
v.AuxInt = c
v.AddArg(x)
return true
}
// match: (ADD x (MOVWconst [c]))
// cond:
// result: (ADDconst [c] x)
for {
x := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpARMMOVWconst {
break
}
c := v_1.AuxInt
v.reset(OpARMADDconst)
v.AuxInt = c
v.AddArg(x)
return true
}
return false
}
func rewriteValueARM_OpAdd32(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (Add32 x y)
// cond:
// result: (ADD x y)
for {
x := v.Args[0]
y := v.Args[1]
v.reset(OpARMADD)
v.AddArg(x)
v.AddArg(y)
return true
}
return false
}
func rewriteValueARM_OpAddr(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (Addr {sym} base)
// cond:
// result: (ADDconst {sym} base)
for {
sym := v.Aux
base := v.Args[0]
v.reset(OpARMADDconst)
v.Aux = sym
v.AddArg(base)
return true
}
return false
}
func rewriteValueARM_OpConst32(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (Const32 [val])
// cond:
// result: (MOVWconst [val])
for {
val := v.AuxInt
v.reset(OpARMMOVWconst)
v.AuxInt = val
return true
}
return false
}
func rewriteValueARM_OpLess32(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (Less32 x y)
// cond:
// result: (LessThan (CMP x y))
for {
x := v.Args[0]
y := v.Args[1]
v.reset(OpARMLessThan)
v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
return true
}
return false
}
func rewriteValueARM_OpLoad(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (Load <t> ptr mem)
// cond: is32BitInt(t)
// result: (MOVWload ptr mem)
for {
t := v.Type
ptr := v.Args[0]
mem := v.Args[1]
if !(is32BitInt(t)) {
break
}
v.reset(OpARMMOVWload)
v.AddArg(ptr)
v.AddArg(mem)
return true
}
return false
}
func rewriteValueARM_OpARMMOVWload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVWload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2)
// result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for {
off1 := v.AuxInt
sym1 := v.Aux
v_0 := v.Args[0]
if v_0.Op != OpARMADDconst {
break
}
off2 := v_0.AuxInt
sym2 := v_0.Aux
ptr := v_0.Args[0]
mem := v.Args[1]
if !(canMergeSym(sym1, sym2)) {
break
}
v.reset(OpARMMOVWload)
v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
v.AddArg(ptr)
v.AddArg(mem)
return true
}
return false
}
func rewriteValueARM_OpARMMOVWstore(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVWstore [off1] {sym1} (ADDconst [off2] {sym2} ptr) val mem)
// cond: canMergeSym(sym1,sym2)
// result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
for {
off1 := v.AuxInt
sym1 := v.Aux
v_0 := v.Args[0]
if v_0.Op != OpARMADDconst {
break
}
off2 := v_0.AuxInt
sym2 := v_0.Aux
ptr := v_0.Args[0]
val := v.Args[1]
mem := v.Args[2]
if !(canMergeSym(sym1, sym2)) {
break
}
v.reset(OpARMMOVWstore)
v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
v.AddArg(ptr)
v.AddArg(val)
v.AddArg(mem)
return true
}
return false
}
func rewriteValueARM_OpOffPtr(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (OffPtr [off] ptr)
// cond:
// result: (ADD (MOVWconst <config.Frontend().TypeInt32()> [off]) ptr)
for {
off := v.AuxInt
ptr := v.Args[0]
v.reset(OpARMADD)
v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.Frontend().TypeInt32())
v0.AuxInt = off
v.AddArg(v0)
v.AddArg(ptr)
return true
}
return false
}
func rewriteValueARM_OpStaticCall(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (StaticCall [argwid] {target} mem)
// cond:
// result: (CALLstatic [argwid] {target} mem)
for {
argwid := v.AuxInt
target := v.Aux
mem := v.Args[0]
v.reset(OpARMCALLstatic)
v.AuxInt = argwid
v.Aux = target
v.AddArg(mem)
return true
}
return false
}
func rewriteValueARM_OpStore(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (Store [4] ptr val mem)
// cond:
// result: (MOVWstore ptr val mem)
for {
if v.AuxInt != 4 {
break
}
ptr := v.Args[0]
val := v.Args[1]
mem := v.Args[2]
v.reset(OpARMMOVWstore)
v.AddArg(ptr)
v.AddArg(val)
v.AddArg(mem)
return true
}
return false
}
func rewriteBlockARM(b *Block) bool {
switch b.Kind {
case BlockIf:
// match: (If (LessThan cc) yes no)
// cond:
// result: (LT cc yes no)
for {
v := b.Control
if v.Op != OpARMLessThan {
break
}
cc := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockARMLT
b.SetControl(cc)
b.Succs[0] = yes
b.Succs[1] = no
return true
}
}
return false
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment