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:
Junyang Shao 2025-02-11 18:14:49 +00:00
parent 8594bf4621
commit 1901161d96
18 changed files with 16367 additions and 16289 deletions

View file

@ -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

View file

@ -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"},

View file

@ -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

View file

@ -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},

View file

@ -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},

View file

@ -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"]),
})

View file

@ -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"]),
})

View file

@ -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

View file

@ -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},

View file

@ -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",

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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 {

View file

@ -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

View file

@ -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&regspec.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&regMask(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 {

View file

@ -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 {