mirror of
https://github.com/golang/go.git
synced 2026-06-27 19:30:52 +00:00
cmd/compile: refactor regMask for more registers
This CL refactors the register mask to be a struct, opening the doors for supporting more registers in the future. Change-Id: Ied1ff7bb4f966381402cbeeaf8ca37567ef9052b Reviewed-on: https://go-review.googlesource.com/c/go/+/648635 Reviewed-by: David Chase <drchase@google.com> Auto-Submit: Junyang Shao <shaojunyang@google.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
8594bf4621
commit
1901161d96
18 changed files with 16367 additions and 16289 deletions
|
|
@ -59,10 +59,10 @@ func init() {
|
|||
num[name] = i
|
||||
}
|
||||
buildReg := func(s string) regMask {
|
||||
m := regMask(0)
|
||||
m := regMask{}
|
||||
for _, r := range strings.Split(s, " ") {
|
||||
if n, ok := num[r]; ok {
|
||||
m |= regMask(1) << uint(n)
|
||||
m = m.addReg(uint(n))
|
||||
continue
|
||||
}
|
||||
panic("register " + r + " not found")
|
||||
|
|
@ -78,9 +78,9 @@ func init() {
|
|||
bx = buildReg("BX")
|
||||
gp = buildReg("AX CX DX BX BP SI DI")
|
||||
fp = buildReg("X0 X1 X2 X3 X4 X5 X6 X7")
|
||||
gpsp = gp | buildReg("SP")
|
||||
gpspsb = gpsp | buildReg("SB")
|
||||
callerSave = gp | fp
|
||||
gpsp = gp.union(buildReg("SP"))
|
||||
gpspsb = gpsp.union(buildReg("SB"))
|
||||
callerSave = gp.union(fp)
|
||||
)
|
||||
// Common slices of register masks
|
||||
var (
|
||||
|
|
@ -95,51 +95,51 @@ func init() {
|
|||
gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly}
|
||||
gp11sb = regInfo{inputs: []regMask{gpspsb}, outputs: gponly}
|
||||
gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
|
||||
gp11carry = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp, 0}}
|
||||
gp21carry = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, 0}}
|
||||
gp11carry = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp, regMask{}}}
|
||||
gp21carry = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, regMask{}}}
|
||||
gp1carry1 = regInfo{inputs: []regMask{gp}, outputs: gponly}
|
||||
gp2carry1 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
|
||||
gp2carry1carry = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, 0}}
|
||||
gp2carry1carry = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, regMask{}}}
|
||||
gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly}
|
||||
gp21sb = regInfo{inputs: []regMask{gpspsb, gpsp}, outputs: gponly}
|
||||
gp21shift = regInfo{inputs: []regMask{gp, cx}, outputs: []regMask{gp}}
|
||||
gp11div = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{ax}, clobbers: dx}
|
||||
gp11div = regInfo{inputs: []regMask{ax, gpsp.minus(dx)}, outputs: []regMask{ax}, clobbers: dx}
|
||||
gp21hmul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx}, clobbers: ax}
|
||||
gp11mod = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{dx}, clobbers: ax}
|
||||
gp11mod = regInfo{inputs: []regMask{ax, gpsp.minus(dx)}, outputs: []regMask{dx}, clobbers: ax}
|
||||
gp21mul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx, ax}}
|
||||
|
||||
gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}}
|
||||
gp1flags = regInfo{inputs: []regMask{gpsp}}
|
||||
gp0flagsLoad = regInfo{inputs: []regMask{gpspsb, 0}}
|
||||
gp1flagsLoad = regInfo{inputs: []regMask{gpspsb, gpsp, 0}}
|
||||
gp0flagsLoad = regInfo{inputs: []regMask{gpspsb, regMask{}}}
|
||||
gp1flagsLoad = regInfo{inputs: []regMask{gpspsb, gpsp, regMask{}}}
|
||||
flagsgp = regInfo{inputs: nil, outputs: gponly}
|
||||
|
||||
readflags = regInfo{inputs: nil, outputs: gponly}
|
||||
flagsgpax = regInfo{inputs: nil, clobbers: ax, outputs: []regMask{gp &^ ax}}
|
||||
flagsgpax = regInfo{inputs: nil, clobbers: ax, outputs: []regMask{gp.minus(ax)}}
|
||||
|
||||
gpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: gponly}
|
||||
gp21load = regInfo{inputs: []regMask{gp, gpspsb, 0}, outputs: gponly}
|
||||
gploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: gponly}
|
||||
gp21loadidx = regInfo{inputs: []regMask{gp, gpspsb, gpsp, 0}, outputs: gponly}
|
||||
gpload = regInfo{inputs: []regMask{gpspsb, regMask{}}, outputs: gponly}
|
||||
gp21load = regInfo{inputs: []regMask{gp, gpspsb, regMask{}}, outputs: gponly}
|
||||
gploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, regMask{}}, outputs: gponly}
|
||||
gp21loadidx = regInfo{inputs: []regMask{gp, gpspsb, gpsp, regMask{}}, outputs: gponly}
|
||||
|
||||
gpstore = regInfo{inputs: []regMask{gpspsb, gpsp, 0}}
|
||||
gpstoreconst = regInfo{inputs: []regMask{gpspsb, 0}}
|
||||
gpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, gpsp, 0}}
|
||||
gpstoreconstidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}}
|
||||
gpstore = regInfo{inputs: []regMask{gpspsb, gpsp, regMask{}}}
|
||||
gpstoreconst = regInfo{inputs: []regMask{gpspsb, regMask{}}}
|
||||
gpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, gpsp, regMask{}}}
|
||||
gpstoreconstidx = regInfo{inputs: []regMask{gpspsb, gpsp, regMask{}}}
|
||||
|
||||
fp01 = regInfo{inputs: nil, outputs: fponly}
|
||||
fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: fponly}
|
||||
fp21load = regInfo{inputs: []regMask{fp, gpspsb, 0}, outputs: fponly}
|
||||
fp21load = regInfo{inputs: []regMask{fp, gpspsb, regMask{}}, outputs: fponly}
|
||||
fpgp = regInfo{inputs: fponly, outputs: gponly}
|
||||
gpfp = regInfo{inputs: gponly, outputs: fponly}
|
||||
fp11 = regInfo{inputs: fponly, outputs: fponly}
|
||||
fp2flags = regInfo{inputs: []regMask{fp, fp}}
|
||||
|
||||
fpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: fponly}
|
||||
fploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: fponly}
|
||||
fpload = regInfo{inputs: []regMask{gpspsb, regMask{}}, outputs: fponly}
|
||||
fploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, regMask{}}, outputs: fponly}
|
||||
|
||||
fpstore = regInfo{inputs: []regMask{gpspsb, fp, 0}}
|
||||
fpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, fp, 0}}
|
||||
fpstore = regInfo{inputs: []regMask{gpspsb, fp, regMask{}}}
|
||||
fpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, fp, regMask{}}}
|
||||
)
|
||||
|
||||
var _386ops = []opData{
|
||||
|
|
@ -199,7 +199,7 @@ func init() {
|
|||
{name: "MULL", argLength: 2, reg: gp21, asm: "IMULL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 * arg1
|
||||
{name: "MULLconst", argLength: 1, reg: gp11, asm: "IMUL3L", aux: "Int32", clobberFlags: true}, // arg0 * auxint
|
||||
|
||||
{name: "MULLU", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{ax, 0}, clobbers: dx}, typ: "(UInt32,Flags)", asm: "MULL", commutative: true, clobberFlags: true}, // Let x = arg0*arg1 (full 32x32->64 unsigned multiply). Returns uint32(x), and flags set to overflow if uint32(x) != x.
|
||||
{name: "MULLU", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{ax, regMask{}}, clobbers: dx}, typ: "(UInt32,Flags)", asm: "MULL", commutative: true, clobberFlags: true}, // Let x = arg0*arg1 (full 32x32->64 unsigned multiply). Returns uint32(x), and flags set to overflow if uint32(x) != x.
|
||||
|
||||
{name: "HMULL", argLength: 2, reg: gp21hmul, commutative: true, asm: "IMULL", clobberFlags: true}, // (arg0 * arg1) >> width
|
||||
{name: "HMULLU", argLength: 2, reg: gp21hmul, commutative: true, asm: "MULL", clobberFlags: true}, // (arg0 * arg1) >> width
|
||||
|
|
@ -457,11 +457,11 @@ func init() {
|
|||
faultOnNilArg0: true,
|
||||
},
|
||||
|
||||
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), regMask{}}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
|
||||
// arg0 = destination pointer
|
||||
// arg1 = source pointer
|
||||
|
|
@ -523,7 +523,7 @@ func init() {
|
|||
// LoweredWB invokes runtime.gcWriteBarrier. arg0=mem, auxint=# of write barrier slots
|
||||
// It saves all GP registers if necessary, but may clobber others.
|
||||
// Returns a pointer to a write barrier buffer in DI.
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave &^ gp, outputs: []regMask{buildReg("DI")}}, clobberFlags: true, aux: "Int64"},
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave.minus(gp), outputs: []regMask{buildReg("DI")}}, clobberFlags: true, aux: "Int64"},
|
||||
|
||||
// LoweredPanicBoundsRR takes x and y, two values that caused a bounds check to fail.
|
||||
// the RC and CR versions are used when one of the arguments is a constant. CC is used
|
||||
|
|
@ -536,8 +536,8 @@ func init() {
|
|||
{name: "LoweredPanicBoundsCC", argLength: 1, aux: "PanicBoundsCC", reg: regInfo{}, typ: "Mem", call: true}, // arg0=mem, returns memory.
|
||||
|
||||
// Same as above, but the x value is 64 bits.
|
||||
{name: "LoweredPanicExtendRR", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{ax | cx | dx | bx, ax | cx | dx | bx, gp}}, typ: "Mem", call: true}, // arg0=x_hi, arg1=x_lo, arg2=y, arg3=mem, returns memory.
|
||||
{name: "LoweredPanicExtendRC", argLength: 3, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{ax | cx | dx | bx, ax | cx | dx | bx}}, typ: "Mem", call: true}, // arg0=x_hi, arg1=x_lo, arg2=mem, returns memory.
|
||||
{name: "LoweredPanicExtendRR", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{ax.union(cx).union(dx).union(bx), ax.union(cx).union(dx).union(bx), gp}}, typ: "Mem", call: true}, // arg0=x_hi, arg1=x_lo, arg2=y, arg3=mem, returns memory.
|
||||
{name: "LoweredPanicExtendRC", argLength: 3, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{ax.union(cx).union(dx).union(bx), ax.union(cx).union(dx).union(bx)}}, typ: "Mem", call: true}, // arg0=x_hi, arg1=x_lo, arg2=mem, returns memory.
|
||||
|
||||
// Constant flag values. For any comparison, there are 5 possible
|
||||
// outcomes: the three from the signed total order (<,==,>) and the
|
||||
|
|
|
|||
|
|
@ -105,10 +105,10 @@ func init() {
|
|||
num[name] = i
|
||||
}
|
||||
buildReg := func(s string) regMask {
|
||||
m := regMask(0)
|
||||
m := regMask{}
|
||||
for _, r := range strings.Split(s, " ") {
|
||||
if n, ok := num[r]; ok {
|
||||
m |= regMask(1) << uint(n)
|
||||
m = m.addReg(uint(n))
|
||||
continue
|
||||
}
|
||||
panic("register " + r + " not found")
|
||||
|
|
@ -128,13 +128,13 @@ func init() {
|
|||
w = buildReg("X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 X31")
|
||||
x15 = buildReg("X15")
|
||||
mask = buildReg("K1 K2 K3 K4 K5 K6 K7")
|
||||
gpsp = gp | buildReg("SP")
|
||||
gpspsb = gpsp | buildReg("SB")
|
||||
gpspsbg = gpspsb | g
|
||||
callerSave = gp | fp | g // runtime.setg (and anything calling it) may clobber g
|
||||
gpsp = gp.union(buildReg("SP"))
|
||||
gpspsb = gpsp.union(buildReg("SB"))
|
||||
gpspsbg = gpspsb.union(g)
|
||||
callerSave = gp.union(fp).union(g) // runtime.setg (and anything calling it) may clobber g
|
||||
|
||||
vz = v | x15
|
||||
wz = w | x15
|
||||
vz = v.union(x15)
|
||||
wz = w.union(x15)
|
||||
x0 = buildReg("X0")
|
||||
)
|
||||
// Common slices of register masks
|
||||
|
|
@ -160,59 +160,59 @@ func init() {
|
|||
gp21sb = regInfo{inputs: []regMask{gpspsbg, gpsp}, outputs: gponly}
|
||||
gp21shift = regInfo{inputs: []regMask{gp, cx}, outputs: []regMask{gp}}
|
||||
gp31shift = regInfo{inputs: []regMask{gp, gp, cx}, outputs: []regMask{gp}}
|
||||
gp11div = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{ax, dx}}
|
||||
gp11div = regInfo{inputs: []regMask{ax, gpsp.minus(dx)}, outputs: []regMask{ax, dx}}
|
||||
gp21hmul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx}, clobbers: ax}
|
||||
gp21flags = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, 0}}
|
||||
gp2flags1flags = regInfo{inputs: []regMask{gp, gp, 0}, outputs: []regMask{gp, 0}}
|
||||
gp21flags = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, regMask{}}}
|
||||
gp2flags1flags = regInfo{inputs: []regMask{gp, gp, regMask{}}, outputs: []regMask{gp, regMask{}}}
|
||||
|
||||
gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}}
|
||||
gp1flags = regInfo{inputs: []regMask{gpsp}}
|
||||
gp0flagsLoad = regInfo{inputs: []regMask{gpspsbg, 0}}
|
||||
gp1flagsLoad = regInfo{inputs: []regMask{gpspsbg, gpsp, 0}}
|
||||
gp2flagsLoad = regInfo{inputs: []regMask{gpspsbg, gpsp, gpsp, 0}}
|
||||
gp0flagsLoad = regInfo{inputs: []regMask{gpspsbg, regMask{}}}
|
||||
gp1flagsLoad = regInfo{inputs: []regMask{gpspsbg, gpsp, regMask{}}}
|
||||
gp2flagsLoad = regInfo{inputs: []regMask{gpspsbg, gpsp, gpsp, regMask{}}}
|
||||
flagsgp = regInfo{inputs: nil, outputs: gponly}
|
||||
|
||||
gp11flags = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp, 0}}
|
||||
gp1flags1flags = regInfo{inputs: []regMask{gp, 0}, outputs: []regMask{gp, 0}}
|
||||
gp11flags = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp, regMask{}}}
|
||||
gp1flags1flags = regInfo{inputs: []regMask{gp, regMask{}}, outputs: []regMask{gp, regMask{}}}
|
||||
|
||||
readflags = regInfo{inputs: nil, outputs: gponly}
|
||||
|
||||
gpload = regInfo{inputs: []regMask{gpspsbg, 0}, outputs: gponly}
|
||||
gp21load = regInfo{inputs: []regMask{gp, gpspsbg, 0}, outputs: gponly}
|
||||
gploadidx = regInfo{inputs: []regMask{gpspsbg, gpsp, 0}, outputs: gponly}
|
||||
gp21loadidx = regInfo{inputs: []regMask{gp, gpspsbg, gpsp, 0}, outputs: gponly}
|
||||
gp21shxload = regInfo{inputs: []regMask{gpspsbg, gp, 0}, outputs: gponly}
|
||||
gp21shxloadidx = regInfo{inputs: []regMask{gpspsbg, gpsp, gp, 0}, outputs: gponly}
|
||||
gpload = regInfo{inputs: []regMask{gpspsbg, regMask{}}, outputs: gponly}
|
||||
gp21load = regInfo{inputs: []regMask{gp, gpspsbg, regMask{}}, outputs: gponly}
|
||||
gploadidx = regInfo{inputs: []regMask{gpspsbg, gpsp, regMask{}}, outputs: gponly}
|
||||
gp21loadidx = regInfo{inputs: []regMask{gp, gpspsbg, gpsp, regMask{}}, outputs: gponly}
|
||||
gp21shxload = regInfo{inputs: []regMask{gpspsbg, gp, regMask{}}, outputs: gponly}
|
||||
gp21shxloadidx = regInfo{inputs: []regMask{gpspsbg, gpsp, gp, regMask{}}, outputs: gponly}
|
||||
|
||||
gpstore = regInfo{inputs: []regMask{gpspsbg, gpsp, 0}}
|
||||
gpstoreconst = regInfo{inputs: []regMask{gpspsbg, 0}}
|
||||
gpstoreidx = regInfo{inputs: []regMask{gpspsbg, gpsp, gpsp, 0}}
|
||||
gpstoreconstidx = regInfo{inputs: []regMask{gpspsbg, gpsp, 0}}
|
||||
gpstorexchg = regInfo{inputs: []regMask{gp, gpspsbg, 0}, outputs: []regMask{gp}}
|
||||
cmpxchg = regInfo{inputs: []regMask{gp, ax, gp, 0}, outputs: []regMask{gp, 0}, clobbers: ax}
|
||||
atomicLogic = regInfo{inputs: []regMask{gp &^ ax, gp &^ ax, 0}, outputs: []regMask{ax, 0}}
|
||||
gpstore = regInfo{inputs: []regMask{gpspsbg, gpsp, regMask{}}}
|
||||
gpstoreconst = regInfo{inputs: []regMask{gpspsbg, regMask{}}}
|
||||
gpstoreidx = regInfo{inputs: []regMask{gpspsbg, gpsp, gpsp, regMask{}}}
|
||||
gpstoreconstidx = regInfo{inputs: []regMask{gpspsbg, gpsp, regMask{}}}
|
||||
gpstorexchg = regInfo{inputs: []regMask{gp, gpspsbg, regMask{}}, outputs: []regMask{gp}}
|
||||
cmpxchg = regInfo{inputs: []regMask{gp, ax, gp, regMask{}}, outputs: []regMask{gp, regMask{}}, clobbers: ax}
|
||||
atomicLogic = regInfo{inputs: []regMask{gp.minus(ax), gp.minus(ax), regMask{}}, outputs: []regMask{ax, regMask{}}}
|
||||
|
||||
fp01 = regInfo{inputs: nil, outputs: fponly}
|
||||
fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: fponly}
|
||||
fp31 = regInfo{inputs: []regMask{fp, fp, fp}, outputs: fponly}
|
||||
fp21load = regInfo{inputs: []regMask{fp, gpspsbg, 0}, outputs: fponly}
|
||||
fp21loadidx = regInfo{inputs: []regMask{fp, gpspsbg, gpspsb, 0}, outputs: fponly}
|
||||
fp21load = regInfo{inputs: []regMask{fp, gpspsbg, regMask{}}, outputs: fponly}
|
||||
fp21loadidx = regInfo{inputs: []regMask{fp, gpspsbg, gpspsb, regMask{}}, outputs: fponly}
|
||||
fpgp = regInfo{inputs: fponly, outputs: gponly}
|
||||
gpfp = regInfo{inputs: gponly, outputs: fponly}
|
||||
fp11 = regInfo{inputs: fponly, outputs: fponly}
|
||||
fp2flags = regInfo{inputs: []regMask{fp, fp}}
|
||||
|
||||
fpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: fponly}
|
||||
fploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: fponly}
|
||||
fpload = regInfo{inputs: []regMask{gpspsb, regMask{}}, outputs: fponly}
|
||||
fploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, regMask{}}, outputs: fponly}
|
||||
|
||||
fpstore = regInfo{inputs: []regMask{gpspsb, fp, 0}}
|
||||
fpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, fp, 0}}
|
||||
fpstore = regInfo{inputs: []regMask{gpspsb, fp, regMask{}}}
|
||||
fpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, fp, regMask{}}}
|
||||
|
||||
// masked loads/stores, vector register or mask register
|
||||
vloadv = regInfo{inputs: []regMask{gpspsb, v, 0}, outputs: vonly}
|
||||
vstorev = regInfo{inputs: []regMask{gpspsb, v, v, 0}}
|
||||
vloadk = regInfo{inputs: []regMask{gpspsb, mask, 0}, outputs: vonly}
|
||||
vstorek = regInfo{inputs: []regMask{gpspsb, mask, v, 0}}
|
||||
vloadv = regInfo{inputs: []regMask{gpspsb, v, regMask{}}, outputs: vonly}
|
||||
vstorev = regInfo{inputs: []regMask{gpspsb, v, v, regMask{}}}
|
||||
vloadk = regInfo{inputs: []regMask{gpspsb, mask, regMask{}}, outputs: vonly}
|
||||
vstorek = regInfo{inputs: []regMask{gpspsb, mask, v, regMask{}}}
|
||||
|
||||
v01 = regInfo{inputs: nil, outputs: vonly}
|
||||
v11 = regInfo{inputs: vonly, outputs: vonly} // used in resultInArg0 ops, arg0 must not be x15
|
||||
|
|
@ -251,21 +251,21 @@ func init() {
|
|||
|
||||
// These register masks are used by SIMD only, they follow the pattern:
|
||||
// Mem last, k mask second to last (if any), address right before mem and k mask.
|
||||
wkwload = regInfo{inputs: []regMask{gpspsb, mask, 0}, outputs: wonly}
|
||||
v21load = regInfo{inputs: []regMask{v, gpspsb, 0}, outputs: vonly} // used in resultInArg0 ops, arg0 must not be x15
|
||||
v31load = regInfo{inputs: []regMask{v, vz, gpspsb, 0}, outputs: vonly} // used in resultInArg0 ops, arg0 must not be x15
|
||||
v11load = regInfo{inputs: []regMask{gpspsb, 0}, outputs: vonly}
|
||||
w21load = regInfo{inputs: []regMask{wz, gpspsb, 0}, outputs: wonly}
|
||||
w31load = regInfo{inputs: []regMask{w, wz, gpspsb, 0}, outputs: wonly} // used in resultInArg0 ops, arg0 must not be x15
|
||||
w2kload = regInfo{inputs: []regMask{wz, gpspsb, 0}, outputs: maskonly}
|
||||
w2kwload = regInfo{inputs: []regMask{wz, gpspsb, mask, 0}, outputs: wonly}
|
||||
w11load = regInfo{inputs: []regMask{gpspsb, 0}, outputs: wonly}
|
||||
w3kwload = regInfo{inputs: []regMask{w, wz, gpspsb, mask, 0}, outputs: wonly} // used in resultInArg0 ops, arg0 must not be x15
|
||||
w2kkload = regInfo{inputs: []regMask{wz, gpspsb, mask, 0}, outputs: maskonly}
|
||||
wkwload = regInfo{inputs: []regMask{gpspsb, mask, regMask{}}, outputs: wonly}
|
||||
v21load = regInfo{inputs: []regMask{v, gpspsb, regMask{}}, outputs: vonly} // used in resultInArg0 ops, arg0 must not be x15
|
||||
v31load = regInfo{inputs: []regMask{v, vz, gpspsb, regMask{}}, outputs: vonly} // used in resultInArg0 ops, arg0 must not be x15
|
||||
v11load = regInfo{inputs: []regMask{gpspsb, regMask{}}, outputs: vonly}
|
||||
w21load = regInfo{inputs: []regMask{wz, gpspsb, regMask{}}, outputs: wonly}
|
||||
w31load = regInfo{inputs: []regMask{w, wz, gpspsb, regMask{}}, outputs: wonly} // used in resultInArg0 ops, arg0 must not be x15
|
||||
w2kload = regInfo{inputs: []regMask{wz, gpspsb, regMask{}}, outputs: maskonly}
|
||||
w2kwload = regInfo{inputs: []regMask{wz, gpspsb, mask, regMask{}}, outputs: wonly}
|
||||
w11load = regInfo{inputs: []regMask{gpspsb, regMask{}}, outputs: wonly}
|
||||
w3kwload = regInfo{inputs: []regMask{w, wz, gpspsb, mask, regMask{}}, outputs: wonly} // used in resultInArg0 ops, arg0 must not be x15
|
||||
w2kkload = regInfo{inputs: []regMask{wz, gpspsb, mask, regMask{}}, outputs: maskonly}
|
||||
v31x0AtIn2 = regInfo{inputs: []regMask{v, vz, x0}, outputs: vonly} // used in resultInArg0 ops, arg0 must not be x15
|
||||
|
||||
kload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: maskonly}
|
||||
kstore = regInfo{inputs: []regMask{gpspsb, mask, 0}}
|
||||
kload = regInfo{inputs: []regMask{gpspsb, regMask{}}, outputs: maskonly}
|
||||
kstore = regInfo{inputs: []regMask{gpspsb, mask, regMask{}}}
|
||||
gpk = regInfo{inputs: gponly, outputs: maskonly}
|
||||
kgp = regInfo{inputs: maskonly, outputs: gponly}
|
||||
|
||||
|
|
@ -375,9 +375,9 @@ func init() {
|
|||
{name: "MULLconst", argLength: 1, reg: gp11, asm: "IMUL3L", aux: "Int32", clobberFlags: true},
|
||||
|
||||
// Let x = arg0*arg1 (full 32x32->64 unsigned multiply). Returns uint32(x), and flags set to overflow if uint32(x) != x.
|
||||
{name: "MULLU", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{ax, 0}, clobbers: dx}, typ: "(UInt32,Flags)", asm: "MULL", commutative: true, clobberFlags: true},
|
||||
{name: "MULLU", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{ax, regMask{}}, clobbers: dx}, typ: "(UInt32,Flags)", asm: "MULL", commutative: true, clobberFlags: true},
|
||||
// Let x = arg0*arg1 (full 64x64->128 unsigned multiply). Returns uint64(x), and flags set to overflow if uint64(x) != x.
|
||||
{name: "MULQU", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{ax, 0}, clobbers: dx}, typ: "(UInt64,Flags)", asm: "MULQ", commutative: true, clobberFlags: true},
|
||||
{name: "MULQU", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{ax, regMask{}}, clobbers: dx}, typ: "(UInt64,Flags)", asm: "MULQ", commutative: true, clobberFlags: true},
|
||||
|
||||
// HMULx[U]: computes the high bits of an integer multiply.
|
||||
// computes arg0 * arg1 >> (x==L?32:64)
|
||||
|
|
@ -1034,11 +1034,11 @@ func init() {
|
|||
},
|
||||
|
||||
// With a register ABI, the actual register info for these instructions (i.e., what is used in regalloc) is augmented with per-call-site bindings of additional arguments to specific in and out registers.
|
||||
{name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), regMask{}}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
|
||||
// arg0 = destination pointer
|
||||
// arg1 = source pointer
|
||||
|
|
@ -1118,7 +1118,7 @@ func init() {
|
|||
// LoweredWB invokes runtime.gcWriteBarrier{auxint}. arg0=mem, auxint=# of buffer entries needed.
|
||||
// It saves all GP registers if necessary, but may clobber others.
|
||||
// Returns a pointer to a write barrier buffer in R11.
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave &^ (gp | g), outputs: []regMask{buildReg("R11")}}, clobberFlags: true, aux: "Int64"},
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave.minus(gp.union(g)), outputs: []regMask{buildReg("R11")}}, clobberFlags: true, aux: "Int64"},
|
||||
|
||||
{name: "LoweredHasCPUFeature", argLength: 0, reg: gp01, rematerializeable: true, typ: "UInt64", aux: "Sym", symEffect: "None"},
|
||||
|
||||
|
|
|
|||
|
|
@ -124,10 +124,10 @@ func init() {
|
|||
num[name] = i
|
||||
}
|
||||
buildReg := func(s string) regMask {
|
||||
m := regMask(0)
|
||||
m := regMask{}
|
||||
for _, r := range strings.Split(s, " ") {
|
||||
if n, ok := num[r]; ok {
|
||||
m |= regMask(1) << uint(n)
|
||||
m = m.addReg(uint(n))
|
||||
continue
|
||||
}
|
||||
panic("register " + r + " not found")
|
||||
|
|
@ -138,12 +138,12 @@ func init() {
|
|||
// Common individual register masks
|
||||
var (
|
||||
gp = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30")
|
||||
gpg = gp | buildReg("g")
|
||||
gpsp = gp | buildReg("SP")
|
||||
gpspg = gpg | buildReg("SP")
|
||||
gpspsbg = gpspg | buildReg("SB")
|
||||
gpg = gp.union(buildReg("g"))
|
||||
gpsp = gp.union(buildReg("SP"))
|
||||
gpspg = gpg.union(buildReg("SP"))
|
||||
gpspsbg = gpspg.union(buildReg("SB"))
|
||||
fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31")
|
||||
callerSave = gp | fp | buildReg("g") // runtime.setg (and anything calling it) may clobber g
|
||||
callerSave = gp.union(fp).union(buildReg("g")) // runtime.setg (and anything calling it) may clobber g
|
||||
r25 = buildReg("R25")
|
||||
r24to25 = buildReg("R24 R25")
|
||||
f16to17 = buildReg("F16 F17")
|
||||
|
|
@ -153,28 +153,28 @@ func init() {
|
|||
// Common regInfo
|
||||
var (
|
||||
gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
|
||||
gp0flags1 = regInfo{inputs: []regMask{0}, outputs: []regMask{gp}}
|
||||
gp0flags1 = regInfo{inputs: []regMask{regMask{}}, outputs: []regMask{gp}}
|
||||
gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
|
||||
gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
|
||||
gp1flags = regInfo{inputs: []regMask{gpg}}
|
||||
gp1flagsflags = regInfo{inputs: []regMask{gpg}}
|
||||
gp1flags1 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
|
||||
gp11flags = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp, 0}}
|
||||
gp11flags = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp, regMask{}}}
|
||||
gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
|
||||
gp21nog = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}}
|
||||
gp21flags = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, 0}}
|
||||
gp21flags = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, regMask{}}}
|
||||
gp2flags = regInfo{inputs: []regMask{gpg, gpg}}
|
||||
gp2flagsflags = regInfo{inputs: []regMask{gpg, gpg}}
|
||||
gp2flags1 = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}}
|
||||
gp2flags1flags = regInfo{inputs: []regMask{gp, gp, 0}, outputs: []regMask{gp, 0}}
|
||||
gp2flags1flags = regInfo{inputs: []regMask{gp, gp, regMask{}}, outputs: []regMask{gp, regMask{}}}
|
||||
gp2load = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
|
||||
gp31 = regInfo{inputs: []regMask{gpg, gpg, gpg}, outputs: []regMask{gp}}
|
||||
gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
|
||||
gpload2 = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gpg, gpg}}
|
||||
gpstore = regInfo{inputs: []regMask{gpspsbg, gpg | rz}}
|
||||
gpstore2 = regInfo{inputs: []regMask{gpspsbg, gpg | rz, gpg | rz}}
|
||||
gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg | rz}, outputs: []regMask{gp}}
|
||||
gpcas = regInfo{inputs: []regMask{gpspsbg, gpg | rz, gpg | rz}, outputs: []regMask{gp}}
|
||||
gpstore = regInfo{inputs: []regMask{gpspsbg, gpg.union(rz)}}
|
||||
gpstore2 = regInfo{inputs: []regMask{gpspsbg, gpg.union(rz), gpg.union(rz)}}
|
||||
gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg.union(rz)}, outputs: []regMask{gp}}
|
||||
gpcas = regInfo{inputs: []regMask{gpspsbg, gpg.union(rz), gpg.union(rz)}, outputs: []regMask{gp}}
|
||||
fp01 = regInfo{inputs: nil, outputs: []regMask{fp}}
|
||||
fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
|
||||
fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
|
||||
|
|
@ -385,7 +385,7 @@ func init() {
|
|||
{name: "FMOVSconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVS", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
|
||||
{name: "FMOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
|
||||
|
||||
{name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
|
||||
{name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP").union(buildReg("SB"))}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
|
||||
|
||||
{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem.
|
||||
{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem.
|
||||
|
|
@ -539,11 +539,11 @@ func init() {
|
|||
{name: "CCMNWconst", argLength: 2, reg: gp1flagsflags, asm: "CCMNW", aux: "ARM64ConditionalParams", typ: "Flags"}, // If Cond then flags = CCMNWconst [ConstValue] arg0 else flags = Nzcv
|
||||
|
||||
// function calls
|
||||
{name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{gpsp, buildReg("R26"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{gpsp, buildReg("R26"), regMask{}}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
|
||||
// pseudo-ops
|
||||
{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem.
|
||||
|
|
@ -613,8 +613,8 @@ func init() {
|
|||
aux: "Int64",
|
||||
argLength: 3,
|
||||
reg: regInfo{
|
||||
inputs: []regMask{gp &^ r25, gp &^ r25},
|
||||
clobbers: r25 | f16to17, // TODO: figure out needIntTemp + x2 for floats
|
||||
inputs: []regMask{gp.minus(r25), gp.minus(r25)},
|
||||
clobbers: r25.union(f16to17), // TODO: figure out needIntTemp + x2 for floats
|
||||
},
|
||||
faultOnNilArg0: true,
|
||||
faultOnNilArg1: true,
|
||||
|
|
@ -631,8 +631,8 @@ func init() {
|
|||
aux: "Int64",
|
||||
argLength: 3,
|
||||
reg: regInfo{
|
||||
inputs: []regMask{gp &^ r24to25, gp &^ r24to25},
|
||||
clobbers: r24to25 | f16to17, // TODO: figure out needIntTemp x2 + x2 for floats
|
||||
inputs: []regMask{gp.minus(r24to25), gp.minus(r24to25)},
|
||||
clobbers: r24to25.union(f16to17), // TODO: figure out needIntTemp x2 + x2 for floats
|
||||
clobbersArg0: true,
|
||||
clobbersArg1: true,
|
||||
},
|
||||
|
|
@ -774,7 +774,7 @@ func init() {
|
|||
// but clobbers R30 (LR) because it's a call.
|
||||
// R16 and R17 may be clobbered by linker trampoline.
|
||||
// Returns a pointer to a write barrier buffer in R25.
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ gpg) | buildReg("R16 R17 R30"), outputs: []regMask{buildReg("R25")}}, clobberFlags: true, aux: "Int64"},
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave.minus(gpg).union(buildReg("R16 R17 R30")), outputs: []regMask{buildReg("R25")}}, clobberFlags: true, aux: "Int64"},
|
||||
|
||||
// LoweredPanicBoundsRR takes x and y, two values that caused a bounds check to fail.
|
||||
// the RC and CR versions are used when one of the arguments is a constant. CC is used
|
||||
|
|
|
|||
|
|
@ -74,10 +74,10 @@ func init() {
|
|||
num[name] = i
|
||||
}
|
||||
buildReg := func(s string) regMask {
|
||||
m := regMask(0)
|
||||
m := regMask{}
|
||||
for _, r := range strings.Split(s, " ") {
|
||||
if n, ok := num[r]; ok {
|
||||
m |= regMask(1) << uint(n)
|
||||
m = m.addReg(uint(n))
|
||||
continue
|
||||
}
|
||||
panic("register " + r + " not found")
|
||||
|
|
@ -88,12 +88,12 @@ func init() {
|
|||
// Common individual register masks
|
||||
var (
|
||||
gp = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14")
|
||||
gpg = gp | buildReg("g")
|
||||
gpsp = gp | buildReg("SP")
|
||||
gpspg = gpg | buildReg("SP")
|
||||
gpspsbg = gpspg | buildReg("SB")
|
||||
gpg = gp.union(buildReg("g"))
|
||||
gpsp = gp.union(buildReg("SP"))
|
||||
gpspg = gpg.union(buildReg("SP"))
|
||||
gpspsbg = gpspg.union(buildReg("SB"))
|
||||
fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15")
|
||||
callerSave = gp | fp | buildReg("g") // runtime.setg (and anything calling it) may clobber g
|
||||
callerSave = gp.union(fp).union(buildReg("g")) // runtime.setg (and anything calling it) may clobber g
|
||||
lr = buildReg("R14")
|
||||
r0 = buildReg("R0")
|
||||
r1 = buildReg("R1")
|
||||
|
|
@ -104,18 +104,18 @@ func init() {
|
|||
var (
|
||||
gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
|
||||
gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
|
||||
gp11carry = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp, 0}}
|
||||
gp11carry = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp, regMask{}}}
|
||||
gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
|
||||
gp1flags = regInfo{inputs: []regMask{gpg}}
|
||||
gp1flags1 = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}
|
||||
gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
|
||||
gp21carry = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp, 0}}
|
||||
gp21carry = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp, regMask{}}}
|
||||
gp2flags = regInfo{inputs: []regMask{gpg, gpg}}
|
||||
gp2flags1 = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}}
|
||||
gp2flags1carry = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, 0}}
|
||||
gp2flags1carry = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, regMask{}}}
|
||||
gp22 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp, gp}}
|
||||
gp31 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
|
||||
gp31carry = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp, 0}}
|
||||
gp31carry = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp, regMask{}}}
|
||||
gp3flags = regInfo{inputs: []regMask{gp, gp, gp}}
|
||||
gp3flags1 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
|
||||
gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
|
||||
|
|
@ -374,7 +374,7 @@ func init() {
|
|||
{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
|
||||
{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
|
||||
|
||||
{name: "MOVWaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVW", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
|
||||
{name: "MOVWaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP").union(buildReg("SB"))}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVW", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
|
||||
|
||||
{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem.
|
||||
{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem.
|
||||
|
|
@ -431,11 +431,11 @@ func init() {
|
|||
{name: "SRAcond", argLength: 3, reg: gp2flags1, asm: "SRA"}, // arg0 >> 31 if flags indicates HS, arg0 >> arg1 otherwise, signed shift, arg2=flags
|
||||
|
||||
// function calls
|
||||
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R7"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R7"), regMask{}}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
|
||||
// pseudo-ops
|
||||
{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem.
|
||||
|
|
@ -549,14 +549,14 @@ func init() {
|
|||
// when both are constant (normally both 0, as prove derives the fact that a [0] bounds
|
||||
// failure means the length must have also been 0).
|
||||
// AuxInt contains a report code (see PanicBounds in genericOps.go).
|
||||
{name: "LoweredPanicBoundsRR", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{gp &^ lr, gp &^ lr}}, typ: "Mem", call: true}, // arg0=x, arg1=y, arg2=mem, returns memory.
|
||||
{name: "LoweredPanicBoundsRC", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{gp &^ lr}}, typ: "Mem", call: true}, // arg0=x, arg1=mem, returns memory.
|
||||
{name: "LoweredPanicBoundsCR", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{gp &^ lr}}, typ: "Mem", call: true}, // arg0=y, arg1=mem, returns memory.
|
||||
{name: "LoweredPanicBoundsCC", argLength: 1, aux: "PanicBoundsCC", reg: regInfo{}, typ: "Mem", call: true}, // arg0=mem, returns memory.
|
||||
{name: "LoweredPanicBoundsRR", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{gp.minus(lr), gp.minus(lr)}}, typ: "Mem", call: true}, // arg0=x, arg1=y, arg2=mem, returns memory.
|
||||
{name: "LoweredPanicBoundsRC", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{gp.minus(lr)}}, typ: "Mem", call: true}, // arg0=x, arg1=mem, returns memory.
|
||||
{name: "LoweredPanicBoundsCR", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{gp.minus(lr)}}, typ: "Mem", call: true}, // arg0=y, arg1=mem, returns memory.
|
||||
{name: "LoweredPanicBoundsCC", argLength: 1, aux: "PanicBoundsCC", reg: regInfo{}, typ: "Mem", call: true}, // arg0=mem, returns memory.
|
||||
|
||||
// Same as above, but the x value is 64 bits.
|
||||
{name: "LoweredPanicExtendRR", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r0 | r1 | r2 | r3, r0 | r1 | r2 | r3, gp}}, typ: "Mem", call: true}, // arg0=x_hi, arg1=x_lo, arg2=y, arg3=mem, returns memory.
|
||||
{name: "LoweredPanicExtendRC", argLength: 3, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{r0 | r1 | r2 | r3, r0 | r1 | r2 | r3}}, typ: "Mem", call: true}, // arg0=x_hi, arg1=x_lo, arg2=mem, returns memory.
|
||||
{name: "LoweredPanicExtendRR", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r0.union(r1).union(r2).union(r3), r0.union(r1).union(r2).union(r3), gp}}, typ: "Mem", call: true}, // arg0=x_hi, arg1=x_lo, arg2=y, arg3=mem, returns memory.
|
||||
{name: "LoweredPanicExtendRC", argLength: 3, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{r0.union(r1).union(r2).union(r3), r0.union(r1).union(r2).union(r3)}}, typ: "Mem", call: true}, // arg0=x_hi, arg1=x_lo, arg2=mem, returns memory.
|
||||
|
||||
// Constant flag value.
|
||||
// Note: there's an "unordered" outcome for floating-point
|
||||
|
|
@ -573,7 +573,7 @@ func init() {
|
|||
// It saves all GP registers if necessary,
|
||||
// but clobbers R14 (LR) because it's a call, and R12 which is linker trampoline scratch register.
|
||||
// Returns a pointer to a write barrier buffer in R8.
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ gpg) | buildReg("R12 R14"), outputs: []regMask{buildReg("R8")}}, clobberFlags: true, aux: "Int64"}}
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave.minus(gpg).union(buildReg("R12 R14")), outputs: []regMask{buildReg("R8")}}, clobberFlags: true, aux: "Int64"}}
|
||||
|
||||
blocks := []blockData{
|
||||
{name: "EQ", controls: 1},
|
||||
|
|
|
|||
|
|
@ -110,10 +110,10 @@ func init() {
|
|||
num[name] = i
|
||||
}
|
||||
buildReg := func(s string) regMask {
|
||||
m := regMask(0)
|
||||
m := regMask{}
|
||||
for _, r := range strings.Split(s, " ") {
|
||||
if n, ok := num[r]; ok {
|
||||
m |= regMask(1) << uint(n)
|
||||
m = m.addReg(uint(n))
|
||||
continue
|
||||
}
|
||||
panic("register " + r + " not found")
|
||||
|
|
@ -124,12 +124,12 @@ func init() {
|
|||
// Common individual register masks
|
||||
var (
|
||||
gp = buildReg("R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31") // R1 is LR, R2 is thread pointer, R3 is stack pointer, R22 is g, R30 is REGTMP
|
||||
gpg = gp | buildReg("g")
|
||||
gpsp = gp | buildReg("SP")
|
||||
gpspg = gpg | buildReg("SP")
|
||||
gpspsbg = gpspg | buildReg("SB")
|
||||
gpg = gp.union(buildReg("g"))
|
||||
gpsp = gp.union(buildReg("SP"))
|
||||
gpspg = gpg.union(buildReg("SP"))
|
||||
gpspsbg = gpspg.union(buildReg("SB"))
|
||||
fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31")
|
||||
callerSave = gp | fp | buildReg("g") // runtime.setg (and anything calling it) may clobber g
|
||||
callerSave = gp.union(fp).union(buildReg("g")) // runtime.setg (and anything calling it) may clobber g
|
||||
first16 = buildReg("R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19")
|
||||
rz = buildReg("ZERO")
|
||||
)
|
||||
|
|
@ -138,11 +138,11 @@ func init() {
|
|||
gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
|
||||
gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
|
||||
gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
|
||||
gp21 = regInfo{inputs: []regMask{gpg, gpg | rz}, outputs: []regMask{gp}}
|
||||
gp21 = regInfo{inputs: []regMask{gpg, gpg.union(rz)}, outputs: []regMask{gp}}
|
||||
gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
|
||||
gp2load = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
|
||||
gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}}
|
||||
gpstore2 = regInfo{inputs: []regMask{gpspsbg, gpg, gpg | rz}}
|
||||
gpstore2 = regInfo{inputs: []regMask{gpspsbg, gpg, gpg.union(rz)}}
|
||||
gpoldatom = regInfo{inputs: []regMask{gpspsbg, gpg}}
|
||||
gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
|
||||
gpcas = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}}
|
||||
|
|
@ -289,7 +289,7 @@ func init() {
|
|||
{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
|
||||
{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
|
||||
|
||||
{name: "MOVVaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVV", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
|
||||
{name: "MOVVaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP").union(buildReg("SB"))}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVV", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
|
||||
|
||||
{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem.
|
||||
{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem.
|
||||
|
|
@ -312,12 +312,12 @@ func init() {
|
|||
{name: "MOVFloadidx", argLength: 3, reg: fp2load, asm: "MOVF", typ: "Float32"}, // load 32-bit float from arg0 + arg1, arg2=mem.
|
||||
{name: "MOVDloadidx", argLength: 3, reg: fp2load, asm: "MOVD", typ: "Float64"}, // load 64-bit float from arg0 + arg1, arg2=mem.
|
||||
|
||||
{name: "MOVBstore", argLength: 3, reg: regInfo{inputs: []regMask{gpspsbg, gpg | rz}}, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of arg1 to arg0 + auxInt + aux. arg2=mem.
|
||||
{name: "MOVHstore", argLength: 3, reg: regInfo{inputs: []regMask{gpspsbg, gpg | rz}}, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
|
||||
{name: "MOVWstore", argLength: 3, reg: regInfo{inputs: []regMask{gpspsbg, gpg | rz}}, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
|
||||
{name: "MOVVstore", argLength: 3, reg: regInfo{inputs: []regMask{gpspsbg, gpg | rz}}, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
|
||||
{name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
|
||||
{name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
|
||||
{name: "MOVBstore", argLength: 3, reg: regInfo{inputs: []regMask{gpspsbg, gpg.union(rz)}}, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of arg1 to arg0 + auxInt + aux. arg2=mem.
|
||||
{name: "MOVHstore", argLength: 3, reg: regInfo{inputs: []regMask{gpspsbg, gpg.union(rz)}}, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
|
||||
{name: "MOVWstore", argLength: 3, reg: regInfo{inputs: []regMask{gpspsbg, gpg.union(rz)}}, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
|
||||
{name: "MOVVstore", argLength: 3, reg: regInfo{inputs: []regMask{gpspsbg, gpg.union(rz)}}, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
|
||||
{name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
|
||||
{name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
|
||||
|
||||
// register indexed store
|
||||
{name: "MOVBstoreidx", argLength: 4, reg: gpstore2, asm: "MOVB", typ: "Mem"}, // store 1 byte of arg2 to arg0 + arg1, arg3 = mem.
|
||||
|
|
@ -366,11 +366,11 @@ func init() {
|
|||
{name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true},
|
||||
|
||||
// function calls
|
||||
{name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{gpsp, buildReg("R29"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{gpsp, buildReg("R29"), regMask{}}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
|
||||
// medium zeroing
|
||||
// arg0 = address of memory to zero
|
||||
|
|
@ -416,7 +416,7 @@ func init() {
|
|||
aux: "Int64",
|
||||
argLength: 3,
|
||||
reg: regInfo{
|
||||
inputs: []regMask{gp &^ buildReg("R23"), gp &^ buildReg("R23")},
|
||||
inputs: []regMask{gp.minus(buildReg("R23")), gp.minus(buildReg("R23"))},
|
||||
clobbers: buildReg("R23"),
|
||||
},
|
||||
faultOnNilArg0: true,
|
||||
|
|
@ -434,7 +434,7 @@ func init() {
|
|||
aux: "Int64",
|
||||
argLength: 3,
|
||||
reg: regInfo{
|
||||
inputs: []regMask{gp &^ buildReg("R23 R24"), gp &^ buildReg("R23 R24")},
|
||||
inputs: []regMask{gp.minus(buildReg("R23 R24")), gp.minus(buildReg("R23 R24"))},
|
||||
clobbers: buildReg("R23 R24"),
|
||||
clobbersArg0: true,
|
||||
clobbersArg1: true,
|
||||
|
|
@ -553,7 +553,7 @@ func init() {
|
|||
// but clobbers R1 (LR) because it's a call
|
||||
// and R30 (REGTMP).
|
||||
// Returns a pointer to a write barrier buffer in R29.
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ gpg) | buildReg("R1"), outputs: []regMask{buildReg("R29")}}, clobberFlags: true, aux: "Int64"},
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave.minus(gpg).union(buildReg("R1")), outputs: []regMask{buildReg("R29")}}, clobberFlags: true, aux: "Int64"},
|
||||
|
||||
// Do data barrier. arg0=memorys
|
||||
{name: "LoweredPubBarrier", argLength: 1, asm: "DBAR", hasSideEffects: true},
|
||||
|
|
|
|||
|
|
@ -114,10 +114,10 @@ func init() {
|
|||
num[name] = i
|
||||
}
|
||||
buildReg := func(s string) regMask {
|
||||
m := regMask(0)
|
||||
m := regMask{}
|
||||
for _, r := range strings.Split(s, " ") {
|
||||
if n, ok := num[r]; ok {
|
||||
m |= regMask(1) << uint(n)
|
||||
m = m.addReg(uint(n))
|
||||
continue
|
||||
}
|
||||
panic("register " + r + " not found")
|
||||
|
|
@ -128,14 +128,14 @@ func init() {
|
|||
// Common individual register masks
|
||||
var (
|
||||
gp = buildReg("R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31")
|
||||
gpg = gp | buildReg("g")
|
||||
gpsp = gp | buildReg("SP")
|
||||
gpspg = gpg | buildReg("SP")
|
||||
gpspsbg = gpspg | buildReg("SB")
|
||||
gpg = gp.union(buildReg("g"))
|
||||
gpsp = gp.union(buildReg("SP"))
|
||||
gpspg = gpg.union(buildReg("SP"))
|
||||
gpspsbg = gpspg.union(buildReg("SB"))
|
||||
fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31")
|
||||
lo = buildReg("LO")
|
||||
hi = buildReg("HI")
|
||||
callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg (and anything calling it) may clobber g
|
||||
callerSave = gp.union(fp).union(lo).union(hi).union(buildReg("g")) // runtime.setg (and anything calling it) may clobber g
|
||||
first16 = buildReg("R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16")
|
||||
rz = buildReg("ZERO")
|
||||
)
|
||||
|
|
@ -144,10 +144,10 @@ func init() {
|
|||
gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
|
||||
gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
|
||||
gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
|
||||
gp21 = regInfo{inputs: []regMask{gpg, gpg | rz}, outputs: []regMask{gp}}
|
||||
gp21 = regInfo{inputs: []regMask{gpg, gpg.union(rz)}, outputs: []regMask{gp}}
|
||||
gp2hilo = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}}
|
||||
gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
|
||||
gpstore = regInfo{inputs: []regMask{gpspsbg, gpg | rz}}
|
||||
gpstore = regInfo{inputs: []regMask{gpspsbg, gpg.union(rz)}}
|
||||
gpstore0 = regInfo{inputs: []regMask{gpspsbg}}
|
||||
gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
|
||||
gpcas = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}}
|
||||
|
|
@ -224,7 +224,7 @@ func init() {
|
|||
{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
|
||||
{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
|
||||
|
||||
{name: "MOVVaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVV", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
|
||||
{name: "MOVVaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP").union(buildReg("SB"))}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVV", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
|
||||
|
||||
{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem.
|
||||
{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem.
|
||||
|
|
@ -274,11 +274,11 @@ func init() {
|
|||
{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32
|
||||
|
||||
// function calls
|
||||
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), regMask{}}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
|
||||
// duffzero
|
||||
// arg0 = address of memory to zero
|
||||
|
|
@ -460,7 +460,7 @@ func init() {
|
|||
// but clobbers R31 (LR) because it's a call
|
||||
// and R23 (REGTMP).
|
||||
// Returns a pointer to a write barrier buffer in R25.
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ gpg) | buildReg("R31"), outputs: []regMask{buildReg("R25")}}, clobberFlags: true, aux: "Int64"},
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave.minus(gpg).union(buildReg("R31")), outputs: []regMask{buildReg("R25")}}, clobberFlags: true, aux: "Int64"},
|
||||
|
||||
// Do data barrier. arg0=memorys
|
||||
{name: "LoweredPubBarrier", argLength: 1, asm: "SYNC", hasSideEffects: true},
|
||||
|
|
@ -496,7 +496,7 @@ func init() {
|
|||
regnames: regNamesMIPS64,
|
||||
gpregmask: gp,
|
||||
fpregmask: fp,
|
||||
specialregmask: hi | lo,
|
||||
specialregmask: hi.union(lo),
|
||||
framepointerreg: -1, // not used
|
||||
linkreg: int8(num["R31"]),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -98,10 +98,10 @@ func init() {
|
|||
num[name] = i
|
||||
}
|
||||
buildReg := func(s string) regMask {
|
||||
m := regMask(0)
|
||||
m := regMask{}
|
||||
for _, r := range strings.Split(s, " ") {
|
||||
if n, ok := num[r]; ok {
|
||||
m |= regMask(1) << uint(n)
|
||||
m = m.addReg(uint(n))
|
||||
continue
|
||||
}
|
||||
panic("register " + r + " not found")
|
||||
|
|
@ -112,14 +112,14 @@ func init() {
|
|||
// Common individual register masks
|
||||
var (
|
||||
gp = buildReg("R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 R31")
|
||||
gpg = gp | buildReg("g")
|
||||
gpsp = gp | buildReg("SP")
|
||||
gpspg = gpg | buildReg("SP")
|
||||
gpspsbg = gpspg | buildReg("SB")
|
||||
gpg = gp.union(buildReg("g"))
|
||||
gpsp = gp.union(buildReg("SP"))
|
||||
gpspg = gpg.union(buildReg("SP"))
|
||||
gpspsbg = gpspg.union(buildReg("SB"))
|
||||
fp = buildReg("F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30")
|
||||
lo = buildReg("LO")
|
||||
hi = buildReg("HI")
|
||||
callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg (and anything calling it) may clobber g
|
||||
callerSave = gp.union(fp).union(lo).union(hi).union(buildReg("g")) // runtime.setg (and anything calling it) may clobber g
|
||||
first16 = buildReg("R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16")
|
||||
first4 = buildReg("R1 R2 R3 R4")
|
||||
)
|
||||
|
|
@ -147,15 +147,15 @@ func init() {
|
|||
readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
|
||||
)
|
||||
ops := []opData{
|
||||
{name: "ADD", argLength: 2, reg: gp21, asm: "ADDU", commutative: true}, // arg0 + arg1
|
||||
{name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADDU", aux: "Int32"}, // arg0 + auxInt
|
||||
{name: "SUB", argLength: 2, reg: gp21, asm: "SUBU"}, // arg0 - arg1
|
||||
{name: "SUBconst", argLength: 1, reg: gp11, asm: "SUBU", aux: "Int32"}, // arg0 - auxInt
|
||||
{name: "MUL", argLength: 2, reg: regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}, clobbers: hi | lo}, asm: "MUL", commutative: true}, // arg0 * arg1
|
||||
{name: "MULT", argLength: 2, reg: gp2hilo, asm: "MUL", commutative: true, typ: "(Int32,Int32)"}, // arg0 * arg1, signed, results hi,lo
|
||||
{name: "MULTU", argLength: 2, reg: gp2hilo, asm: "MULU", commutative: true, typ: "(UInt32,UInt32)"}, // arg0 * arg1, unsigned, results hi,lo
|
||||
{name: "DIV", argLength: 2, reg: gp2hilo, asm: "DIV", typ: "(Int32,Int32)", hasSideEffects: true}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
|
||||
{name: "DIVU", argLength: 2, reg: gp2hilo, asm: "DIVU", typ: "(UInt32,UInt32)", hasSideEffects: true}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
|
||||
{name: "ADD", argLength: 2, reg: gp21, asm: "ADDU", commutative: true}, // arg0 + arg1
|
||||
{name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADDU", aux: "Int32"}, // arg0 + auxInt
|
||||
{name: "SUB", argLength: 2, reg: gp21, asm: "SUBU"}, // arg0 - arg1
|
||||
{name: "SUBconst", argLength: 1, reg: gp11, asm: "SUBU", aux: "Int32"}, // arg0 - auxInt
|
||||
{name: "MUL", argLength: 2, reg: regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}, clobbers: hi.union(lo)}, asm: "MUL", commutative: true}, // arg0 * arg1
|
||||
{name: "MULT", argLength: 2, reg: gp2hilo, asm: "MUL", commutative: true, typ: "(Int32,Int32)"}, // arg0 * arg1, signed, results hi,lo
|
||||
{name: "MULTU", argLength: 2, reg: gp2hilo, asm: "MULU", commutative: true, typ: "(UInt32,UInt32)"}, // arg0 * arg1, unsigned, results hi,lo
|
||||
{name: "DIV", argLength: 2, reg: gp2hilo, asm: "DIV", typ: "(Int32,Int32)", hasSideEffects: true}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
|
||||
{name: "DIVU", argLength: 2, reg: gp2hilo, asm: "DIVU", typ: "(UInt32,UInt32)", hasSideEffects: true}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
|
||||
|
||||
{name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1
|
||||
{name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1
|
||||
|
|
@ -211,7 +211,7 @@ func init() {
|
|||
{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float32", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
|
||||
{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
|
||||
|
||||
{name: "MOVWaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVW", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
|
||||
{name: "MOVWaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP").union(buildReg("SB"))}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVW", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
|
||||
|
||||
{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem.
|
||||
{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem.
|
||||
|
|
@ -257,11 +257,11 @@ func init() {
|
|||
{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32
|
||||
|
||||
// function calls
|
||||
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=cpdeptr, arg1=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=cpdeptr, arg1=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), regMask{}}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
|
||||
// atomic ops
|
||||
|
||||
|
|
@ -403,7 +403,7 @@ func init() {
|
|||
// but clobbers R31 (LR) because it's a call
|
||||
// and R23 (REGTMP).
|
||||
// Returns a pointer to a write barrier buffer in R25.
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ gpg) | buildReg("R31"), outputs: []regMask{buildReg("R25")}}, clobberFlags: true, aux: "Int64"},
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave.minus(gpg).union(buildReg("R31")), outputs: []regMask{buildReg("R25")}}, clobberFlags: true, aux: "Int64"},
|
||||
|
||||
// Do data barrier. arg0=memorys
|
||||
{name: "LoweredPubBarrier", argLength: 1, asm: "SYNC", hasSideEffects: true},
|
||||
|
|
@ -443,7 +443,7 @@ func init() {
|
|||
regnames: regNamesMIPS,
|
||||
gpregmask: gp,
|
||||
fpregmask: fp,
|
||||
specialregmask: hi | lo,
|
||||
specialregmask: hi.union(lo),
|
||||
framepointerreg: -1, // not used
|
||||
linkreg: int8(num["R31"]),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -109,10 +109,10 @@ func init() {
|
|||
num[name] = i
|
||||
}
|
||||
buildReg := func(s string) regMask {
|
||||
m := regMask(0)
|
||||
m := regMask{}
|
||||
for _, r := range strings.Split(s, " ") {
|
||||
if n, ok := num[r]; ok {
|
||||
m |= regMask(1) << uint(n)
|
||||
m = m.addReg(uint(n))
|
||||
continue
|
||||
}
|
||||
panic("register " + r + " not found")
|
||||
|
|
@ -135,30 +135,30 @@ func init() {
|
|||
callptr = buildReg("R12")
|
||||
// tls = buildReg("R13")
|
||||
gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
|
||||
gp11 = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
|
||||
gp11 = regInfo{inputs: []regMask{gp.union(sp).union(sb)}, outputs: []regMask{gp}}
|
||||
xergp = regInfo{inputs: []regMask{xer}, outputs: []regMask{gp}, clobbers: xer}
|
||||
gp11cxer = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}, clobbers: xer}
|
||||
gp11xer = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp, xer}}
|
||||
gp1xer1xer = regInfo{inputs: []regMask{gp | sp | sb, xer}, outputs: []regMask{gp, xer}, clobbers: xer}
|
||||
gp21 = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}}
|
||||
gp21a0 = regInfo{inputs: []regMask{gp, gp | sp | sb}, outputs: []regMask{gp}}
|
||||
gp21cxer = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}, clobbers: xer}
|
||||
gp21xer = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp, xer}, clobbers: xer}
|
||||
gp2xer1xer = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, xer}, outputs: []regMask{gp, xer}, clobbers: xer}
|
||||
gp31 = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}}
|
||||
gp1cr = regInfo{inputs: []regMask{gp | sp | sb}}
|
||||
gp2cr = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}}
|
||||
gp11cxer = regInfo{inputs: []regMask{gp.union(sp).union(sb)}, outputs: []regMask{gp}, clobbers: xer}
|
||||
gp11xer = regInfo{inputs: []regMask{gp.union(sp).union(sb)}, outputs: []regMask{gp, xer}}
|
||||
gp1xer1xer = regInfo{inputs: []regMask{gp.union(sp).union(sb), xer}, outputs: []regMask{gp, xer}, clobbers: xer}
|
||||
gp21 = regInfo{inputs: []regMask{gp.union(sp).union(sb), gp.union(sp).union(sb)}, outputs: []regMask{gp}}
|
||||
gp21a0 = regInfo{inputs: []regMask{gp, gp.union(sp).union(sb)}, outputs: []regMask{gp}}
|
||||
gp21cxer = regInfo{inputs: []regMask{gp.union(sp).union(sb), gp.union(sp).union(sb)}, outputs: []regMask{gp}, clobbers: xer}
|
||||
gp21xer = regInfo{inputs: []regMask{gp.union(sp).union(sb), gp.union(sp).union(sb)}, outputs: []regMask{gp, xer}, clobbers: xer}
|
||||
gp2xer1xer = regInfo{inputs: []regMask{gp.union(sp).union(sb), gp.union(sp).union(sb), xer}, outputs: []regMask{gp, xer}, clobbers: xer}
|
||||
gp31 = regInfo{inputs: []regMask{gp.union(sp).union(sb), gp.union(sp).union(sb), gp.union(sp).union(sb)}, outputs: []regMask{gp}}
|
||||
gp1cr = regInfo{inputs: []regMask{gp.union(sp).union(sb)}}
|
||||
gp2cr = regInfo{inputs: []regMask{gp.union(sp).union(sb), gp.union(sp).union(sb)}}
|
||||
crgp = regInfo{inputs: nil, outputs: []regMask{gp}}
|
||||
crgp11 = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}
|
||||
crgp21 = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}}
|
||||
gpload = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
|
||||
gploadidx = regInfo{inputs: []regMask{gp | sp | sb, gp}, outputs: []regMask{gp}}
|
||||
prefreg = regInfo{inputs: []regMask{gp | sp | sb}}
|
||||
gpstore = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}}
|
||||
gpstoreidx = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, gp | sp | sb}}
|
||||
gpstorezero = regInfo{inputs: []regMask{gp | sp | sb}} // ppc64.REGZERO is reserved zero value
|
||||
gpxchg = regInfo{inputs: []regMask{gp | sp | sb, gp}, outputs: []regMask{gp}}
|
||||
gpcas = regInfo{inputs: []regMask{gp | sp | sb, gp, gp}, outputs: []regMask{gp}}
|
||||
gpload = regInfo{inputs: []regMask{gp.union(sp).union(sb)}, outputs: []regMask{gp}}
|
||||
gploadidx = regInfo{inputs: []regMask{gp.union(sp).union(sb), gp}, outputs: []regMask{gp}}
|
||||
prefreg = regInfo{inputs: []regMask{gp.union(sp).union(sb)}}
|
||||
gpstore = regInfo{inputs: []regMask{gp.union(sp).union(sb), gp.union(sp).union(sb)}}
|
||||
gpstoreidx = regInfo{inputs: []regMask{gp.union(sp).union(sb), gp.union(sp).union(sb), gp.union(sp).union(sb)}}
|
||||
gpstorezero = regInfo{inputs: []regMask{gp.union(sp).union(sb)}} // ppc64.REGZERO is reserved zero value
|
||||
gpxchg = regInfo{inputs: []regMask{gp.union(sp).union(sb), gp}, outputs: []regMask{gp}}
|
||||
gpcas = regInfo{inputs: []regMask{gp.union(sp).union(sb), gp, gp}, outputs: []regMask{gp}}
|
||||
fp01 = regInfo{inputs: nil, outputs: []regMask{fp}}
|
||||
fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
|
||||
fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
|
||||
|
|
@ -166,11 +166,11 @@ func init() {
|
|||
fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
|
||||
fp31 = regInfo{inputs: []regMask{fp, fp, fp}, outputs: []regMask{fp}}
|
||||
fp2cr = regInfo{inputs: []regMask{fp, fp}}
|
||||
fpload = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{fp}}
|
||||
fploadidx = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{fp}}
|
||||
fpstore = regInfo{inputs: []regMask{gp | sp | sb, fp}}
|
||||
fpstoreidx = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, fp}}
|
||||
callerSave = regMask(gp | fp | gr | xer)
|
||||
fpload = regInfo{inputs: []regMask{gp.union(sp).union(sb)}, outputs: []regMask{fp}}
|
||||
fploadidx = regInfo{inputs: []regMask{gp.union(sp).union(sb), gp.union(sp).union(sb)}, outputs: []regMask{fp}}
|
||||
fpstore = regInfo{inputs: []regMask{gp.union(sp).union(sb), fp}}
|
||||
fpstoreidx = regInfo{inputs: []regMask{gp.union(sp).union(sb), gp.union(sp).union(sb), fp}}
|
||||
callerSave = regMask(gp.union(fp).union(gr).union(xer))
|
||||
first7 = buildReg("R3 R4 R5 R6 R7 R8 R9")
|
||||
)
|
||||
ops := []opData{
|
||||
|
|
@ -322,10 +322,10 @@ func init() {
|
|||
{name: "FNABS", argLength: 1, reg: fp11, asm: "FNABS"}, // -abs(arg0), float64
|
||||
{name: "FCPSGN", argLength: 2, reg: fp21, asm: "FCPSGN"}, // copysign arg0 -> arg1, float64
|
||||
|
||||
{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"}, // arg0|aux
|
||||
{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64"}, // arg0^aux
|
||||
{name: "ANDCCconst", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}, asm: "ANDCC", aux: "Int64", typ: "(Int,Flags)"}, // arg0&aux == 0 // and-immediate sets CC on PPC, always.
|
||||
{name: "ANDconst", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}, clobberFlags: true, asm: "ANDCC", aux: "Int64", typ: "Int"}, // arg0&aux == 0 // and-immediate sets CC on PPC, always.
|
||||
{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"}, // arg0|aux
|
||||
{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64"}, // arg0^aux
|
||||
{name: "ANDCCconst", argLength: 1, reg: regInfo{inputs: []regMask{gp.union(sp).union(sb)}, outputs: []regMask{gp}}, asm: "ANDCC", aux: "Int64", typ: "(Int,Flags)"}, // arg0&aux == 0 // and-immediate sets CC on PPC, always.
|
||||
{name: "ANDconst", argLength: 1, reg: regInfo{inputs: []regMask{gp.union(sp).union(sb)}, outputs: []regMask{gp}}, clobberFlags: true, asm: "ANDCC", aux: "Int64", typ: "Int"}, // arg0&aux == 0 // and-immediate sets CC on PPC, always.
|
||||
|
||||
{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB", typ: "Int64"}, // sign extend int8 to int64
|
||||
{name: "MOVBZreg", argLength: 1, reg: gp11, asm: "MOVBZ", typ: "Int64"}, // zero extend uint8 to uint64
|
||||
|
|
@ -405,7 +405,7 @@ func init() {
|
|||
{name: "MOVWstorezero", argLength: 2, reg: gpstorezero, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 4 bytes
|
||||
{name: "MOVDstorezero", argLength: 2, reg: gpstorezero, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 8 bytes
|
||||
|
||||
{name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{sp | sb | gp}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB/GP
|
||||
{name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{sp.union(sb).union(gp)}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB/GP
|
||||
|
||||
{name: "MOVDconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVD", typ: "Int64", rematerializeable: true}, //
|
||||
{name: "FMOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVD", rematerializeable: true}, //
|
||||
|
|
@ -460,7 +460,7 @@ func init() {
|
|||
{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
|
||||
|
||||
//arg0=ptr,arg1=mem, returns void. Faults if ptr is nil.
|
||||
{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true},
|
||||
{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gp.union(sp).union(sb)}, clobbers: tmp}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true},
|
||||
// Round ops to block fused-multiply-add extraction.
|
||||
{name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true},
|
||||
{name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true},
|
||||
|
|
@ -468,7 +468,7 @@ func init() {
|
|||
{name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: -1, reg: regInfo{inputs: []regMask{callptr}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{callptr, ctxt, 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{callptr, ctxt, regMask{}}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{callptr}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
|
||||
// large or unaligned zeroing
|
||||
|
|
@ -701,7 +701,7 @@ func init() {
|
|||
// It preserves R0 through R17 (except special registers R1, R2, R11, R12, R13), g, and R20 and R21,
|
||||
// but may clobber anything else, including R31 (REGTMP).
|
||||
// Returns a pointer to a write barrier buffer in R29.
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ buildReg("R0 R3 R4 R5 R6 R7 R8 R9 R10 R14 R15 R16 R17 R20 R21 g")) | buildReg("R31"), outputs: []regMask{buildReg("R29")}}, clobberFlags: true, aux: "Int64"},
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave.minus(buildReg("R0 R3 R4 R5 R6 R7 R8 R9 R10 R14 R15 R16 R17 R20 R21 g")).union(buildReg("R31")), outputs: []regMask{buildReg("R29")}}, clobberFlags: true, aux: "Int64"},
|
||||
|
||||
{name: "LoweredPubBarrier", argLength: 1, asm: "LWSYNC", hasSideEffects: true}, // Do data barrier. arg0=memory
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ func init() {
|
|||
//
|
||||
// If name is specified, use it rather than the riscv reg number.
|
||||
addreg := func(r int, name string) regMask {
|
||||
mask := regMask(1) << uint(len(regNamesRISCV64))
|
||||
mask := regMaskAt(uint(len(regNamesRISCV64)))
|
||||
if name == "" {
|
||||
name = riscv64RegName(r)
|
||||
}
|
||||
|
|
@ -81,20 +81,20 @@ func init() {
|
|||
// ZERO, GP, TP and TMP are not in any gp mask.
|
||||
case riscv64REG_ZERO, riscv64REG_GP, riscv64REG_TP, riscv64REG_TMP:
|
||||
case riscv64REG_G:
|
||||
gpgMask |= mask
|
||||
gpspsbgMask |= mask
|
||||
gpgMask = gpgMask.union(mask)
|
||||
gpspsbgMask = gpspsbgMask.union(mask)
|
||||
case riscv64REG_SP:
|
||||
gpspMask |= mask
|
||||
gpspsbMask |= mask
|
||||
gpspsbgMask |= mask
|
||||
gpspMask = gpspMask.union(mask)
|
||||
gpspsbMask = gpspsbMask.union(mask)
|
||||
gpspsbgMask = gpspsbgMask.union(mask)
|
||||
default:
|
||||
gpMask |= mask
|
||||
gpgMask |= mask
|
||||
gpspMask |= mask
|
||||
gpspsbMask |= mask
|
||||
gpspsbgMask |= mask
|
||||
gpMask = gpMask.union(mask)
|
||||
gpgMask = gpgMask.union(mask)
|
||||
gpspMask = gpspMask.union(mask)
|
||||
gpspsbMask = gpspsbMask.union(mask)
|
||||
gpspsbgMask = gpspsbgMask.union(mask)
|
||||
if r >= 5 && r < 5+16 {
|
||||
first16Mask |= mask
|
||||
first16Mask = first16Mask.union(mask)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -102,13 +102,13 @@ func init() {
|
|||
// Floating point registers.
|
||||
for r := 32; r <= 63; r++ {
|
||||
mask := addreg(r, "")
|
||||
fpMask |= mask
|
||||
fpMask = fpMask.union(mask)
|
||||
}
|
||||
|
||||
// Pseudo-register: SB
|
||||
mask := addreg(-1, "SB")
|
||||
gpspsbMask |= mask
|
||||
gpspsbgMask |= mask
|
||||
gpspsbMask = gpspsbMask.union(mask)
|
||||
gpspsbgMask = gpspsbgMask.union(mask)
|
||||
|
||||
if len(regNamesRISCV64) > 64 {
|
||||
// regMask is only 64 bits.
|
||||
|
|
@ -116,18 +116,18 @@ func init() {
|
|||
}
|
||||
|
||||
regCtxt := regNamed["X26"]
|
||||
callerSave := gpMask | fpMask | regNamed["g"]
|
||||
r5toR6 := regNamed["X5"] | regNamed["X6"]
|
||||
callerSave := gpMask.union(fpMask).union(regNamed["g"])
|
||||
r5toR6 := regNamed["X5"].union(regNamed["X6"])
|
||||
regX5 := regNamed["X5"]
|
||||
|
||||
var (
|
||||
gpstore = regInfo{inputs: []regMask{gpspsbMask, gpspMask, 0}} // SB in first input so we can load from a global, but not in second to avoid using SB as a temporary register
|
||||
gpstore = regInfo{inputs: []regMask{gpspsbMask, gpspMask, regMask{}}} // SB in first input so we can load from a global, but not in second to avoid using SB as a temporary register
|
||||
gpstore0 = regInfo{inputs: []regMask{gpspsbMask}}
|
||||
gp01 = regInfo{outputs: []regMask{gpMask}}
|
||||
gp11 = regInfo{inputs: []regMask{gpMask}, outputs: []regMask{gpMask}}
|
||||
gp21 = regInfo{inputs: []regMask{gpMask, gpMask}, outputs: []regMask{gpMask}}
|
||||
gp22 = regInfo{inputs: []regMask{gpMask, gpMask}, outputs: []regMask{gpMask, gpMask}}
|
||||
gpload = regInfo{inputs: []regMask{gpspsbMask, 0}, outputs: []regMask{gpMask}}
|
||||
gpload = regInfo{inputs: []regMask{gpspsbMask, regMask{}}, outputs: []regMask{gpMask}}
|
||||
gp11sb = regInfo{inputs: []regMask{gpspsbMask}, outputs: []regMask{gpMask}}
|
||||
gpxchg = regInfo{inputs: []regMask{gpspsbgMask, gpgMask}, outputs: []regMask{gpMask}}
|
||||
gpcas = regInfo{inputs: []regMask{gpspsbgMask, gpgMask, gpgMask}, outputs: []regMask{gpMask}}
|
||||
|
|
@ -139,8 +139,8 @@ func init() {
|
|||
fp31 = regInfo{inputs: []regMask{fpMask, fpMask, fpMask}, outputs: []regMask{fpMask}}
|
||||
gpfp = regInfo{inputs: []regMask{gpMask}, outputs: []regMask{fpMask}}
|
||||
fpgp = regInfo{inputs: []regMask{fpMask}, outputs: []regMask{gpMask}}
|
||||
fpstore = regInfo{inputs: []regMask{gpspsbMask, fpMask, 0}}
|
||||
fpload = regInfo{inputs: []regMask{gpspsbMask, 0}, outputs: []regMask{fpMask}}
|
||||
fpstore = regInfo{inputs: []regMask{gpspsbMask, fpMask, regMask{}}}
|
||||
fpload = regInfo{inputs: []regMask{gpspsbMask, regMask{}}, outputs: []regMask{fpMask}}
|
||||
fp2gp = regInfo{inputs: []regMask{fpMask, fpMask}, outputs: []regMask{gpMask}}
|
||||
|
||||
call = regInfo{clobbers: callerSave}
|
||||
|
|
@ -148,8 +148,8 @@ func init() {
|
|||
// RAS pop-then-push behavior which is not correct for function calls.
|
||||
// Please refer to section 2.5.1 of the RISC-V ISA
|
||||
// (https://docs.riscv.org/reference/isa/unpriv/rv32.html#rashints) for details.
|
||||
callClosure = regInfo{inputs: []regMask{gpspMask ^ regX5, regCtxt, 0}, clobbers: callerSave}
|
||||
callInter = regInfo{inputs: []regMask{gpMask ^ regX5}, clobbers: callerSave}
|
||||
callClosure = regInfo{inputs: []regMask{gpspMask.minus(regX5), regCtxt, regMask{}}, clobbers: callerSave}
|
||||
callInter = regInfo{inputs: []regMask{gpMask.minus(regX5)}, clobbers: callerSave}
|
||||
)
|
||||
|
||||
RISCV64ops := []opData{
|
||||
|
|
@ -339,7 +339,7 @@ func init() {
|
|||
symEffect: "Write",
|
||||
argLength: 3,
|
||||
reg: regInfo{
|
||||
inputs: []regMask{gpMask &^ regNamed["X5"], gpMask &^ regNamed["X5"]},
|
||||
inputs: []regMask{gpMask.minus(regNamed["X5"]), gpMask.minus(regNamed["X5"])},
|
||||
clobbers: regNamed["X5"],
|
||||
},
|
||||
faultOnNilArg0: true,
|
||||
|
|
@ -366,7 +366,7 @@ func init() {
|
|||
argLength: 3,
|
||||
symEffect: "Write",
|
||||
reg: regInfo{
|
||||
inputs: []regMask{gpMask &^ r5toR6, gpMask &^ r5toR6},
|
||||
inputs: []regMask{gpMask.minus(r5toR6), gpMask.minus(r5toR6)},
|
||||
clobbers: r5toR6,
|
||||
clobbersArg0: true,
|
||||
clobbersArg1: true,
|
||||
|
|
@ -438,7 +438,7 @@ func init() {
|
|||
// but clobbers RA (LR) because it's a call
|
||||
// and T6 (REG_TMP).
|
||||
// Returns a pointer to a write barrier buffer in X24.
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ (gpMask | regNamed["g"])) | regNamed["X1"], outputs: []regMask{regNamed["X24"]}}, clobberFlags: true, aux: "Int64"},
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave.minus(gpMask.union(regNamed["g"])).union(regNamed["X1"]), outputs: []regMask{regNamed["X24"]}}, clobberFlags: true, aux: "Int64"},
|
||||
|
||||
// Do data barrier. arg0=memorys
|
||||
{name: "LoweredPubBarrier", argLength: 1, asm: "FENCE", hasSideEffects: true},
|
||||
|
|
|
|||
|
|
@ -97,10 +97,10 @@ func init() {
|
|||
num[name] = i
|
||||
}
|
||||
buildReg := func(s string) regMask {
|
||||
m := regMask(0)
|
||||
m := regMask{}
|
||||
for _, r := range strings.Split(s, " ") {
|
||||
if n, ok := num[r]; ok {
|
||||
m |= regMask(1) << uint(n)
|
||||
m = m.addReg(uint(n))
|
||||
continue
|
||||
}
|
||||
panic("register " + r + " not found")
|
||||
|
|
@ -118,16 +118,16 @@ func init() {
|
|||
|
||||
// R10 is reserved by the assembler.
|
||||
gp = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14")
|
||||
gpg = gp | buildReg("g")
|
||||
gpsp = gp | sp
|
||||
gpg = gp.union(buildReg("g"))
|
||||
gpsp = gp.union(sp)
|
||||
|
||||
// R0 is considered to contain the value 0 in address calculations.
|
||||
ptr = gp &^ r0
|
||||
ptrsp = ptr | sp
|
||||
ptrspsb = ptrsp | sb
|
||||
ptr = gp.minus(r0)
|
||||
ptrsp = ptr.union(sp)
|
||||
ptrspsb = ptrsp.union(sb)
|
||||
|
||||
fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15")
|
||||
callerSave = gp | fp | buildReg("g") // runtime.setg (and anything calling it) may clobber g
|
||||
callerSave = gp.union(fp).union(buildReg("g")) // runtime.setg (and anything calling it) may clobber g
|
||||
r1 = buildReg("R1")
|
||||
r2 = buildReg("R2")
|
||||
r3 = buildReg("R3")
|
||||
|
|
@ -146,14 +146,14 @@ func init() {
|
|||
gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly}
|
||||
gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
|
||||
gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly}
|
||||
gp21tmp = regInfo{inputs: []regMask{gp &^ tmp, gp &^ tmp}, outputs: []regMask{gp &^ tmp}, clobbers: tmp}
|
||||
gp21tmp = regInfo{inputs: []regMask{gp.minus(tmp), gp.minus(tmp)}, outputs: []regMask{gp.minus(tmp)}, clobbers: tmp}
|
||||
|
||||
// R0 evaluates to 0 when used as the number of bits to shift
|
||||
// so we need to exclude it from that operand.
|
||||
sh21 = regInfo{inputs: []regMask{gp, ptr}, outputs: gponly}
|
||||
|
||||
addr = regInfo{inputs: []regMask{sp | sb}, outputs: gponly}
|
||||
addridx = regInfo{inputs: []regMask{sp | sb, ptrsp}, outputs: gponly}
|
||||
addr = regInfo{inputs: []regMask{sp.union(sb)}, outputs: gponly}
|
||||
addridx = regInfo{inputs: []regMask{sp.union(sb), ptrsp}, outputs: gponly}
|
||||
|
||||
gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}}
|
||||
gp1flags = regInfo{inputs: []regMask{gpsp}}
|
||||
|
|
@ -162,17 +162,17 @@ func init() {
|
|||
gp21flags = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
|
||||
gp2flags1flags = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
|
||||
|
||||
gpload = regInfo{inputs: []regMask{ptrspsb, 0}, outputs: gponly}
|
||||
gploadidx = regInfo{inputs: []regMask{ptrspsb, ptrsp, 0}, outputs: gponly}
|
||||
gpopload = regInfo{inputs: []regMask{gp, ptrsp, 0}, outputs: gponly}
|
||||
gpstore = regInfo{inputs: []regMask{ptrspsb, gpsp, 0}}
|
||||
gpstoreconst = regInfo{inputs: []regMask{ptrspsb, 0}}
|
||||
gpstoreidx = regInfo{inputs: []regMask{ptrsp, ptrsp, gpsp, 0}}
|
||||
gpstorebr = regInfo{inputs: []regMask{ptrsp, gpsp, 0}}
|
||||
gpstorelaa = regInfo{inputs: []regMask{ptrspsb, gpsp, 0}, outputs: gponly}
|
||||
gpstorelab = regInfo{inputs: []regMask{r1, gpsp, 0}, clobbers: r1}
|
||||
gpload = regInfo{inputs: []regMask{ptrspsb, regMask{}}, outputs: gponly}
|
||||
gploadidx = regInfo{inputs: []regMask{ptrspsb, ptrsp, regMask{}}, outputs: gponly}
|
||||
gpopload = regInfo{inputs: []regMask{gp, ptrsp, regMask{}}, outputs: gponly}
|
||||
gpstore = regInfo{inputs: []regMask{ptrspsb, gpsp, regMask{}}}
|
||||
gpstoreconst = regInfo{inputs: []regMask{ptrspsb, regMask{}}}
|
||||
gpstoreidx = regInfo{inputs: []regMask{ptrsp, ptrsp, gpsp, regMask{}}}
|
||||
gpstorebr = regInfo{inputs: []regMask{ptrsp, gpsp, regMask{}}}
|
||||
gpstorelaa = regInfo{inputs: []regMask{ptrspsb, gpsp, regMask{}}, outputs: gponly}
|
||||
gpstorelab = regInfo{inputs: []regMask{r1, gpsp, regMask{}}, clobbers: r1}
|
||||
|
||||
gpmvc = regInfo{inputs: []regMask{ptrsp, ptrsp, 0}}
|
||||
gpmvc = regInfo{inputs: []regMask{ptrsp, ptrsp, regMask{}}}
|
||||
|
||||
fp01 = regInfo{inputs: []regMask{}, outputs: fponly}
|
||||
fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: fponly}
|
||||
|
|
@ -185,22 +185,22 @@ func init() {
|
|||
fp11clobber = regInfo{inputs: fponly, outputs: fponly}
|
||||
fp2flags = regInfo{inputs: []regMask{fp, fp}}
|
||||
|
||||
fpload = regInfo{inputs: []regMask{ptrspsb, 0}, outputs: fponly}
|
||||
fploadidx = regInfo{inputs: []regMask{ptrsp, ptrsp, 0}, outputs: fponly}
|
||||
fpload = regInfo{inputs: []regMask{ptrspsb, regMask{}}, outputs: fponly}
|
||||
fploadidx = regInfo{inputs: []regMask{ptrsp, ptrsp, regMask{}}, outputs: fponly}
|
||||
|
||||
fpstore = regInfo{inputs: []regMask{ptrspsb, fp, 0}}
|
||||
fpstoreidx = regInfo{inputs: []regMask{ptrsp, ptrsp, fp, 0}}
|
||||
fpstore = regInfo{inputs: []regMask{ptrspsb, fp, regMask{}}}
|
||||
fpstoreidx = regInfo{inputs: []regMask{ptrsp, ptrsp, fp, regMask{}}}
|
||||
|
||||
sync = regInfo{inputs: []regMask{0}}
|
||||
sync = regInfo{inputs: []regMask{regMask{}}}
|
||||
|
||||
// LoweredAtomicCas may overwrite arg1, so force it to R0 for now.
|
||||
cas = regInfo{inputs: []regMask{ptrsp, r0, gpsp, 0}, outputs: []regMask{gp, 0}, clobbers: r0}
|
||||
cas = regInfo{inputs: []regMask{ptrsp, r0, gpsp, regMask{}}, outputs: []regMask{gp, regMask{}}, clobbers: r0}
|
||||
|
||||
// LoweredAtomicExchange overwrites the output before executing
|
||||
// CS{,G}, so the output register must not be the same as the
|
||||
// input register. For now we just force the output register to
|
||||
// R0.
|
||||
exchange = regInfo{inputs: []regMask{ptrsp, gpsp &^ r0, 0}, outputs: []regMask{r0, 0}}
|
||||
exchange = regInfo{inputs: []regMask{ptrsp, gpsp.minus(r0), regMask{}}, outputs: []regMask{r0, regMask{}}}
|
||||
)
|
||||
|
||||
var S390Xops = []opData{
|
||||
|
|
@ -482,13 +482,13 @@ func init() {
|
|||
{name: "MOVWstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVW", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low 4 bytes of ...
|
||||
{name: "MOVDstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVD", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of ...
|
||||
|
||||
{name: "CLEAR", argLength: 2, reg: regInfo{inputs: []regMask{ptr, 0}}, asm: "CLEAR", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"},
|
||||
{name: "CLEAR", argLength: 2, reg: regInfo{inputs: []regMask{ptr, regMask{}}}, asm: "CLEAR", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"},
|
||||
|
||||
{name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: -1, reg: regInfo{inputs: []regMask{ptr}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{ptrsp, buildReg("R12"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{ptr}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLtailinter", argLength: -1, reg: regInfo{inputs: []regMask{ptr}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{ptrsp, buildReg("R12"), regMask{}}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{ptr}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
|
||||
|
||||
// (InvertFlags (CMP a b)) == (CMP b a)
|
||||
// InvertFlags is a pseudo-op which can't appear in assembly output.
|
||||
|
|
@ -518,17 +518,17 @@ func init() {
|
|||
// but clobbers R14 (LR) because it's a call,
|
||||
// and also clobbers R1 as the PLT stub does.
|
||||
// Returns a pointer to a write barrier buffer in R9.
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ gpg) | buildReg("R14") | r1, outputs: []regMask{r9}}, clobberFlags: true, aux: "Int64"},
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave.minus(gpg).union(buildReg("R14")).union(r1), outputs: []regMask{r9}}, clobberFlags: true, aux: "Int64"},
|
||||
|
||||
// LoweredPanicBoundsRR takes x and y, two values that caused a bounds check to fail.
|
||||
// the RC and CR versions are used when one of the arguments is a constant. CC is used
|
||||
// when both are constant (normally both 0, as prove derives the fact that a [0] bounds
|
||||
// failure means the length must have also been 0).
|
||||
// AuxInt contains a report code (see PanicBounds in genericOps.go).
|
||||
{name: "LoweredPanicBoundsRR", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{gp &^ lr, gp &^ lr}}, typ: "Mem", call: true}, // arg0=x, arg1=y, arg2=mem, returns memory.
|
||||
{name: "LoweredPanicBoundsRC", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{gp &^ lr}}, typ: "Mem", call: true}, // arg0=x, arg1=mem, returns memory.
|
||||
{name: "LoweredPanicBoundsCR", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{gp &^ lr}}, typ: "Mem", call: true}, // arg0=y, arg1=mem, returns memory.
|
||||
{name: "LoweredPanicBoundsCC", argLength: 1, aux: "PanicBoundsCC", reg: regInfo{}, typ: "Mem", call: true}, // arg0=mem, returns memory.
|
||||
{name: "LoweredPanicBoundsRR", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{gp.minus(lr), gp.minus(lr)}}, typ: "Mem", call: true}, // arg0=x, arg1=y, arg2=mem, returns memory.
|
||||
{name: "LoweredPanicBoundsRC", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{gp.minus(lr)}}, typ: "Mem", call: true}, // arg0=x, arg1=mem, returns memory.
|
||||
{name: "LoweredPanicBoundsCR", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{gp.minus(lr)}}, typ: "Mem", call: true}, // arg0=y, arg1=mem, returns memory.
|
||||
{name: "LoweredPanicBoundsCC", argLength: 1, aux: "PanicBoundsCC", reg: regInfo{}, typ: "Mem", call: true}, // arg0=mem, returns memory.
|
||||
|
||||
// Constant condition code values. The condition code can be 0, 1, 2 or 3.
|
||||
{name: "FlagEQ"}, // CC=0 (equal)
|
||||
|
|
@ -643,7 +643,7 @@ func init() {
|
|||
{
|
||||
name: "STMG2",
|
||||
argLength: 4,
|
||||
reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), 0}},
|
||||
reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), regMask{}}},
|
||||
aux: "SymOff",
|
||||
typ: "Mem",
|
||||
asm: "STMG",
|
||||
|
|
@ -654,7 +654,7 @@ func init() {
|
|||
{
|
||||
name: "STMG3",
|
||||
argLength: 5,
|
||||
reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), buildReg("R3"), 0}},
|
||||
reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), buildReg("R3"), regMask{}}},
|
||||
aux: "SymOff",
|
||||
typ: "Mem",
|
||||
asm: "STMG",
|
||||
|
|
@ -671,7 +671,7 @@ func init() {
|
|||
buildReg("R2"),
|
||||
buildReg("R3"),
|
||||
buildReg("R4"),
|
||||
0,
|
||||
regMask{},
|
||||
}},
|
||||
aux: "SymOff",
|
||||
typ: "Mem",
|
||||
|
|
@ -683,7 +683,7 @@ func init() {
|
|||
{
|
||||
name: "STM2",
|
||||
argLength: 4,
|
||||
reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), 0}},
|
||||
reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), regMask{}}},
|
||||
aux: "SymOff",
|
||||
typ: "Mem",
|
||||
asm: "STMY",
|
||||
|
|
@ -694,7 +694,7 @@ func init() {
|
|||
{
|
||||
name: "STM3",
|
||||
argLength: 5,
|
||||
reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), buildReg("R3"), 0}},
|
||||
reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), buildReg("R3"), regMask{}}},
|
||||
aux: "SymOff",
|
||||
typ: "Mem",
|
||||
asm: "STMY",
|
||||
|
|
@ -711,7 +711,7 @@ func init() {
|
|||
buildReg("R2"),
|
||||
buildReg("R3"),
|
||||
buildReg("R4"),
|
||||
0,
|
||||
regMask{},
|
||||
}},
|
||||
aux: "SymOff",
|
||||
typ: "Mem",
|
||||
|
|
|
|||
|
|
@ -75,10 +75,10 @@ func init() {
|
|||
num[name] = i
|
||||
}
|
||||
buildReg := func(s string) regMask {
|
||||
m := regMask(0)
|
||||
m := regMask{}
|
||||
for _, r := range strings.Split(s, " ") {
|
||||
if n, ok := num[r]; ok {
|
||||
m |= regMask(1) << uint(n)
|
||||
m = m.addReg(uint(n))
|
||||
continue
|
||||
}
|
||||
panic("register " + r + " not found")
|
||||
|
|
@ -90,11 +90,11 @@ func init() {
|
|||
gp = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15")
|
||||
fp32 = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15")
|
||||
fp64 = buildReg("F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31")
|
||||
gpsp = gp | buildReg("SP")
|
||||
gpspsb = gpsp | buildReg("SB")
|
||||
gpsp = gp.union(buildReg("SP"))
|
||||
gpspsb = gpsp.union(buildReg("SB"))
|
||||
// The "registers", which are actually local variables, can get clobbered
|
||||
// if we're switching goroutines, because it unwinds the WebAssembly stack.
|
||||
callerSave = gp | fp32 | fp64 | buildReg("g")
|
||||
callerSave = gp.union(fp32).union(fp64).union(buildReg("g"))
|
||||
)
|
||||
|
||||
// Common regInfo
|
||||
|
|
@ -111,19 +111,19 @@ func init() {
|
|||
fp64_11 = regInfo{inputs: []regMask{fp64}, outputs: []regMask{fp64}}
|
||||
fp64_21 = regInfo{inputs: []regMask{fp64, fp64}, outputs: []regMask{fp64}}
|
||||
fp64_21gp = regInfo{inputs: []regMask{fp64, fp64}, outputs: []regMask{gp}}
|
||||
gpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: []regMask{gp}}
|
||||
gpstore = regInfo{inputs: []regMask{gpspsb, gpsp, 0}}
|
||||
fp32load = regInfo{inputs: []regMask{gpspsb, 0}, outputs: []regMask{fp32}}
|
||||
fp32store = regInfo{inputs: []regMask{gpspsb, fp32, 0}}
|
||||
fp64load = regInfo{inputs: []regMask{gpspsb, 0}, outputs: []regMask{fp64}}
|
||||
fp64store = regInfo{inputs: []regMask{gpspsb, fp64, 0}}
|
||||
gpload = regInfo{inputs: []regMask{gpspsb, regMask{}}, outputs: []regMask{gp}}
|
||||
gpstore = regInfo{inputs: []regMask{gpspsb, gpsp, regMask{}}}
|
||||
fp32load = regInfo{inputs: []regMask{gpspsb, regMask{}}, outputs: []regMask{fp32}}
|
||||
fp32store = regInfo{inputs: []regMask{gpspsb, fp32, regMask{}}}
|
||||
fp64load = regInfo{inputs: []regMask{gpspsb, regMask{}}, outputs: []regMask{fp64}}
|
||||
fp64store = regInfo{inputs: []regMask{gpspsb, fp64, regMask{}}}
|
||||
)
|
||||
|
||||
var WasmOps = []opData{
|
||||
{name: "LoweredStaticCall", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "LoweredTailCall", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "LoweredTailCallInter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", call: true, tailCall: true}, // tail call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
{name: "LoweredClosureCall", argLength: 3, reg: regInfo{inputs: []regMask{gp, gp, 0}, clobbers: callerSave}, aux: "CallOff", call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
|
||||
{name: "LoweredClosureCall", argLength: 3, reg: regInfo{inputs: []regMask{gp, gp, regMask{}}, clobbers: callerSave}, aux: "CallOff", call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
|
||||
{name: "LoweredInterCall", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
|
||||
{name: "LoweredAddr", argLength: 1, reg: gp11, aux: "SymOff", rematerializeable: true, symEffect: "Addr"}, // returns base+aux+auxint, arg0=base
|
||||
|
|
@ -269,7 +269,7 @@ func init() {
|
|||
blocks: nil,
|
||||
regnames: regNamesWasm,
|
||||
gpregmask: gp,
|
||||
fpregmask: fp32 | fp64,
|
||||
fpregmask: fp32.union(fp64),
|
||||
fp32regmask: fp32,
|
||||
fp64regmask: fp64,
|
||||
framepointerreg: -1, // not used
|
||||
|
|
|
|||
|
|
@ -96,19 +96,53 @@ type regInfo struct {
|
|||
outputs []regMask
|
||||
}
|
||||
|
||||
type regMask uint64
|
||||
type regMask struct {
|
||||
v1, v2 uint64
|
||||
}
|
||||
|
||||
func regMaskAt(i uint) regMask {
|
||||
if i < 64 {
|
||||
return regMask{v1: 1 << i}
|
||||
}
|
||||
return regMask{v2: 1 << (i - 64)}
|
||||
}
|
||||
|
||||
func (r regMask) empty() bool {
|
||||
return r.v1 == 0 && r.v2 == 0
|
||||
}
|
||||
|
||||
func (r regMask) hasReg(i uint) bool {
|
||||
if i < 64 {
|
||||
return (r.v1>>i)&1 != 0
|
||||
}
|
||||
return (r.v2>>(i-64))&1 != 0
|
||||
}
|
||||
|
||||
func (r regMask) addReg(i uint) regMask {
|
||||
if i < 64 {
|
||||
return regMask{r.v1 | 1<<i, r.v2}
|
||||
}
|
||||
return regMask{r.v1, r.v2 | 1<<(i-64)}
|
||||
}
|
||||
|
||||
func (r regMask) union(s regMask) regMask {
|
||||
return regMask{r.v1 | s.v1, r.v2 | s.v2}
|
||||
}
|
||||
|
||||
func (r regMask) minus(s regMask) regMask {
|
||||
return regMask{r.v1 &^ s.v1, r.v2 &^ s.v2}
|
||||
}
|
||||
|
||||
func (a arch) regMaskComment(r regMask) string {
|
||||
var buf strings.Builder
|
||||
for i := uint64(0); r != 0; i++ {
|
||||
if r&1 != 0 {
|
||||
for i := uint(0); i < uint(len(a.regnames)); i++ {
|
||||
if r.hasReg(i) {
|
||||
if buf.Len() == 0 {
|
||||
buf.WriteString(" //")
|
||||
}
|
||||
buf.WriteString(" ")
|
||||
buf.WriteString(a.regnames[i])
|
||||
}
|
||||
r >>= 1
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
|
@ -297,7 +331,7 @@ func genOp() {
|
|||
fmt.Fprintf(w, "argLen: %d,\n", v.argLength)
|
||||
|
||||
if v.rematerializeable {
|
||||
if v.reg.clobbers != 0 || v.reg.clobbersArg0 || v.reg.clobbersArg1 {
|
||||
if !v.reg.clobbers.empty() || v.reg.clobbersArg0 || v.reg.clobbersArg1 {
|
||||
log.Fatalf("%s is rematerializeable and clobbers registers", v.name)
|
||||
}
|
||||
if v.clobberFlags {
|
||||
|
|
@ -389,7 +423,7 @@ func genOp() {
|
|||
// that we will always be able to find a register.
|
||||
var s []intPair
|
||||
for i, r := range v.reg.inputs {
|
||||
if r != 0 {
|
||||
if !r.empty() {
|
||||
s = append(s, intPair{countRegs(r), i})
|
||||
}
|
||||
}
|
||||
|
|
@ -398,13 +432,13 @@ func genOp() {
|
|||
fmt.Fprintln(w, "inputs: []inputInfo{")
|
||||
for _, p := range s {
|
||||
r := v.reg.inputs[p.val]
|
||||
fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r))
|
||||
fmt.Fprintf(w, "{%d,regMask{v1: %d, v2: %d}},%s\n", p.val, r.v1, r.v2, a.regMaskComment(r))
|
||||
}
|
||||
fmt.Fprintln(w, "},")
|
||||
}
|
||||
|
||||
if v.reg.clobbers > 0 {
|
||||
fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers))
|
||||
if !v.reg.clobbers.empty() {
|
||||
fmt.Fprintf(w, "clobbers: regMask{v1: %d, v2: %d},%s\n", v.reg.clobbers.v1, v.reg.clobbers.v2, a.regMaskComment(v.reg.clobbers))
|
||||
}
|
||||
if v.reg.clobbersArg0 {
|
||||
fmt.Fprintf(w, "clobbersArg0: true,\n")
|
||||
|
|
@ -423,7 +457,7 @@ func genOp() {
|
|||
fmt.Fprintln(w, "outputs: []outputInfo{")
|
||||
for _, p := range s {
|
||||
r := v.reg.outputs[p.val]
|
||||
fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r))
|
||||
fmt.Fprintf(w, "{%d,regMask{v1: %d, v2: %d}},%s\n", p.val, r.v1, r.v2, a.regMaskComment(r))
|
||||
}
|
||||
fmt.Fprintln(w, "},")
|
||||
}
|
||||
|
|
@ -500,15 +534,15 @@ func genOp() {
|
|||
fmt.Fprintln(w, "}")
|
||||
fmt.Fprintf(w, "var paramIntReg%s = %#v\n", a.name, paramIntRegs)
|
||||
fmt.Fprintf(w, "var paramFloatReg%s = %#v\n", a.name, paramFloatRegs)
|
||||
fmt.Fprintf(w, "var gpRegMask%s = regMask(%d)\n", a.name, a.gpregmask)
|
||||
fmt.Fprintf(w, "var fpRegMask%s = regMask(%d)\n", a.name, a.fpregmask)
|
||||
if a.fp32regmask != 0 {
|
||||
fmt.Fprintf(w, "var fp32RegMask%s = regMask(%d)\n", a.name, a.fp32regmask)
|
||||
fmt.Fprintf(w, "var gpRegMask%s = regMask{v1: %d, v2: %d}\n", a.name, a.gpregmask.v1, a.gpregmask.v2)
|
||||
fmt.Fprintf(w, "var fpRegMask%s = regMask{v1: %d, v2: %d}\n", a.name, a.fpregmask.v1, a.fpregmask.v2)
|
||||
if !a.fp32regmask.empty() {
|
||||
fmt.Fprintf(w, "var fp32RegMask%s = regMask{v1: %d, v2: %d}\n", a.name, a.fp32regmask.v1, a.fp32regmask.v2)
|
||||
}
|
||||
if a.fp64regmask != 0 {
|
||||
fmt.Fprintf(w, "var fp64RegMask%s = regMask(%d)\n", a.name, a.fp64regmask)
|
||||
if !a.fp64regmask.empty() {
|
||||
fmt.Fprintf(w, "var fp64RegMask%s = regMask{v1: %d, v2: %d}\n", a.name, a.fp64regmask.v1, a.fp64regmask.v2)
|
||||
}
|
||||
fmt.Fprintf(w, "var specialRegMask%s = regMask(%d)\n", a.name, a.specialregmask)
|
||||
fmt.Fprintf(w, "var specialRegMask%s = regMask{v1: %d, v2: %d}\n", a.name, a.specialregmask.v1, a.specialregmask.v2)
|
||||
fmt.Fprintf(w, "var framepointerReg%s = int8(%d)\n", a.name, a.framepointerreg)
|
||||
fmt.Fprintf(w, "var linkReg%s = int8(%d)\n", a.name, a.linkreg)
|
||||
}
|
||||
|
|
@ -579,7 +613,7 @@ func (a arch) Name() string {
|
|||
|
||||
// countRegs returns the number of set bits in the register mask.
|
||||
func countRegs(r regMask) int {
|
||||
return bits.OnesCount64(uint64(r))
|
||||
return bits.OnesCount64(r.v1) + bits.OnesCount64(r.v2)
|
||||
}
|
||||
|
||||
// for sorting a pair of integers by key
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize, softfloat boo
|
|||
// LoweredWB is secretly a CALL and CALLs on 386 in
|
||||
// shared mode get rewritten by obj6.go to go through
|
||||
// the GOT, which clobbers BX.
|
||||
opcodeTable[Op386LoweredWB].reg.clobbers |= 1 << 3 // BX
|
||||
opcodeTable[Op386LoweredWB].reg.clobbers = opcodeTable[Op386LoweredWB].reg.clobbers.addReg(3) // BX
|
||||
}
|
||||
|
||||
c.buildRecipes(arch)
|
||||
|
|
|
|||
|
|
@ -1051,13 +1051,13 @@ func (state *debugState) processValue(v *Value, vSlots []SlotID, vReg *Register)
|
|||
// Handle any register clobbering. Call operations, for example,
|
||||
// clobber all registers even though they don't explicitly write to
|
||||
// them.
|
||||
clobbers := uint64(opcodeTable[v.Op].reg.clobbers)
|
||||
clobbers := opcodeTable[v.Op].reg.clobbers
|
||||
for {
|
||||
if clobbers == 0 {
|
||||
if clobbers.empty() {
|
||||
break
|
||||
}
|
||||
reg := uint8(bits.TrailingZeros64(clobbers))
|
||||
clobbers &^= 1 << reg
|
||||
reg := pickReg(clobbers)
|
||||
clobbers = clobbers.removeReg(reg)
|
||||
|
||||
for _, slot := range locs.registers[reg] {
|
||||
if state.loggingLevel > 1 {
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ type AuxCall struct {
|
|||
// At this point (active development of register ABI) that is very premature,
|
||||
// but if this turns out to be a cost, we could do it.
|
||||
func (a *AuxCall) Reg(i *regInfo, c *Config) *regInfo {
|
||||
if a.reg.clobbers != 0 {
|
||||
if !a.reg.clobbers.empty() {
|
||||
// Already updated
|
||||
return a.reg
|
||||
}
|
||||
|
|
@ -146,7 +146,7 @@ func (a *AuxCall) Reg(i *regInfo, c *Config) *regInfo {
|
|||
for _, p := range a.abiInfo.InParams() {
|
||||
for _, r := range p.Registers {
|
||||
m := archRegForAbiReg(r, c)
|
||||
a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: (1 << m)})
|
||||
a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: regMaskAt(register(m))})
|
||||
k++
|
||||
}
|
||||
}
|
||||
|
|
@ -155,7 +155,7 @@ func (a *AuxCall) Reg(i *regInfo, c *Config) *regInfo {
|
|||
for _, p := range a.abiInfo.OutParams() {
|
||||
for _, r := range p.Registers {
|
||||
m := archRegForAbiReg(r, c)
|
||||
a.reg.outputs = append(a.reg.outputs, outputInfo{idx: k, regs: (1 << m)})
|
||||
a.reg.outputs = append(a.reg.outputs, outputInfo{idx: k, regs: regMaskAt(register(m))})
|
||||
k++
|
||||
}
|
||||
}
|
||||
|
|
@ -180,7 +180,7 @@ func (a *AuxCall) ResultReg(c *Config) *regInfo {
|
|||
for _, p := range a.abiInfo.OutParams() {
|
||||
for _, r := range p.Registers {
|
||||
m := archRegForAbiReg(r, c)
|
||||
a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: (1 << m)})
|
||||
a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: regMaskAt(register(m))})
|
||||
k++
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -165,16 +165,61 @@ var noRegisters [32]register = [32]register{
|
|||
}
|
||||
|
||||
// A regMask encodes a set of machine registers.
|
||||
// TODO: regMask -> regSet?
|
||||
type regMask uint64
|
||||
type regMask struct {
|
||||
v1, v2 uint64
|
||||
}
|
||||
|
||||
func (r regMask) intersect(s regMask) regMask {
|
||||
return regMask{r.v1 & s.v1, r.v2 & s.v2}
|
||||
}
|
||||
|
||||
func (r regMask) union(s regMask) regMask {
|
||||
return regMask{r.v1 | s.v1, r.v2 | s.v2}
|
||||
}
|
||||
|
||||
func (r regMask) minus(s regMask) regMask {
|
||||
return regMask{r.v1 &^ s.v1, r.v2 &^ s.v2}
|
||||
}
|
||||
|
||||
func (r regMask) empty() bool {
|
||||
return r.v1 == 0 && r.v2 == 0
|
||||
}
|
||||
|
||||
func regMaskAt(i register) regMask {
|
||||
if i < 64 {
|
||||
return regMask{v1: 1 << i}
|
||||
}
|
||||
return regMask{v2: 1 << (i - 64)}
|
||||
}
|
||||
|
||||
func (r regMask) addReg(i register) regMask {
|
||||
if i < 64 {
|
||||
return regMask{r.v1 | 1<<i, r.v2}
|
||||
}
|
||||
return regMask{r.v1, r.v2 | 1<<(i-64)}
|
||||
}
|
||||
|
||||
func (r regMask) removeReg(i register) regMask {
|
||||
if i < 64 {
|
||||
return regMask{r.v1 &^ (1 << i), r.v2}
|
||||
}
|
||||
return regMask{r.v1, r.v2 &^ (1 << (i - 64))}
|
||||
}
|
||||
|
||||
func (r regMask) hasReg(i register) bool {
|
||||
if i < 64 {
|
||||
return (r.v1>>i)&1 != 0
|
||||
}
|
||||
return (r.v2>>(i-64))&1 != 0
|
||||
}
|
||||
|
||||
func (m regMask) String() string {
|
||||
s := ""
|
||||
for r := register(0); m != 0; r++ {
|
||||
if m>>r&1 == 0 {
|
||||
for r := register(0); !m.empty(); r++ {
|
||||
if !m.hasReg(r) {
|
||||
continue
|
||||
}
|
||||
m &^= regMask(1) << r
|
||||
m = m.removeReg(r)
|
||||
if s != "" {
|
||||
s += " "
|
||||
}
|
||||
|
|
@ -183,17 +228,13 @@ func (m regMask) String() string {
|
|||
return s
|
||||
}
|
||||
|
||||
func (m regMask) contains(r register) bool {
|
||||
return m>>r&1 != 0
|
||||
}
|
||||
|
||||
func (s *regAllocState) RegMaskString(m regMask) string {
|
||||
str := ""
|
||||
for r := register(0); m != 0; r++ {
|
||||
if m>>r&1 == 0 {
|
||||
for r := register(0); !m.empty(); r++ {
|
||||
if !m.hasReg(r) {
|
||||
continue
|
||||
}
|
||||
m &^= regMask(1) << r
|
||||
m = m.removeReg(r)
|
||||
if str != "" {
|
||||
str += " "
|
||||
}
|
||||
|
|
@ -204,16 +245,19 @@ func (s *regAllocState) RegMaskString(m regMask) string {
|
|||
|
||||
// countRegs returns the number of set bits in the register mask.
|
||||
func countRegs(r regMask) int {
|
||||
return bits.OnesCount64(uint64(r))
|
||||
return bits.OnesCount64(r.v1) + bits.OnesCount64(r.v2)
|
||||
}
|
||||
|
||||
// pickReg picks an arbitrary register from the register mask.
|
||||
func pickReg(r regMask) register {
|
||||
if r == 0 {
|
||||
if r.empty() {
|
||||
panic("can't pick a register from an empty set")
|
||||
}
|
||||
// pick the lowest one
|
||||
return register(bits.TrailingZeros64(uint64(r)))
|
||||
if r.v1 != 0 {
|
||||
return register(bits.TrailingZeros64(r.v1))
|
||||
}
|
||||
return register(bits.TrailingZeros64(r.v2) + 64)
|
||||
}
|
||||
|
||||
type use struct {
|
||||
|
|
@ -356,7 +400,7 @@ type startReg struct {
|
|||
|
||||
// freeReg frees up register r. Any current user of r is kicked out.
|
||||
func (s *regAllocState) freeReg(r register) {
|
||||
if !s.allocatable.contains(r) && !s.isGReg(r) {
|
||||
if !s.allocatable.hasReg(r) && !s.isGReg(r) {
|
||||
return
|
||||
}
|
||||
v := s.regs[r].v
|
||||
|
|
@ -369,23 +413,23 @@ func (s *regAllocState) freeReg(r register) {
|
|||
fmt.Printf("freeReg %s (dump %s/%s)\n", &s.registers[r], v, s.regs[r].c)
|
||||
}
|
||||
s.regs[r] = regState{}
|
||||
s.values[v.ID].regs &^= regMask(1) << r
|
||||
s.used &^= regMask(1) << r
|
||||
s.values[v.ID].regs = s.values[v.ID].regs.removeReg(r)
|
||||
s.used = s.used.removeReg(r)
|
||||
}
|
||||
|
||||
// freeRegs frees up all registers listed in m.
|
||||
func (s *regAllocState) freeRegs(m regMask) {
|
||||
for m&s.used != 0 {
|
||||
s.freeReg(pickReg(m & s.used))
|
||||
for !m.intersect(s.used).empty() {
|
||||
s.freeReg(pickReg(m.intersect(s.used)))
|
||||
}
|
||||
}
|
||||
|
||||
// clobberRegs inserts instructions that clobber registers listed in m.
|
||||
func (s *regAllocState) clobberRegs(m regMask) {
|
||||
m &= s.allocatable & s.f.Config.gpRegMask // only integer register can contain pointers, only clobber them
|
||||
for m != 0 {
|
||||
m = m.intersect(s.allocatable.intersect(s.f.Config.gpRegMask)) // only integer register can contain pointers, only clobber them
|
||||
for !m.empty() {
|
||||
r := pickReg(m)
|
||||
m &^= 1 << r
|
||||
m = m.removeReg(r)
|
||||
x := s.curBlock.NewValue0(src.NoXPos, OpClobberReg, types.TypeVoid)
|
||||
s.f.setHome(x, &s.registers[r])
|
||||
}
|
||||
|
|
@ -416,18 +460,18 @@ func (s *regAllocState) assignReg(r register, v *Value, c *Value) {
|
|||
fmt.Printf("assignReg %s %s/%s\n", &s.registers[r], v, c)
|
||||
}
|
||||
// Allocate v to r.
|
||||
s.values[v.ID].regs |= regMask(1) << r
|
||||
s.values[v.ID].regs = s.values[v.ID].regs.addReg(r)
|
||||
s.f.setHome(c, &s.registers[r])
|
||||
|
||||
// Allocate r to v.
|
||||
if !s.allocatable.contains(r) && !s.isGReg(r) {
|
||||
if !s.allocatable.hasReg(r) && !s.isGReg(r) {
|
||||
return
|
||||
}
|
||||
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)
|
||||
}
|
||||
s.regs[r] = regState{v, c}
|
||||
s.used |= regMask(1) << r
|
||||
s.used = s.used.addReg(r)
|
||||
}
|
||||
|
||||
// allocReg chooses a register from the set of registers in mask.
|
||||
|
|
@ -438,16 +482,16 @@ func (s *regAllocState) allocReg(mask regMask, v *Value) register {
|
|||
return noRegister
|
||||
}
|
||||
|
||||
mask &= s.allocatable
|
||||
mask &^= s.nospill
|
||||
if mask == 0 {
|
||||
mask = mask.intersect(s.allocatable)
|
||||
mask = mask.minus(s.nospill)
|
||||
if mask.empty() {
|
||||
s.f.Fatalf("no register available for %s", v.LongString())
|
||||
}
|
||||
|
||||
// Pick an unused register if one is available.
|
||||
if mask&^s.used != 0 {
|
||||
r := pickReg(mask &^ s.used)
|
||||
s.usedSinceBlockStart |= regMask(1) << r
|
||||
if !mask.minus(s.used).empty() {
|
||||
r := pickReg(mask.minus(s.used))
|
||||
s.usedSinceBlockStart = s.usedSinceBlockStart.addReg(r)
|
||||
return r
|
||||
}
|
||||
|
||||
|
|
@ -464,7 +508,7 @@ func (s *regAllocState) allocReg(mask regMask, v *Value) register {
|
|||
var r register
|
||||
maxuse := int32(-1)
|
||||
for t := register(0); t < s.numRegs; t++ {
|
||||
if mask>>t&1 == 0 {
|
||||
if !mask.hasReg(t) {
|
||||
continue
|
||||
}
|
||||
v := s.regs[t].v
|
||||
|
|
@ -490,9 +534,9 @@ func (s *regAllocState) allocReg(mask regMask, v *Value) register {
|
|||
// Try to move it around before kicking out, if there is a free register.
|
||||
// We generate a Copy and record it. It will be deleted if never used.
|
||||
v2 := s.regs[r].v
|
||||
m := s.compatRegs(v2.Type) &^ s.used &^ s.tmpused &^ (regMask(1) << r)
|
||||
if m != 0 && !s.values[v2.ID].rematerializeable && countRegs(s.values[v2.ID].regs) == 1 {
|
||||
s.usedSinceBlockStart |= regMask(1) << r
|
||||
m := s.compatRegs(v2.Type).minus(s.used).minus(s.tmpused).removeReg(r)
|
||||
if !m.empty() && !s.values[v2.ID].rematerializeable && countRegs(s.values[v2.ID].regs) == 1 {
|
||||
s.usedSinceBlockStart = s.usedSinceBlockStart.addReg(r)
|
||||
r2 := pickReg(m)
|
||||
c := s.curBlock.NewValue1(v2.Pos, OpCopy, v2.Type, s.regs[r].c)
|
||||
s.copies[c] = false
|
||||
|
|
@ -506,17 +550,17 @@ func (s *regAllocState) allocReg(mask regMask, v *Value) register {
|
|||
// If the evicted register isn't used between the start of the block
|
||||
// and now then there is no reason to even request it on entry. We can
|
||||
// drop from startRegs in that case.
|
||||
if s.usedSinceBlockStart&(regMask(1)<<r) == 0 {
|
||||
if s.startRegsMask&(regMask(1)<<r) != 0 {
|
||||
if !s.usedSinceBlockStart.hasReg(r) {
|
||||
if s.startRegsMask.hasReg(r) {
|
||||
if s.f.pass.debug > regDebug {
|
||||
fmt.Printf("dropped from startRegs: %s\n", &s.registers[r])
|
||||
}
|
||||
s.startRegsMask &^= regMask(1) << r
|
||||
s.startRegsMask = s.startRegsMask.removeReg(r)
|
||||
}
|
||||
}
|
||||
|
||||
s.freeReg(r)
|
||||
s.usedSinceBlockStart |= regMask(1) << r
|
||||
s.usedSinceBlockStart = s.usedSinceBlockStart.addReg(r)
|
||||
return r
|
||||
}
|
||||
|
||||
|
|
@ -562,25 +606,25 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos
|
|||
vi := &s.values[v.ID]
|
||||
pos = pos.WithNotStmt()
|
||||
// Check if v is already in a requested register.
|
||||
if mask&vi.regs != 0 {
|
||||
mask &= vi.regs
|
||||
if !mask.intersect(vi.regs).empty() {
|
||||
mask = mask.intersect(vi.regs)
|
||||
r := pickReg(mask)
|
||||
if mask.contains(s.SPReg) {
|
||||
if mask.hasReg(s.SPReg) {
|
||||
// Prefer the stack pointer if it is allowed.
|
||||
// (Needed because the op might have an Aux symbol
|
||||
// that needs SP as its base.)
|
||||
r = s.SPReg
|
||||
}
|
||||
if !s.allocatable.contains(r) {
|
||||
if !s.allocatable.hasReg(r) {
|
||||
return v // v is in a fixed register
|
||||
}
|
||||
if s.regs[r].v != v || s.regs[r].c == nil {
|
||||
panic("bad register state")
|
||||
}
|
||||
if nospill {
|
||||
s.nospill |= regMask(1) << r
|
||||
s.nospill = s.nospill.addReg(r)
|
||||
}
|
||||
s.usedSinceBlockStart |= regMask(1) << r
|
||||
s.usedSinceBlockStart = s.usedSinceBlockStart.addReg(r)
|
||||
return s.regs[r].c
|
||||
}
|
||||
|
||||
|
|
@ -594,10 +638,10 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos
|
|||
|
||||
// Allocate v to the new register.
|
||||
var c *Value
|
||||
if vi.regs != 0 {
|
||||
if !vi.regs.empty() {
|
||||
// Copy from a register that v is already in.
|
||||
var current *Value
|
||||
if vi.regs&^s.allocatable != 0 {
|
||||
if !vi.regs.minus(s.allocatable).empty() {
|
||||
// v is in a fixed register, prefer that
|
||||
current = v
|
||||
} else {
|
||||
|
|
@ -606,7 +650,7 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos
|
|||
panic("bad register state")
|
||||
}
|
||||
current = s.regs[r2].c
|
||||
s.usedSinceBlockStart |= regMask(1) << r2
|
||||
s.usedSinceBlockStart = s.usedSinceBlockStart.addReg(r2)
|
||||
}
|
||||
c = s.curBlock.NewValue1(pos, OpCopy, v.Type, current)
|
||||
} else if v.rematerializeable() {
|
||||
|
|
@ -620,7 +664,7 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos
|
|||
// Because GP and FP masks do not overlap, mask & outputMask == 0
|
||||
// detects this situation thoroughly.
|
||||
sourceMask := s.regspec(c).outputs[0].regs
|
||||
if mask&sourceMask == 0 && !onWasmStack {
|
||||
if mask.intersect(sourceMask).empty() && !onWasmStack {
|
||||
s.setOrig(c, v)
|
||||
s.assignReg(s.allocReg(sourceMask, v), v, c)
|
||||
// v.Type for the new OpCopy is likely wrong and it might delay the problem
|
||||
|
|
@ -656,7 +700,7 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos
|
|||
s.f.Fatalf("allocValToReg.OpLoadReg targeting g: " + c.LongString())
|
||||
}
|
||||
if nospill {
|
||||
s.nospill |= regMask(1) << r
|
||||
s.nospill = s.nospill.addReg(r)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
|
@ -683,7 +727,7 @@ func (s *regAllocState) init(f *Func) {
|
|||
s.f = f
|
||||
s.f.RegAlloc = s.f.Cache.locs[:0]
|
||||
s.registers = f.Config.registers
|
||||
if nr := len(s.registers); nr == 0 || nr > int(noRegister) || nr > int(unsafe.Sizeof(regMask(0))*8) {
|
||||
if nr := len(s.registers); nr == 0 || nr > int(noRegister) || nr > int(unsafe.Sizeof(regMask{})*8) {
|
||||
s.f.Fatalf("bad number of registers: %d", nr)
|
||||
} else {
|
||||
s.numRegs = register(nr)
|
||||
|
|
@ -718,22 +762,22 @@ func (s *regAllocState) init(f *Func) {
|
|||
}
|
||||
|
||||
// Figure out which registers we're allowed to use.
|
||||
s.allocatable = s.f.Config.gpRegMask | s.f.Config.fpRegMask | s.f.Config.specialRegMask
|
||||
s.allocatable &^= 1 << s.SPReg
|
||||
s.allocatable &^= 1 << s.SBReg
|
||||
s.allocatable = s.f.Config.gpRegMask.union(s.f.Config.fpRegMask).union(s.f.Config.specialRegMask)
|
||||
s.allocatable = s.allocatable.removeReg(s.SPReg)
|
||||
s.allocatable = s.allocatable.removeReg(s.SBReg)
|
||||
if s.f.Config.hasGReg {
|
||||
s.allocatable &^= 1 << s.GReg
|
||||
s.allocatable = s.allocatable.removeReg(s.GReg)
|
||||
}
|
||||
if s.ZeroIntReg != noRegister {
|
||||
s.allocatable &^= 1 << s.ZeroIntReg
|
||||
s.allocatable = s.allocatable.removeReg(s.ZeroIntReg)
|
||||
}
|
||||
if buildcfg.FramePointerEnabled && s.f.Config.FPReg >= 0 {
|
||||
s.allocatable &^= 1 << uint(s.f.Config.FPReg)
|
||||
s.allocatable = s.allocatable.removeReg(register(s.f.Config.FPReg))
|
||||
}
|
||||
if s.f.Config.LinkReg != -1 {
|
||||
if isLeaf(f) {
|
||||
// Leaf functions don't save/restore the link register.
|
||||
s.allocatable &^= 1 << uint(s.f.Config.LinkReg)
|
||||
s.allocatable = s.allocatable.removeReg(register(s.f.Config.LinkReg))
|
||||
}
|
||||
}
|
||||
if s.f.Config.ctxt.Flag_dynlink {
|
||||
|
|
@ -745,9 +789,9 @@ func (s *regAllocState) init(f *Func) {
|
|||
// in the rewrite rules so we always have a free register
|
||||
// available for global load/stores. See _gen/386.rules (search for Flag_shared).
|
||||
case "amd64":
|
||||
s.allocatable &^= 1 << 15 // R15
|
||||
s.allocatable = s.allocatable.removeReg(15) // R15
|
||||
case "arm":
|
||||
s.allocatable &^= 1 << 9 // R9
|
||||
s.allocatable = s.allocatable.removeReg(9) // R9
|
||||
case "arm64":
|
||||
// nothing to do
|
||||
case "loong64": // R2 (aka TP) already reserved.
|
||||
|
|
@ -757,7 +801,7 @@ func (s *regAllocState) init(f *Func) {
|
|||
case "riscv64": // X3 (aka GP) and X4 (aka TP) already reserved.
|
||||
// nothing to do
|
||||
case "s390x":
|
||||
s.allocatable &^= 1 << 11 // R11
|
||||
s.allocatable = s.allocatable.removeReg(11) // R11
|
||||
default:
|
||||
s.f.fe.Fatalf(src.NoXPos, "arch %s not implemented", s.f.Config.arch)
|
||||
}
|
||||
|
|
@ -937,20 +981,20 @@ func (s *regAllocState) setState(regs []endReg) {
|
|||
func (s *regAllocState) compatRegs(t *types.Type) regMask {
|
||||
var m regMask
|
||||
if t.IsTuple() || t.IsFlags() {
|
||||
return 0
|
||||
return regMask{}
|
||||
}
|
||||
if t.IsSIMD() {
|
||||
if t.Size() > 8 {
|
||||
return s.f.Config.fpRegMask & s.allocatable
|
||||
return s.f.Config.fpRegMask.intersect(s.allocatable)
|
||||
} else {
|
||||
// K mask
|
||||
return s.f.Config.gpRegMask & s.allocatable
|
||||
return s.f.Config.gpRegMask.intersect(s.allocatable)
|
||||
}
|
||||
}
|
||||
if t.IsFloat() || t == types.TypeInt128 {
|
||||
if t.Kind() == types.TFLOAT32 && s.f.Config.fp32RegMask != 0 {
|
||||
if t.Kind() == types.TFLOAT32 && !s.f.Config.fp32RegMask.empty() {
|
||||
m = s.f.Config.fp32RegMask
|
||||
} else if t.Kind() == types.TFLOAT64 && s.f.Config.fp64RegMask != 0 {
|
||||
} else if t.Kind() == types.TFLOAT64 && !s.f.Config.fp64RegMask.empty() {
|
||||
m = s.f.Config.fp64RegMask
|
||||
} else {
|
||||
m = s.f.Config.fpRegMask
|
||||
|
|
@ -958,7 +1002,7 @@ func (s *regAllocState) compatRegs(t *types.Type) regMask {
|
|||
} else {
|
||||
m = s.f.Config.gpRegMask
|
||||
}
|
||||
return m & s.allocatable
|
||||
return m.intersect(s.allocatable)
|
||||
}
|
||||
|
||||
// regspec returns the regInfo for operation op.
|
||||
|
|
@ -968,16 +1012,16 @@ func (s *regAllocState) regspec(v *Value) regInfo {
|
|||
// OpConvert is a generic op, so it doesn't have a
|
||||
// register set in the static table. It can use any
|
||||
// allocatable integer register.
|
||||
m := s.allocatable & s.f.Config.gpRegMask
|
||||
m := s.allocatable.intersect(s.f.Config.gpRegMask)
|
||||
return regInfo{inputs: []inputInfo{{regs: m}}, outputs: []outputInfo{{regs: m}}}
|
||||
}
|
||||
if op == OpArgIntReg {
|
||||
reg := v.Block.Func.Config.intParamRegs[v.AuxInt8()]
|
||||
return regInfo{outputs: []outputInfo{{regs: 1 << uint(reg)}}}
|
||||
return regInfo{outputs: []outputInfo{{regs: regMaskAt(register(reg))}}}
|
||||
}
|
||||
if op == OpArgFloatReg {
|
||||
reg := v.Block.Func.Config.floatParamRegs[v.AuxInt8()]
|
||||
return regInfo{outputs: []outputInfo{{regs: 1 << uint(reg)}}}
|
||||
return regInfo{outputs: []outputInfo{{regs: regMaskAt(register(reg))}}}
|
||||
}
|
||||
if op.IsCall() {
|
||||
if ac, ok := v.Aux.(*AuxCall); ok && ac.reg != nil {
|
||||
|
|
@ -1025,8 +1069,8 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
fmt.Printf("Begin processing block %v\n", b)
|
||||
}
|
||||
s.curBlock = b
|
||||
s.startRegsMask = 0
|
||||
s.usedSinceBlockStart = 0
|
||||
s.startRegsMask = regMask{}
|
||||
s.usedSinceBlockStart = regMask{}
|
||||
clear(desiredSecondReg)
|
||||
|
||||
// Initialize regValLiveSet and uses fields for this block.
|
||||
|
|
@ -1205,10 +1249,10 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
a := v.Args[idx]
|
||||
// Some instructions target not-allocatable registers.
|
||||
// They're not suitable for further (phi-function) allocation.
|
||||
m := s.values[a.ID].regs &^ phiUsed & s.allocatable
|
||||
if m != 0 {
|
||||
m := s.values[a.ID].regs.minus(phiUsed).intersect(s.allocatable)
|
||||
if !m.empty() {
|
||||
r := pickReg(m)
|
||||
phiUsed |= regMask(1) << r
|
||||
phiUsed = phiUsed.addReg(r)
|
||||
phiRegs = append(phiRegs, r)
|
||||
} else {
|
||||
phiRegs = append(phiRegs, noRegister)
|
||||
|
|
@ -1234,8 +1278,8 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
// Pick a free register. At this point some registers used in the predecessor
|
||||
// block may have been deallocated. Those are the ones used for Phis. Exclude
|
||||
// them (and they are not going to be helpful anyway).
|
||||
m := s.compatRegs(a.Type) &^ s.used &^ phiUsed
|
||||
if m != 0 && !s.values[a.ID].rematerializeable && countRegs(s.values[a.ID].regs) == 1 {
|
||||
m := s.compatRegs(a.Type).minus(s.used).minus(phiUsed)
|
||||
if !m.empty() && !s.values[a.ID].rematerializeable && countRegs(s.values[a.ID].regs) == 1 {
|
||||
r2 := pickReg(m)
|
||||
c := p.NewValue1(a.Pos, OpCopy, a.Type, s.regs[r].c)
|
||||
s.copies[c] = false
|
||||
|
|
@ -1262,7 +1306,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
if phiRegs[i] != noRegister {
|
||||
continue
|
||||
}
|
||||
m := s.compatRegs(v.Type) &^ phiUsed &^ s.used
|
||||
m := s.compatRegs(v.Type).minus(phiUsed).minus(s.used)
|
||||
// If one of the other inputs of v is in a register, and the register is available,
|
||||
// select this register, which can save some unnecessary copies.
|
||||
for i, pe := range b.Preds {
|
||||
|
|
@ -1276,15 +1320,15 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
break
|
||||
}
|
||||
}
|
||||
if ri != noRegister && m>>ri&1 != 0 {
|
||||
m = regMask(1) << ri
|
||||
if ri != noRegister && m.hasReg(ri) {
|
||||
m = regMaskAt(ri)
|
||||
break
|
||||
}
|
||||
}
|
||||
if m != 0 {
|
||||
if !m.empty() {
|
||||
r := pickReg(m)
|
||||
phiRegs[i] = r
|
||||
phiUsed |= regMask(1) << r
|
||||
phiUsed = phiUsed.addReg(r)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1306,7 +1350,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
|
||||
// Deallocate any values which are no longer live. Phis are excluded.
|
||||
for r := register(0); r < s.numRegs; r++ {
|
||||
if phiUsed>>r&1 != 0 {
|
||||
if phiUsed.hasReg(r) {
|
||||
continue
|
||||
}
|
||||
v := s.regs[r].v
|
||||
|
|
@ -1325,13 +1369,13 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
if v == nil {
|
||||
continue
|
||||
}
|
||||
if phiUsed>>r&1 != 0 {
|
||||
if phiUsed.hasReg(r) {
|
||||
// Skip registers that phis used, we'll handle those
|
||||
// specially during merge edge processing.
|
||||
continue
|
||||
}
|
||||
regList = append(regList, startReg{r, v, s.regs[r].c, s.values[v.ID].uses.pos})
|
||||
s.startRegsMask |= regMask(1) << r
|
||||
s.startRegsMask = s.startRegsMask.addReg(r)
|
||||
}
|
||||
s.startRegs[b.ID] = make([]startReg, len(regList))
|
||||
copy(s.startRegs[b.ID], regList)
|
||||
|
|
@ -1512,7 +1556,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
s.advanceUses(v)
|
||||
a := v.Args[0]
|
||||
vi := &s.values[a.ID]
|
||||
if vi.regs == 0 && !vi.rematerializeable {
|
||||
if vi.regs.empty() && !vi.rematerializeable {
|
||||
// Use the spill location.
|
||||
// This forces later liveness analysis to make the
|
||||
// value live at this point.
|
||||
|
|
@ -1587,7 +1631,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
}
|
||||
for _, i := range regspec.inputs {
|
||||
mask := i.regs
|
||||
if countRegs(mask) == 1 && mask&s.values[v.Args[i.idx].ID].regs != 0 {
|
||||
if countRegs(mask) == 1 && !mask.intersect(s.values[v.Args[i.idx].ID].regs).empty() {
|
||||
args[i.idx] = s.allocValToReg(v.Args[i.idx], mask, true, v.Pos)
|
||||
}
|
||||
}
|
||||
|
|
@ -1604,14 +1648,14 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
continue // already allocated
|
||||
}
|
||||
mask := i.regs
|
||||
if countRegs(mask) == 1 && mask&^s.used != 0 {
|
||||
if countRegs(mask) == 1 && !mask.minus(s.used).empty() {
|
||||
args[i.idx] = s.allocValToReg(v.Args[i.idx], mask, true, v.Pos)
|
||||
// If the input is in other registers that will be clobbered by v,
|
||||
// or the input is dead, free the registers. This may make room
|
||||
// for other inputs.
|
||||
oldregs := s.values[v.Args[i.idx].ID].regs
|
||||
if oldregs&^regspec.clobbers == 0 || !s.liveAfterCurrentInstruction(v.Args[i.idx]) {
|
||||
s.freeRegs(oldregs &^ mask &^ s.nospill)
|
||||
if oldregs.minus(regspec.clobbers).empty() || !s.liveAfterCurrentInstruction(v.Args[i.idx]) {
|
||||
s.freeRegs(oldregs.minus(mask).minus(s.nospill))
|
||||
freed = true
|
||||
}
|
||||
}
|
||||
|
|
@ -1627,30 +1671,30 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
continue // already allocated
|
||||
}
|
||||
mask := i.regs
|
||||
if mask&s.values[v.Args[i.idx].ID].regs == 0 {
|
||||
if mask.intersect(s.values[v.Args[i.idx].ID].regs).empty() {
|
||||
// Need a new register for the input.
|
||||
mask &= s.allocatable
|
||||
mask &^= s.nospill
|
||||
mask = mask.intersect(s.allocatable)
|
||||
mask = mask.minus(s.nospill)
|
||||
// Used desired register if available.
|
||||
if i.idx < 3 {
|
||||
for _, r := range dinfo[idx].in[i.idx] {
|
||||
if r != noRegister && (mask&^s.used)>>r&1 != 0 {
|
||||
if r != noRegister && mask.minus(s.used).hasReg(r) {
|
||||
// Desired register is allowed and unused.
|
||||
mask = regMask(1) << r
|
||||
mask = regMaskAt(r)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// Avoid registers we're saving for other values.
|
||||
if mask&^desired.avoid != 0 {
|
||||
mask &^= desired.avoid
|
||||
if !mask.minus(desired.avoid).empty() {
|
||||
mask = mask.minus(desired.avoid)
|
||||
}
|
||||
}
|
||||
if mask&s.values[v.Args[i.idx].ID].regs&(1<<s.SPReg) != 0 {
|
||||
if mask.intersect(s.values[v.Args[i.idx].ID].regs).hasReg(s.SPReg) {
|
||||
// Prefer SP register. This ensures that local variables
|
||||
// use SP as their base register (instead of a copy of the
|
||||
// stack pointer living in another register). See issue 74836.
|
||||
mask = 1 << s.SPReg
|
||||
mask = regMaskAt(s.SPReg)
|
||||
}
|
||||
args[i.idx] = s.allocValToReg(v.Args[i.idx], mask, true, v.Pos)
|
||||
}
|
||||
|
|
@ -1689,8 +1733,8 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
// need to make a copy of an input so we have a register we can modify.
|
||||
|
||||
// Possible new registers to copy into.
|
||||
m = s.compatRegs(v.Args[0].Type) &^ s.used
|
||||
if m == 0 {
|
||||
m = s.compatRegs(v.Args[0].Type).minus(s.used)
|
||||
if m.empty() {
|
||||
// No free registers. In this case we'll just clobber
|
||||
// an input and future uses of that input must use a restore.
|
||||
// TODO(khr): We should really do this like allocReg does it,
|
||||
|
|
@ -1700,8 +1744,8 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
|
||||
// Try to move an input to the desired output, if allowed.
|
||||
for _, r := range dinfo[idx].out {
|
||||
if r != noRegister && (m®spec.outputs[0].regs)>>r&1 != 0 {
|
||||
m = regMask(1) << r
|
||||
if r != noRegister && m.intersect(regspec.outputs[0].regs).hasReg(r) {
|
||||
m = regMaskAt(r)
|
||||
args[0] = s.allocValToReg(v.Args[0], m, true, v.Pos)
|
||||
// Note: we update args[0] so the instruction will
|
||||
// use the register copy we just made.
|
||||
|
|
@ -1711,8 +1755,8 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
// Try to copy input to its desired location & use its old
|
||||
// location as the result register.
|
||||
for _, r := range dinfo[idx].in[0] {
|
||||
if r != noRegister && m>>r&1 != 0 {
|
||||
m = regMask(1) << r
|
||||
if r != noRegister && m.hasReg(r) {
|
||||
m = regMaskAt(r)
|
||||
c := s.allocValToReg(v.Args[0], m, true, v.Pos)
|
||||
s.copies[c] = false
|
||||
// Note: no update to args[0] so the instruction will
|
||||
|
|
@ -1722,8 +1766,8 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
}
|
||||
if opcodeTable[v.Op].commutative {
|
||||
for _, r := range dinfo[idx].in[1] {
|
||||
if r != noRegister && m>>r&1 != 0 {
|
||||
m = regMask(1) << r
|
||||
if r != noRegister && m.hasReg(r) {
|
||||
m = regMaskAt(r)
|
||||
c := s.allocValToReg(v.Args[1], m, true, v.Pos)
|
||||
s.copies[c] = false
|
||||
args[0], args[1] = args[1], args[0]
|
||||
|
|
@ -1733,8 +1777,8 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
}
|
||||
|
||||
// Avoid future fixed uses if we can.
|
||||
if m&^desired.avoid != 0 {
|
||||
m &^= desired.avoid
|
||||
if !m.minus(desired.avoid).empty() {
|
||||
m = m.minus(desired.avoid)
|
||||
}
|
||||
// Save input 0 to a new register so we can clobber it.
|
||||
c := s.allocValToReg(v.Args[0], m, true, v.Pos)
|
||||
|
|
@ -1743,7 +1787,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
// Normally we use the register of the old copy of input 0 as the target.
|
||||
// However, if input 0 is already in its desired register then we use
|
||||
// the register of the new copy instead.
|
||||
if regspec.outputs[0].regs>>s.f.getHome(c.ID).(*Register).num&1 != 0 {
|
||||
if regspec.outputs[0].regs.hasReg(register(s.f.getHome(c.ID).(*Register).num)) {
|
||||
if rp, ok := s.f.getHome(args[0].ID).(*Register); ok {
|
||||
r := register(rp.num)
|
||||
for _, r2 := range dinfo[idx].in[0] {
|
||||
|
|
@ -1773,8 +1817,8 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
continue
|
||||
}
|
||||
// Possible new registers to copy into.
|
||||
m := s.compatRegs(v.Args[i].Type) &^ s.used
|
||||
if m == 0 {
|
||||
m := s.compatRegs(v.Args[i].Type).minus(s.used)
|
||||
if m.empty() {
|
||||
// No free registers. In this case we'll just clobber the
|
||||
// input and future uses of that input must use a restore.
|
||||
// TODO(khr): We should really do this like allocReg does it,
|
||||
|
|
@ -1793,18 +1837,18 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
// (Not all instructions need that distinct part, but it is conservative.)
|
||||
// We also ensure it is not any of the single-choice output registers.
|
||||
if opcodeTable[v.Op].needIntTemp {
|
||||
m := s.allocatable & s.f.Config.gpRegMask
|
||||
m := s.allocatable.intersect(s.f.Config.gpRegMask)
|
||||
for _, out := range regspec.outputs {
|
||||
if countRegs(out.regs) == 1 {
|
||||
m &^= out.regs
|
||||
m = m.minus(out.regs)
|
||||
}
|
||||
}
|
||||
if m&^desired.avoid&^s.nospill != 0 {
|
||||
m &^= desired.avoid
|
||||
if !m.minus(desired.avoid).minus(s.nospill).empty() {
|
||||
m = m.minus(desired.avoid)
|
||||
}
|
||||
tmpReg = s.allocReg(m, &tmpVal)
|
||||
s.nospill |= regMask(1) << tmpReg
|
||||
s.tmpused |= regMask(1) << tmpReg
|
||||
s.nospill = s.nospill.addReg(tmpReg)
|
||||
s.tmpused = s.tmpused.addReg(tmpReg)
|
||||
}
|
||||
|
||||
if regspec.clobbersArg0 {
|
||||
|
|
@ -1820,7 +1864,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
// same register as a dying input.
|
||||
if !opcodeTable[v.Op].resultNotInArgs {
|
||||
s.tmpused = s.nospill
|
||||
s.nospill = 0
|
||||
s.nospill = regMask{}
|
||||
s.advanceUses(v) // frees any registers holding args that are no longer live
|
||||
}
|
||||
|
||||
|
|
@ -1828,10 +1872,10 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
if s.doClobber && v.Op.IsCall() {
|
||||
// clobber registers that are marked as clobber in regmask, but
|
||||
// don't clobber inputs.
|
||||
s.clobberRegs(regspec.clobbers &^ s.tmpused &^ s.nospill)
|
||||
s.clobberRegs(regspec.clobbers.minus(s.tmpused).minus(s.nospill))
|
||||
}
|
||||
s.freeRegs(regspec.clobbers)
|
||||
s.tmpused |= regspec.clobbers
|
||||
s.tmpused = s.tmpused.union(regspec.clobbers)
|
||||
|
||||
// Pick registers for outputs.
|
||||
{
|
||||
|
|
@ -1841,24 +1885,24 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
if tmpReg != noRegister {
|
||||
// Ensure output registers are distinct from the temporary register.
|
||||
// (Not all instructions need that distinct part, but it is conservative.)
|
||||
used |= regMask(1) << tmpReg
|
||||
used = used.addReg(tmpReg)
|
||||
}
|
||||
for _, out := range regspec.outputs {
|
||||
if out.regs == 0 {
|
||||
if out.regs.empty() {
|
||||
continue
|
||||
}
|
||||
mask := out.regs & s.allocatable &^ used
|
||||
if mask == 0 {
|
||||
mask := out.regs.intersect(s.allocatable).minus(used)
|
||||
if mask.empty() {
|
||||
s.f.Fatalf("can't find any output register %s", v.LongString())
|
||||
}
|
||||
if opcodeTable[v.Op].resultInArg0 && out.idx == 0 {
|
||||
if !opcodeTable[v.Op].commutative {
|
||||
// Output must use the same register as input 0.
|
||||
r := register(s.f.getHome(args[0].ID).(*Register).num)
|
||||
if mask>>r&1 == 0 {
|
||||
if !mask.hasReg(r) {
|
||||
s.f.Fatalf("resultInArg0 value's input %v cannot be an output of %s", s.f.getHome(args[0].ID).(*Register), v.LongString())
|
||||
}
|
||||
mask = regMask(1) << r
|
||||
mask = regMaskAt(r)
|
||||
} else {
|
||||
// Output must use the same register as input 0 or 1.
|
||||
r0 := register(s.f.getHome(args[0].ID).(*Register).num)
|
||||
|
|
@ -1866,8 +1910,8 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
// Check r0 and r1 for desired output register.
|
||||
found := false
|
||||
for _, r := range dinfo[idx].out {
|
||||
if (r == r0 || r == r1) && (mask&^s.used)>>r&1 != 0 {
|
||||
mask = regMask(1) << r
|
||||
if (r == r0 || r == r1) && mask.minus(s.used).hasReg(r) {
|
||||
mask = regMaskAt(r)
|
||||
found = true
|
||||
if r == r1 {
|
||||
args[0], args[1] = args[1], args[0]
|
||||
|
|
@ -1877,15 +1921,15 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
}
|
||||
if !found {
|
||||
// Neither are desired, pick r0.
|
||||
mask = regMask(1) << r0
|
||||
mask = regMaskAt(r0)
|
||||
}
|
||||
}
|
||||
}
|
||||
if out.idx == 0 { // desired registers only apply to the first element of a tuple result
|
||||
for _, r := range dinfo[idx].out {
|
||||
if r != noRegister && (mask&^s.used)>>r&1 != 0 {
|
||||
if r != noRegister && mask.minus(s.used).hasReg(r) {
|
||||
// Desired register is allowed and unused.
|
||||
mask = regMask(1) << r
|
||||
mask = regMaskAt(r)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -1893,25 +1937,25 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
if out.idx == 1 {
|
||||
if prefs, ok := desiredSecondReg[v.ID]; ok {
|
||||
for _, r := range prefs {
|
||||
if r != noRegister && (mask&^s.used)>>r&1 != 0 {
|
||||
if r != noRegister && mask.minus(s.used).hasReg(r) {
|
||||
// Desired register is allowed and unused.
|
||||
mask = regMask(1) << r
|
||||
mask = regMaskAt(r)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Avoid registers we're saving for other values.
|
||||
if mask&^desired.avoid&^s.nospill&^s.used != 0 {
|
||||
mask &^= desired.avoid
|
||||
if !mask.minus(desired.avoid).minus(s.nospill).minus(s.used).empty() {
|
||||
mask = mask.minus(desired.avoid)
|
||||
}
|
||||
r := s.allocReg(mask, v)
|
||||
if out.idx > maxOutIdx {
|
||||
maxOutIdx = out.idx
|
||||
}
|
||||
outRegs[out.idx] = r
|
||||
used |= regMask(1) << r
|
||||
s.tmpused |= regMask(1) << r
|
||||
used = used.addReg(r)
|
||||
s.tmpused = s.tmpused.addReg(r)
|
||||
}
|
||||
// Record register choices
|
||||
if v.Type.IsTuple() {
|
||||
|
|
@ -1949,10 +1993,10 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
|
||||
// deallocate dead args, if we have not done so
|
||||
if opcodeTable[v.Op].resultNotInArgs {
|
||||
s.nospill = 0
|
||||
s.nospill = regMask{}
|
||||
s.advanceUses(v) // frees any registers holding args that are no longer live
|
||||
}
|
||||
s.tmpused = 0
|
||||
s.tmpused = regMask{}
|
||||
|
||||
// Issue the Value itself.
|
||||
for i, a := range args {
|
||||
|
|
@ -2030,7 +2074,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
var likelyUsedRegs regMask
|
||||
for _, live := range s.live[b.ID] {
|
||||
if live.dist < unlikelyDistance {
|
||||
likelyUsedRegs |= s.values[live.ID].regs
|
||||
likelyUsedRegs = likelyUsedRegs.union(s.values[live.ID].regs)
|
||||
}
|
||||
}
|
||||
// Promote values we're going to use soon in the destination to registers.
|
||||
|
|
@ -2049,11 +2093,11 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
// as returned by compatRegs. Being in a fixed register
|
||||
// (e.g. the zero register) or being easily
|
||||
// rematerializeable isn't enough.
|
||||
if vi.regs&s.compatRegs(v.Type) != 0 {
|
||||
if !vi.regs.intersect(s.compatRegs(v.Type)).empty() {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if vi.regs != 0 {
|
||||
if !vi.regs.empty() {
|
||||
continue
|
||||
}
|
||||
if vi.rematerializeable {
|
||||
|
|
@ -2072,8 +2116,8 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
}
|
||||
// Registers we could load v into.
|
||||
// Don't kick out other likely-used values.
|
||||
m := s.compatRegs(v.Type) &^ likelyUsedRegs
|
||||
if m == 0 {
|
||||
m := s.compatRegs(v.Type).minus(likelyUsedRegs)
|
||||
if m.empty() {
|
||||
// To many likely-used values to give them all a register.
|
||||
continue
|
||||
}
|
||||
|
|
@ -2085,17 +2129,17 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
continue
|
||||
}
|
||||
for _, r := range e.regs {
|
||||
if r != noRegister && m>>r&1 != 0 {
|
||||
m = regMask(1) << r
|
||||
if r != noRegister && m.hasReg(r) {
|
||||
m = regMaskAt(r)
|
||||
break outerloop
|
||||
}
|
||||
}
|
||||
}
|
||||
if m&^desired.avoid != 0 {
|
||||
m &^= desired.avoid
|
||||
if !m.minus(desired.avoid).empty() {
|
||||
m = m.minus(desired.avoid)
|
||||
}
|
||||
s.allocValToReg(v, m, false, b.Pos)
|
||||
likelyUsedRegs |= s.values[v.ID].regs
|
||||
likelyUsedRegs = likelyUsedRegs.union(s.values[v.ID].regs)
|
||||
}
|
||||
}
|
||||
badloop:
|
||||
|
|
@ -2146,7 +2190,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
if s.live != nil {
|
||||
for _, e := range s.live[b.ID] {
|
||||
vi := &s.values[e.ID]
|
||||
if vi.regs != 0 {
|
||||
if !vi.regs.empty() {
|
||||
// in a register, we'll use that source for the merge.
|
||||
continue
|
||||
}
|
||||
|
|
@ -2187,7 +2231,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
if c := countRegs(s.startRegsMask); c != len(s.startRegs[b.ID]) {
|
||||
regs := make([]startReg, 0, c)
|
||||
for _, sr := range s.startRegs[b.ID] {
|
||||
if s.startRegsMask&(regMask(1)<<sr.r) == 0 {
|
||||
if !s.startRegsMask.hasReg(sr.r) {
|
||||
continue
|
||||
}
|
||||
regs = append(regs, sr)
|
||||
|
|
@ -2438,10 +2482,10 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
|
|||
clear(e.cache)
|
||||
e.cachedVals = e.cachedVals[:0]
|
||||
clear(e.contents)
|
||||
e.usedRegs = 0
|
||||
e.uniqueRegs = 0
|
||||
e.finalRegs = 0
|
||||
e.rematerializeableRegs = 0
|
||||
e.usedRegs = regMask{}
|
||||
e.uniqueRegs = regMask{}
|
||||
e.finalRegs = regMask{}
|
||||
e.rematerializeableRegs = regMask{}
|
||||
|
||||
// Live registers can be sources.
|
||||
for _, x := range srcReg {
|
||||
|
|
@ -2648,7 +2692,7 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
|
|||
// Instead of setting the wrong register for the rematerialized v, we should find the right register
|
||||
// for it and emit an additional copy to move to the desired register.
|
||||
// For #70451.
|
||||
if e.s.regspec(v).outputs[0].regs®Mask(1<<register(loc.(*Register).num)) == 0 {
|
||||
if !e.s.regspec(v).outputs[0].regs.hasReg(register(loc.(*Register).num)) {
|
||||
_, srcReg := src.(*Register)
|
||||
if srcReg {
|
||||
// It exists in a valid register already, so just copy it to the desired register
|
||||
|
|
@ -2724,23 +2768,23 @@ func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, pos src.XPos
|
|||
a = append(a, c)
|
||||
e.cache[vid] = a
|
||||
if r, ok := loc.(*Register); ok {
|
||||
if e.usedRegs&(regMask(1)<<uint(r.num)) != 0 {
|
||||
if e.usedRegs.hasReg(register(r.num)) {
|
||||
e.s.f.Fatalf("%v is already set (v%d/%v)", r, vid, c)
|
||||
}
|
||||
e.usedRegs |= regMask(1) << uint(r.num)
|
||||
e.usedRegs = e.usedRegs.addReg(register(r.num))
|
||||
if final {
|
||||
e.finalRegs |= regMask(1) << uint(r.num)
|
||||
e.finalRegs = e.finalRegs.addReg(register(r.num))
|
||||
}
|
||||
if len(a) == 1 {
|
||||
e.uniqueRegs |= regMask(1) << uint(r.num)
|
||||
e.uniqueRegs = e.uniqueRegs.addReg(register(r.num))
|
||||
}
|
||||
if len(a) == 2 {
|
||||
if t, ok := e.s.f.getHome(a[0].ID).(*Register); ok {
|
||||
e.uniqueRegs &^= regMask(1) << uint(t.num)
|
||||
e.uniqueRegs = e.uniqueRegs.removeReg(register(t.num))
|
||||
}
|
||||
}
|
||||
if e.s.values[vid].rematerializeable {
|
||||
e.rematerializeableRegs |= regMask(1) << uint(r.num)
|
||||
e.rematerializeableRegs = e.rematerializeableRegs.addReg(register(r.num))
|
||||
}
|
||||
}
|
||||
if e.s.f.pass.debug > regDebug {
|
||||
|
|
@ -2779,15 +2823,15 @@ func (e *edgeState) erase(loc Location) {
|
|||
|
||||
// Update register masks.
|
||||
if r, ok := loc.(*Register); ok {
|
||||
e.usedRegs &^= regMask(1) << uint(r.num)
|
||||
e.usedRegs = e.usedRegs.removeReg(register(r.num))
|
||||
if cr.final {
|
||||
e.finalRegs &^= regMask(1) << uint(r.num)
|
||||
e.finalRegs = e.finalRegs.removeReg(register(r.num))
|
||||
}
|
||||
e.rematerializeableRegs &^= regMask(1) << uint(r.num)
|
||||
e.rematerializeableRegs = e.rematerializeableRegs.removeReg(register(r.num))
|
||||
}
|
||||
if len(a) == 1 {
|
||||
if r, ok := e.s.f.getHome(a[0].ID).(*Register); ok {
|
||||
e.uniqueRegs |= regMask(1) << uint(r.num)
|
||||
e.uniqueRegs = e.uniqueRegs.addReg(register(r.num))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2802,20 +2846,20 @@ func (e *edgeState) findRegFor(typ *types.Type) Location {
|
|||
// 2) a non-unique register not holding a final value
|
||||
// 3) a non-unique register
|
||||
// 4) a register holding a rematerializeable value
|
||||
x := m &^ e.usedRegs
|
||||
if x != 0 {
|
||||
x := m.minus(e.usedRegs)
|
||||
if !x.empty() {
|
||||
return &e.s.registers[pickReg(x)]
|
||||
}
|
||||
x = m &^ e.uniqueRegs &^ e.finalRegs
|
||||
if x != 0 {
|
||||
x = m.minus(e.uniqueRegs).minus(e.finalRegs)
|
||||
if !x.empty() {
|
||||
return &e.s.registers[pickReg(x)]
|
||||
}
|
||||
x = m &^ e.uniqueRegs
|
||||
if x != 0 {
|
||||
x = m.minus(e.uniqueRegs)
|
||||
if !x.empty() {
|
||||
return &e.s.registers[pickReg(x)]
|
||||
}
|
||||
x = m & e.rematerializeableRegs
|
||||
if x != 0 {
|
||||
x = m.intersect(e.rematerializeableRegs)
|
||||
if !x.empty() {
|
||||
return &e.s.registers[pickReg(x)]
|
||||
}
|
||||
|
||||
|
|
@ -2824,7 +2868,7 @@ func (e *edgeState) findRegFor(typ *types.Type) Location {
|
|||
for _, vid := range e.cachedVals {
|
||||
a := e.cache[vid]
|
||||
for _, c := range a {
|
||||
if r, ok := e.s.f.getHome(c.ID).(*Register); ok && m>>uint(r.num)&1 != 0 {
|
||||
if r, ok := e.s.f.getHome(c.ID).(*Register); ok && m.hasReg(register(r.num)) {
|
||||
if !c.rematerializeable() {
|
||||
x := e.p.NewValue1(c.Pos, OpStoreReg, c.Type, c)
|
||||
// Allocate a temp location to spill a register to.
|
||||
|
|
@ -3317,7 +3361,7 @@ func (s *regAllocState) debugPrintLiveBlock(b *Block, live []liveInfo, desired *
|
|||
fmt.Printf("]")
|
||||
}
|
||||
}
|
||||
if avoid := desired.avoid; avoid != 0 {
|
||||
if avoid := desired.avoid; !avoid.empty() {
|
||||
fmt.Printf(" avoid=%v", s.RegMaskString(avoid))
|
||||
}
|
||||
fmt.Println()
|
||||
|
|
@ -3357,7 +3401,7 @@ func (d *desiredState) get(vid ID) [4]register {
|
|||
|
||||
// add records that we'd like value vid to be in register r.
|
||||
func (d *desiredState) add(vid ID, r register) {
|
||||
d.avoid |= regMask(1) << r
|
||||
d.avoid = d.avoid.addReg(r)
|
||||
for i := range d.entries {
|
||||
e := &d.entries[i]
|
||||
if e.ID != vid {
|
||||
|
|
@ -3398,7 +3442,7 @@ func (d *desiredState) clobber(m regMask) {
|
|||
e := &d.entries[i]
|
||||
j := 0
|
||||
for _, r := range e.regs {
|
||||
if r != noRegister && m>>r&1 == 0 {
|
||||
if r != noRegister && !m.hasReg(r) {
|
||||
e.regs[j] = r
|
||||
j++
|
||||
}
|
||||
|
|
@ -3414,7 +3458,7 @@ func (d *desiredState) clobber(m regMask) {
|
|||
}
|
||||
i++
|
||||
}
|
||||
d.avoid &^= m
|
||||
d.avoid = d.avoid.minus(m)
|
||||
}
|
||||
|
||||
// copy copies a desired state from another desiredState x.
|
||||
|
|
@ -3440,7 +3484,7 @@ func (d *desiredState) remove(vid ID) [4]register {
|
|||
// changed
|
||||
func (d *desiredState) merge(x *desiredState) bool {
|
||||
oldAvoid := d.avoid
|
||||
d.avoid |= x.avoid
|
||||
d.avoid = d.avoid.union(x.avoid)
|
||||
// There should only be a few desired registers, so
|
||||
// linear insert is ok.
|
||||
for _, e := range x.entries {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ func TestSizeof(t *testing.T) {
|
|||
{Value{}, 72, 112},
|
||||
{Block{}, 168, 312},
|
||||
{LocalSlot{}, 28, 40},
|
||||
{valState{}, 28, 40},
|
||||
{valState{}, 36, 48},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue