Commit 93b8aab5 authored by Cherry Zhang's avatar Cherry Zhang

[dev.ssa] cmd/compile: handle GetG on ARM

Use hardware g register (R10) for GetG, allow g to appear at LHS of
some ops.

Progress on SSA backend for ARM. Now everything compiles and runs.

Updates #15365.

Change-Id: Icdf93585579faa86cc29b1e17ab7c90f0119fc4e
Reviewed-on: https://go-review.googlesource.com/23952Reviewed-by: 's avatarDavid Chase <drchase@google.com>
parent 0393ed82
......@@ -24,7 +24,7 @@ var ssaRegToReg = []int16{
arm.REG_R7,
arm.REG_R8,
arm.REG_R9,
arm.REG_R10,
arm.REGG, // aka R10
arm.REG_R11,
arm.REG_R12,
arm.REGSP, // aka R13
......@@ -111,7 +111,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
// memory arg needs no code
case ssa.OpArg:
// input args need no code
case ssa.OpSP, ssa.OpSB:
case ssa.OpSP, ssa.OpSB, ssa.OpGetG:
// nothing to do
case ssa.OpCopy, ssa.OpARMMOVWconvert:
if v.Type.IsMemory() {
......
......@@ -24,6 +24,7 @@ type Config struct {
fpRegMask regMask // floating point register mask
flagRegMask regMask // flag register mask
FPReg int8 // register number of frame pointer, -1 if not used
hasGReg bool // has hardware g register
fe Frontend // callbacks into compiler frontend
HTML *HTMLWriter // html writer, for debugging
ctxt *obj.Link // Generic arch information
......@@ -137,6 +138,7 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
c.fpRegMask = fpRegMaskAMD64
c.flagRegMask = flagRegMaskAMD64
c.FPReg = framepointerRegAMD64
c.hasGReg = false
case "386":
c.IntSize = 4
c.PtrSize = 4
......@@ -152,6 +154,7 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
c.fpRegMask = fpRegMaskARM
c.flagRegMask = flagRegMaskARM
c.FPReg = framepointerRegARM
c.hasGReg = true
default:
fe.Unimplementedf(0, "arch %s not implemented", arch)
}
......
......@@ -36,7 +36,7 @@ var regNamesARM = []string{
"R7",
"R8",
"R9",
"R10", // g
"g", // aka R10
"R11", // tmp
"R12",
"SP", // aka R13
......@@ -89,33 +89,35 @@ func init() {
// Common individual register masks
var (
gp = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12")
gpg = gp | buildReg("g")
gpsp = gp | buildReg("SP")
gpspsb = gpsp | buildReg("SB")
gpspg = gpg | buildReg("SP")
gpspsbg = gpspg | buildReg("SB")
flags = buildReg("FLAGS")
fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15")
callerSave = gp | fp | flags
callerSave = gp | fp | flags | buildReg("g") // runtime.setg (and anything calling it) may clobber g
)
// Common regInfo
var (
gp01 = regInfo{inputs: []regMask{}, outputs: []regMask{gp}}
gp11 = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}
gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: []regMask{gp}}
gp1flags = regInfo{inputs: []regMask{gp}, outputs: []regMask{flags}}
gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}}
gp21cf = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}, clobbers: flags} // cf: clobbers flags
gp2flags = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{flags}}
gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
gp1flags = regInfo{inputs: []regMask{gpg}, outputs: []regMask{flags}}
gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
gp21cf = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}, clobbers: flags} // cf: clobbers flags
gp2flags = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{flags}}
gp2flags1 = regInfo{inputs: []regMask{gp, gp, flags}, outputs: []regMask{gp}}
gp31 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
gpload = regInfo{inputs: []regMask{gpspsb}, outputs: []regMask{gp}}
gpstore = regInfo{inputs: []regMask{gpspsb, gp}, outputs: []regMask{}}
gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{}}
fp01 = regInfo{inputs: []regMask{}, outputs: []regMask{fp}}
fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
gpfp = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}
fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
fp2flags = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{flags}}
fpload = regInfo{inputs: []regMask{gpspsb}, outputs: []regMask{fp}}
fpstore = regInfo{inputs: []regMask{gpspsb, fp}, outputs: []regMask{}}
fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
fpstore = regInfo{inputs: []regMask{gpspsbg, fp}, outputs: []regMask{}}
readflags = regInfo{inputs: []regMask{flags}, outputs: []regMask{gp}}
)
ops := []opData{
......@@ -222,13 +224,13 @@ func init() {
{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff"}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
{name: "CALLclosure", argLength: 3, reg: regInfo{[]regMask{gpsp, buildReg("R7"), 0}, callerSave, nil}, aux: "Int64"}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R7"), 0}, clobbers: callerSave}, aux: "Int64"}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64"}, // call deferproc. arg0=mem, auxint=argsize, returns mem
{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64"}, // call newproc. arg0=mem, auxint=argsize, returns mem
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64"}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
// pseudo-ops
{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpsp}, clobbers: flags}}, // panic if arg0 is nil. arg1=mem.
{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}}, // panic if arg0 is nil. arg1=mem.
{name: "Equal", argLength: 1, reg: readflags}, // bool, true flags encode x==y false otherwise.
{name: "NotEqual", argLength: 1, reg: readflags}, // bool, true flags encode x!=y false otherwise.
......@@ -243,7 +245,7 @@ func init() {
{name: "Carry", argLength: 1, reg: regInfo{inputs: []regMask{}, outputs: []regMask{flags}}, typ: "Flags"}, // flags of a (Flags,UInt32)
{name: "LoweredSelect0", argLength: 1, reg: regInfo{inputs: []regMask{}, outputs: []regMask{buildReg("R0")}}}, // the first component of a tuple, implicitly in R0, arg0=tuple
{name: "LoweredSelect1", argLength: 1, reg: gp11, resultInArg0: true}, // the second component of a tuple, arg0=tuple
{name: "LoweredSelect1", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // the second component of a tuple, arg0=tuple
{name: "LoweredZeromask", argLength: 1, reg: gp11}, // 0 if arg0 == 1, 0xffffffff if arg0 != 0
......
......@@ -23,6 +23,11 @@ func checkLower(f *Func) {
switch v.Op {
case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive:
continue // ok not to lower
case OpGetG:
if f.Config.hasGReg {
// has hardware g register, regalloc takes care of it
continue // ok not to lower
}
}
s := "not lowered: " + v.Op.String() + " " + v.Type.SimpleString()
for _, a := range v.Args {
......
This diff is collapsed.
......@@ -206,6 +206,7 @@ type regAllocState struct {
numRegs register
SPReg register
SBReg register
GReg register
allocatable regMask
// for each block, its primary predecessor.
......@@ -449,12 +450,18 @@ func (s *regAllocState) init(f *Func) {
if s.registers[r].Name() == "SB" {
s.SBReg = r
}
if s.registers[r].Name() == "g" {
s.GReg = r
}
}
// Figure out which registers we're allowed to use.
s.allocatable = s.f.Config.gpRegMask | s.f.Config.fpRegMask | s.f.Config.flagRegMask
s.allocatable &^= 1 << s.SPReg
s.allocatable &^= 1 << s.SBReg
if s.f.Config.hasGReg {
s.allocatable &^= 1 << s.GReg
}
if s.f.Config.ctxt.Framepointer_enabled && s.f.Config.FPReg >= 0 {
s.allocatable &^= 1 << uint(s.f.Config.FPReg)
}
......@@ -937,6 +944,26 @@ func (s *regAllocState) regalloc(f *Func) {
s.advanceUses(v)
continue
}
if v.Op == OpGetG && s.f.Config.hasGReg {
// use hardware g register
if s.regs[s.GReg].v != nil {
s.freeReg(s.GReg) // kick out the old value
}
s.assignReg(s.GReg, v, v)
b.Values = append(b.Values, v)
s.advanceUses(v)
// spill unconditionally, will be deleted if never used
spill := b.NewValue1(v.Line, OpStoreReg, v.Type, v)
s.setOrig(spill, v)
s.values[v.ID].spill = spill
s.values[v.ID].spillUsed = false
if loop != nil {
loop.spills = append(loop.spills, v)
nSpillsInner++
}
nSpills++
continue
}
if v.Op == OpArg {
// Args are "pre-spilled" values. We don't allocate
// any register here. We just set up the spill pointer to
......
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