since we have now so many virtual registers, reduce memory consumption for the register allocator (#17985)
This commit is contained in:
parent
983a2aa11c
commit
a9ae5fe5be
3 changed files with 48 additions and 50 deletions
|
|
@ -2106,7 +2106,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
|
|
||||||
proc execute(c: PCtx, start: int): PNode =
|
proc execute(c: PCtx, start: int): PNode =
|
||||||
var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil)
|
var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil)
|
||||||
newSeq(tos.slots, c.prc.maxSlots)
|
newSeq(tos.slots, c.prc.regInfo.len)
|
||||||
result = rawExecute(c, start, tos).regToNode
|
result = rawExecute(c, start, tos).regToNode
|
||||||
|
|
||||||
proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
|
proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
|
||||||
|
|
@ -2203,8 +2203,8 @@ proc evalConstExprAux(module: PSym; idgen: IdGenerator;
|
||||||
assert c.code[start].opcode != opcEof
|
assert c.code[start].opcode != opcEof
|
||||||
when debugEchoCode: c.echoCode start
|
when debugEchoCode: c.echoCode start
|
||||||
var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil)
|
var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil)
|
||||||
newSeq(tos.slots, c.prc.maxSlots)
|
newSeq(tos.slots, c.prc.regInfo.len)
|
||||||
#for i in 0..<c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
|
#for i in 0..<c.prc.regInfo.len: tos.slots[i] = newNode(nkEmpty)
|
||||||
result = rawExecute(c, start, tos).regToNode
|
result = rawExecute(c, start, tos).regToNode
|
||||||
if result.info.col < 0: result.info = n.info
|
if result.info.col < 0: result.info = n.info
|
||||||
c.mode = oldMode
|
c.mode = oldMode
|
||||||
|
|
|
||||||
|
|
@ -231,8 +231,7 @@ type
|
||||||
PProc* = ref object
|
PProc* = ref object
|
||||||
blocks*: seq[TBlock] # blocks; temp data structure
|
blocks*: seq[TBlock] # blocks; temp data structure
|
||||||
sym*: PSym
|
sym*: PSym
|
||||||
slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
|
regInfo*: seq[tuple[inUse: bool, kind: TSlotKind]]
|
||||||
maxSlots*: int
|
|
||||||
|
|
||||||
VmArgs* = object
|
VmArgs* = object
|
||||||
ra*, rb*, rc*: Natural
|
ra*, rb*, rc*: Natural
|
||||||
|
|
|
||||||
|
|
@ -211,22 +211,22 @@ proc getFreeRegister(cc: PCtx; k: TSlotKind; start: int): TRegister =
|
||||||
# we prefer the same slot kind here for efficiency. Unfortunately for
|
# we prefer the same slot kind here for efficiency. Unfortunately for
|
||||||
# discardable return types we may not know the desired type. This can happen
|
# discardable return types we may not know the desired type. This can happen
|
||||||
# for e.g. mNAdd[Multiple]:
|
# for e.g. mNAdd[Multiple]:
|
||||||
for i in start..c.maxSlots-1:
|
for i in start..c.regInfo.len-1:
|
||||||
if c.slots[i].kind == k and not c.slots[i].inUse:
|
if c.regInfo[i].kind == k and not c.regInfo[i].inUse:
|
||||||
c.slots[i].inUse = true
|
c.regInfo[i].inUse = true
|
||||||
return TRegister(i)
|
return TRegister(i)
|
||||||
|
|
||||||
# if register pressure is high, we re-use more aggressively:
|
# if register pressure is high, we re-use more aggressively:
|
||||||
if c.maxSlots >= high(TRegister):
|
if c.regInfo.len >= high(TRegister):
|
||||||
for i in start..c.maxSlots-1:
|
for i in start..c.regInfo.len-1:
|
||||||
if not c.slots[i].inUse:
|
if not c.regInfo[i].inUse:
|
||||||
c.slots[i] = (inUse: true, kind: k)
|
c.regInfo[i] = (inUse: true, kind: k)
|
||||||
return TRegister(i)
|
return TRegister(i)
|
||||||
if c.maxSlots >= high(TRegister):
|
if c.regInfo.len >= high(TRegister):
|
||||||
globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
|
globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
|
||||||
result = TRegister(max(c.maxSlots, start))
|
result = TRegister(max(c.regInfo.len, start))
|
||||||
c.slots[result] = (inUse: true, kind: k)
|
c.regInfo.setLen int(result)+1
|
||||||
c.maxSlots = result + 1
|
c.regInfo[result] = (inUse: true, kind: k)
|
||||||
|
|
||||||
proc getTemp(cc: PCtx; tt: PType): TRegister =
|
proc getTemp(cc: PCtx; tt: PType): TRegister =
|
||||||
let typ = tt.skipTypesOrNil({tyStatic})
|
let typ = tt.skipTypesOrNil({tyStatic})
|
||||||
|
|
@ -244,29 +244,29 @@ proc getTemp(cc: PCtx; tt: PType): TRegister =
|
||||||
|
|
||||||
proc freeTemp(c: PCtx; r: TRegister) =
|
proc freeTemp(c: PCtx; r: TRegister) =
|
||||||
let c = c.prc
|
let c = c.prc
|
||||||
if c.slots[r].kind in {slotSomeTemp..slotTempComplex}:
|
if c.regInfo[r].kind in {slotSomeTemp..slotTempComplex}:
|
||||||
# this seems to cause https://github.com/nim-lang/Nim/issues/10647
|
# this seems to cause https://github.com/nim-lang/Nim/issues/10647
|
||||||
c.slots[r].inUse = false
|
c.regInfo[r].inUse = false
|
||||||
|
|
||||||
proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister =
|
proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister =
|
||||||
# if register pressure is high, we re-use more aggressively:
|
# if register pressure is high, we re-use more aggressively:
|
||||||
let c = cc.prc
|
let c = cc.prc
|
||||||
# we could also customize via the following (with proper caching in ConfigRef):
|
# we could also customize via the following (with proper caching in ConfigRef):
|
||||||
# let highRegisterPressure = cc.config.getConfigVar("vm.highRegisterPressure", "40").parseInt
|
# let highRegisterPressure = cc.config.getConfigVar("vm.highRegisterPressure", "40").parseInt
|
||||||
if c.maxSlots >= HighRegisterPressure or c.maxSlots+n >= high(TRegister):
|
if c.regInfo.len >= HighRegisterPressure or c.regInfo.len+n >= high(TRegister):
|
||||||
for i in 0..c.maxSlots-n:
|
for i in 0..c.regInfo.len-n:
|
||||||
if not c.slots[i].inUse:
|
if not c.regInfo[i].inUse:
|
||||||
block search:
|
block search:
|
||||||
for j in i+1..i+n-1:
|
for j in i+1..i+n-1:
|
||||||
if c.slots[j].inUse: break search
|
if c.regInfo[j].inUse: break search
|
||||||
result = TRegister(i)
|
result = TRegister(i)
|
||||||
for k in result..result+n-1: c.slots[k] = (inUse: true, kind: kind)
|
for k in result..result+n-1: c.regInfo[k] = (inUse: true, kind: kind)
|
||||||
return
|
return
|
||||||
if c.maxSlots+n >= high(TRegister):
|
if c.regInfo.len+n >= high(TRegister):
|
||||||
globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
|
globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
|
||||||
result = TRegister(c.maxSlots)
|
result = TRegister(c.regInfo.len)
|
||||||
inc c.maxSlots, n
|
setLen c.regInfo, c.regInfo.len+n
|
||||||
for k in result..result+n-1: c.slots[k] = (inUse: true, kind: kind)
|
for k in result..result+n-1: c.regInfo[k] = (inUse: true, kind: kind)
|
||||||
|
|
||||||
proc freeTempRange(c: PCtx; start: TRegister, n: int) =
|
proc freeTempRange(c: PCtx; start: TRegister, n: int) =
|
||||||
for i in start..start+n-1: c.freeTemp(TRegister(i))
|
for i in start..start+n-1: c.freeTemp(TRegister(i))
|
||||||
|
|
@ -350,21 +350,21 @@ proc genWhile(c: PCtx; n: PNode) =
|
||||||
c.patch(lab2)
|
c.patch(lab2)
|
||||||
|
|
||||||
proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
|
proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
let oldRegisterCount = c.prc.maxSlots
|
let oldRegisterCount = c.prc.regInfo.len
|
||||||
withBlock(n[0].sym):
|
withBlock(n[0].sym):
|
||||||
c.gen(n[1], dest)
|
c.gen(n[1], dest)
|
||||||
|
|
||||||
for i in oldRegisterCount..<c.prc.maxSlots:
|
for i in oldRegisterCount..<c.prc.regInfo.len:
|
||||||
#if c.prc.slots[i].kind in {slotFixedVar, slotFixedLet}:
|
#if c.prc.regInfo[i].kind in {slotFixedVar, slotFixedLet}:
|
||||||
if i != dest:
|
if i != dest:
|
||||||
when not defined(release):
|
when not defined(release):
|
||||||
if c.prc.slots[i].inUse and c.prc.slots[i].kind in {slotTempUnknown,
|
if c.prc.regInfo[i].inUse and c.prc.regInfo[i].kind in {slotTempUnknown,
|
||||||
slotTempInt,
|
slotTempInt,
|
||||||
slotTempFloat,
|
slotTempFloat,
|
||||||
slotTempStr,
|
slotTempStr,
|
||||||
slotTempComplex}:
|
slotTempComplex}:
|
||||||
doAssert false, "leaking temporary " & $i & " " & $c.prc.slots[i].kind
|
doAssert false, "leaking temporary " & $i & " " & $c.prc.regInfo[i].kind
|
||||||
c.prc.slots[i] = (inUse: false, kind: slotEmpty)
|
c.prc.regInfo[i] = (inUse: false, kind: slotEmpty)
|
||||||
|
|
||||||
c.clearDest(n, dest)
|
c.clearDest(n, dest)
|
||||||
|
|
||||||
|
|
@ -416,7 +416,7 @@ proc genIf(c: PCtx, n: PNode; dest: var TDest) =
|
||||||
c.clearDest(n, dest)
|
c.clearDest(n, dest)
|
||||||
|
|
||||||
proc isTemp(c: PCtx; dest: TDest): bool =
|
proc isTemp(c: PCtx; dest: TDest): bool =
|
||||||
result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown
|
result = dest >= 0 and c.prc.regInfo[dest].kind >= slotTempUnknown
|
||||||
|
|
||||||
proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
|
proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
|
||||||
# asgn dest, a
|
# asgn dest, a
|
||||||
|
|
@ -583,7 +583,7 @@ proc genLit(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
# assignments now:
|
# assignments now:
|
||||||
#var opc = opcLdConst
|
#var opc = opcLdConst
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
#elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
|
#elif c.prc.regInfo[dest].kind == slotFixedVar: opc = opcAsgnConst
|
||||||
let lit = genLiteral(c, n)
|
let lit = genLiteral(c, n)
|
||||||
c.gABx(n, opcLdConst, dest, lit)
|
c.gABx(n, opcLdConst, dest, lit)
|
||||||
|
|
||||||
|
|
@ -814,7 +814,7 @@ proc genVarargsABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||||
var r: TRegister = x+i-1
|
var r: TRegister = x+i-1
|
||||||
c.gen(n[i], r)
|
c.gen(n[i], r)
|
||||||
c.gABC(n, opc, dest, x, n.len-1)
|
c.gABC(n, opc, dest, x, n.len-1)
|
||||||
c.freeTempRange(x, n.len)
|
c.freeTempRange(x, n.len-1)
|
||||||
|
|
||||||
proc isInt8Lit(n: PNode): bool =
|
proc isInt8Lit(n: PNode): bool =
|
||||||
if n.kind in {nkCharLit..nkUInt64Lit}:
|
if n.kind in {nkCharLit..nkUInt64Lit}:
|
||||||
|
|
@ -1431,11 +1431,11 @@ proc genAddr(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) =
|
||||||
else:
|
else:
|
||||||
let tmp = c.genx(n[0], newflags)
|
let tmp = c.genx(n[0], newflags)
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
if c.prc.slots[tmp].kind >= slotTempUnknown:
|
if c.prc.regInfo[tmp].kind >= slotTempUnknown:
|
||||||
gABC(c, n, opcAddrNode, dest, tmp)
|
gABC(c, n, opcAddrNode, dest, tmp)
|
||||||
# hack ahead; in order to fix bug #1781 we mark the temporary as
|
# hack ahead; in order to fix bug #1781 we mark the temporary as
|
||||||
# permanent, so that it's not used for anything else:
|
# permanent, so that it's not used for anything else:
|
||||||
c.prc.slots[tmp].kind = slotTempPerm
|
c.prc.regInfo[tmp].kind = slotTempPerm
|
||||||
# XXX this is still a hack
|
# XXX this is still a hack
|
||||||
#message(c.congig, n.info, warnUser, "suspicious opcode used")
|
#message(c.congig, n.info, warnUser, "suspicious opcode used")
|
||||||
else:
|
else:
|
||||||
|
|
@ -1662,10 +1662,10 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||||
s.kind in {skParam, skResult}):
|
s.kind in {skParam, skResult}):
|
||||||
if dest < 0:
|
if dest < 0:
|
||||||
dest = s.position + ord(s.kind == skParam)
|
dest = s.position + ord(s.kind == skParam)
|
||||||
internalAssert(c.config, c.prc.slots[dest].kind < slotSomeTemp)
|
internalAssert(c.config, c.prc.regInfo[dest].kind < slotSomeTemp)
|
||||||
else:
|
else:
|
||||||
# we need to generate an assignment:
|
# we need to generate an assignment:
|
||||||
let requiresCopy = c.prc.slots[dest].kind >= slotSomeTemp and
|
let requiresCopy = c.prc.regInfo[dest].kind >= slotSomeTemp and
|
||||||
gfIsParam notin flags
|
gfIsParam notin flags
|
||||||
genAsgn(c, dest, n, requiresCopy)
|
genAsgn(c, dest, n, requiresCopy)
|
||||||
else:
|
else:
|
||||||
|
|
@ -2188,10 +2188,10 @@ proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int =
|
||||||
|
|
||||||
proc genParams(c: PCtx; params: PNode) =
|
proc genParams(c: PCtx; params: PNode) =
|
||||||
# res.sym.position is already 0
|
# res.sym.position is already 0
|
||||||
c.prc.slots[0] = (inUse: true, kind: slotFixedVar)
|
setLen(c.prc.regInfo, max(params.len, 1))
|
||||||
|
c.prc.regInfo[0] = (inUse: true, kind: slotFixedVar)
|
||||||
for i in 1..<params.len:
|
for i in 1..<params.len:
|
||||||
c.prc.slots[i] = (inUse: true, kind: slotFixedLet)
|
c.prc.regInfo[i] = (inUse: true, kind: slotFixedLet)
|
||||||
c.prc.maxSlots = max(params.len, 1)
|
|
||||||
|
|
||||||
proc finalJumpTarget(c: PCtx; pc, diff: int) =
|
proc finalJumpTarget(c: PCtx; pc, diff: int) =
|
||||||
internalAssert(c.config, regBxMin < diff and diff < regBxMax)
|
internalAssert(c.config, regBxMin < diff and diff < regBxMax)
|
||||||
|
|
@ -2201,12 +2201,12 @@ proc finalJumpTarget(c: PCtx; pc, diff: int) =
|
||||||
TInstrType(diff+wordExcess) shl regBxShift).TInstr
|
TInstrType(diff+wordExcess) shl regBxShift).TInstr
|
||||||
|
|
||||||
proc genGenericParams(c: PCtx; gp: PNode) =
|
proc genGenericParams(c: PCtx; gp: PNode) =
|
||||||
var base = c.prc.maxSlots
|
var base = c.prc.regInfo.len
|
||||||
|
setLen c.prc.regInfo, base + gp.len
|
||||||
for i in 0..<gp.len:
|
for i in 0..<gp.len:
|
||||||
var param = gp[i].sym
|
var param = gp[i].sym
|
||||||
param.position = base + i # XXX: fix this earlier; make it consistent with templates
|
param.position = base + i # XXX: fix this earlier; make it consistent with templates
|
||||||
c.prc.slots[base + i] = (inUse: true, kind: slotFixedLet)
|
c.prc.regInfo[base + i] = (inUse: true, kind: slotFixedLet)
|
||||||
c.prc.maxSlots = base + gp.len
|
|
||||||
|
|
||||||
proc optimizeJumps(c: PCtx; start: int) =
|
proc optimizeJumps(c: PCtx; start: int) =
|
||||||
const maxIterations = 10
|
const maxIterations = 10
|
||||||
|
|
@ -2280,19 +2280,18 @@ proc genProc(c: PCtx; s: PSym): int =
|
||||||
if tfCapturesEnv in s.typ.flags:
|
if tfCapturesEnv in s.typ.flags:
|
||||||
#let env = s.ast[paramsPos].lastSon.sym
|
#let env = s.ast[paramsPos].lastSon.sym
|
||||||
#assert env.position == 2
|
#assert env.position == 2
|
||||||
c.prc.slots[c.prc.maxSlots] = (inUse: true, kind: slotFixedLet)
|
c.prc.regInfo.add (inUse: true, kind: slotFixedLet)
|
||||||
inc c.prc.maxSlots
|
|
||||||
gen(c, body)
|
gen(c, body)
|
||||||
# generate final 'return' statement:
|
# generate final 'return' statement:
|
||||||
c.gABC(body, opcRet)
|
c.gABC(body, opcRet)
|
||||||
c.patch(procStart)
|
c.patch(procStart)
|
||||||
c.gABC(body, opcEof, eofInstr.regA)
|
c.gABC(body, opcEof, eofInstr.regA)
|
||||||
c.optimizeJumps(result)
|
c.optimizeJumps(result)
|
||||||
s.offset = c.prc.maxSlots
|
s.offset = c.prc.regInfo.len
|
||||||
#if s.name.s == "main" or s.name.s == "[]":
|
#if s.name.s == "main" or s.name.s == "[]":
|
||||||
# echo renderTree(body)
|
# echo renderTree(body)
|
||||||
# c.echoCode(result)
|
# c.echoCode(result)
|
||||||
c.prc = oldPrc
|
c.prc = oldPrc
|
||||||
else:
|
else:
|
||||||
c.prc.maxSlots = s.offset
|
c.prc.regInfo.setLen s.offset
|
||||||
result = pos
|
result = pos
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue