Skip to content

Commit a9ae5fe

Browse files
authored
since we have now so many virtual registers, reduce memory consumption for the register allocator (nim-lang#17985)
1 parent 983a2aa commit a9ae5fe

File tree

3 files changed

+48
-50
lines changed

3 files changed

+48
-50
lines changed

compiler/vm.nim

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,7 +2106,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
21062106

21072107
proc execute(c: PCtx, start: int): PNode =
21082108
var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil)
2109-
newSeq(tos.slots, c.prc.maxSlots)
2109+
newSeq(tos.slots, c.prc.regInfo.len)
21102110
result = rawExecute(c, start, tos).regToNode
21112111

21122112
proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
@@ -2203,8 +2203,8 @@ proc evalConstExprAux(module: PSym; idgen: IdGenerator;
22032203
assert c.code[start].opcode != opcEof
22042204
when debugEchoCode: c.echoCode start
22052205
var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil)
2206-
newSeq(tos.slots, c.prc.maxSlots)
2207-
#for i in 0..<c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
2206+
newSeq(tos.slots, c.prc.regInfo.len)
2207+
#for i in 0..<c.prc.regInfo.len: tos.slots[i] = newNode(nkEmpty)
22082208
result = rawExecute(c, start, tos).regToNode
22092209
if result.info.col < 0: result.info = n.info
22102210
c.mode = oldMode

compiler/vmdef.nim

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,7 @@ type
231231
PProc* = ref object
232232
blocks*: seq[TBlock] # blocks; temp data structure
233233
sym*: PSym
234-
slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
235-
maxSlots*: int
234+
regInfo*: seq[tuple[inUse: bool, kind: TSlotKind]]
236235

237236
VmArgs* = object
238237
ra*, rb*, rc*: Natural

compiler/vmgen.nim

Lines changed: 44 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -211,22 +211,22 @@ proc getFreeRegister(cc: PCtx; k: TSlotKind; start: int): TRegister =
211211
# we prefer the same slot kind here for efficiency. Unfortunately for
212212
# discardable return types we may not know the desired type. This can happen
213213
# for e.g. mNAdd[Multiple]:
214-
for i in start..c.maxSlots-1:
215-
if c.slots[i].kind == k and not c.slots[i].inUse:
216-
c.slots[i].inUse = true
214+
for i in start..c.regInfo.len-1:
215+
if c.regInfo[i].kind == k and not c.regInfo[i].inUse:
216+
c.regInfo[i].inUse = true
217217
return TRegister(i)
218218

219219
# if register pressure is high, we re-use more aggressively:
220-
if c.maxSlots >= high(TRegister):
221-
for i in start..c.maxSlots-1:
222-
if not c.slots[i].inUse:
223-
c.slots[i] = (inUse: true, kind: k)
220+
if c.regInfo.len >= high(TRegister):
221+
for i in start..c.regInfo.len-1:
222+
if not c.regInfo[i].inUse:
223+
c.regInfo[i] = (inUse: true, kind: k)
224224
return TRegister(i)
225-
if c.maxSlots >= high(TRegister):
225+
if c.regInfo.len >= high(TRegister):
226226
globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
227-
result = TRegister(max(c.maxSlots, start))
228-
c.slots[result] = (inUse: true, kind: k)
229-
c.maxSlots = result + 1
227+
result = TRegister(max(c.regInfo.len, start))
228+
c.regInfo.setLen int(result)+1
229+
c.regInfo[result] = (inUse: true, kind: k)
230230

231231
proc getTemp(cc: PCtx; tt: PType): TRegister =
232232
let typ = tt.skipTypesOrNil({tyStatic})
@@ -244,29 +244,29 @@ proc getTemp(cc: PCtx; tt: PType): TRegister =
244244

245245
proc freeTemp(c: PCtx; r: TRegister) =
246246
let c = c.prc
247-
if c.slots[r].kind in {slotSomeTemp..slotTempComplex}:
247+
if c.regInfo[r].kind in {slotSomeTemp..slotTempComplex}:
248248
# this seems to cause https://github.com/nim-lang/Nim/issues/10647
249-
c.slots[r].inUse = false
249+
c.regInfo[r].inUse = false
250250

251251
proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister =
252252
# if register pressure is high, we re-use more aggressively:
253253
let c = cc.prc
254254
# we could also customize via the following (with proper caching in ConfigRef):
255255
# let highRegisterPressure = cc.config.getConfigVar("vm.highRegisterPressure", "40").parseInt
256-
if c.maxSlots >= HighRegisterPressure or c.maxSlots+n >= high(TRegister):
257-
for i in 0..c.maxSlots-n:
258-
if not c.slots[i].inUse:
256+
if c.regInfo.len >= HighRegisterPressure or c.regInfo.len+n >= high(TRegister):
257+
for i in 0..c.regInfo.len-n:
258+
if not c.regInfo[i].inUse:
259259
block search:
260260
for j in i+1..i+n-1:
261-
if c.slots[j].inUse: break search
261+
if c.regInfo[j].inUse: break search
262262
result = TRegister(i)
263-
for k in result..result+n-1: c.slots[k] = (inUse: true, kind: kind)
263+
for k in result..result+n-1: c.regInfo[k] = (inUse: true, kind: kind)
264264
return
265-
if c.maxSlots+n >= high(TRegister):
265+
if c.regInfo.len+n >= high(TRegister):
266266
globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
267-
result = TRegister(c.maxSlots)
268-
inc c.maxSlots, n
269-
for k in result..result+n-1: c.slots[k] = (inUse: true, kind: kind)
267+
result = TRegister(c.regInfo.len)
268+
setLen c.regInfo, c.regInfo.len+n
269+
for k in result..result+n-1: c.regInfo[k] = (inUse: true, kind: kind)
270270

271271
proc freeTempRange(c: PCtx; start: TRegister, n: int) =
272272
for i in start..start+n-1: c.freeTemp(TRegister(i))
@@ -350,21 +350,21 @@ proc genWhile(c: PCtx; n: PNode) =
350350
c.patch(lab2)
351351

352352
proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
353-
let oldRegisterCount = c.prc.maxSlots
353+
let oldRegisterCount = c.prc.regInfo.len
354354
withBlock(n[0].sym):
355355
c.gen(n[1], dest)
356356

357-
for i in oldRegisterCount..<c.prc.maxSlots:
358-
#if c.prc.slots[i].kind in {slotFixedVar, slotFixedLet}:
357+
for i in oldRegisterCount..<c.prc.regInfo.len:
358+
#if c.prc.regInfo[i].kind in {slotFixedVar, slotFixedLet}:
359359
if i != dest:
360360
when not defined(release):
361-
if c.prc.slots[i].inUse and c.prc.slots[i].kind in {slotTempUnknown,
361+
if c.prc.regInfo[i].inUse and c.prc.regInfo[i].kind in {slotTempUnknown,
362362
slotTempInt,
363363
slotTempFloat,
364364
slotTempStr,
365365
slotTempComplex}:
366-
doAssert false, "leaking temporary " & $i & " " & $c.prc.slots[i].kind
367-
c.prc.slots[i] = (inUse: false, kind: slotEmpty)
366+
doAssert false, "leaking temporary " & $i & " " & $c.prc.regInfo[i].kind
367+
c.prc.regInfo[i] = (inUse: false, kind: slotEmpty)
368368

369369
c.clearDest(n, dest)
370370

@@ -416,7 +416,7 @@ proc genIf(c: PCtx, n: PNode; dest: var TDest) =
416416
c.clearDest(n, dest)
417417

418418
proc isTemp(c: PCtx; dest: TDest): bool =
419-
result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown
419+
result = dest >= 0 and c.prc.regInfo[dest].kind >= slotTempUnknown
420420

421421
proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
422422
# asgn dest, a
@@ -583,7 +583,7 @@ proc genLit(c: PCtx; n: PNode; dest: var TDest) =
583583
# assignments now:
584584
#var opc = opcLdConst
585585
if dest < 0: dest = c.getTemp(n.typ)
586-
#elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
586+
#elif c.prc.regInfo[dest].kind == slotFixedVar: opc = opcAsgnConst
587587
let lit = genLiteral(c, n)
588588
c.gABx(n, opcLdConst, dest, lit)
589589

@@ -814,7 +814,7 @@ proc genVarargsABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
814814
var r: TRegister = x+i-1
815815
c.gen(n[i], r)
816816
c.gABC(n, opc, dest, x, n.len-1)
817-
c.freeTempRange(x, n.len)
817+
c.freeTempRange(x, n.len-1)
818818

819819
proc isInt8Lit(n: PNode): bool =
820820
if n.kind in {nkCharLit..nkUInt64Lit}:
@@ -1431,11 +1431,11 @@ proc genAddr(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) =
14311431
else:
14321432
let tmp = c.genx(n[0], newflags)
14331433
if dest < 0: dest = c.getTemp(n.typ)
1434-
if c.prc.slots[tmp].kind >= slotTempUnknown:
1434+
if c.prc.regInfo[tmp].kind >= slotTempUnknown:
14351435
gABC(c, n, opcAddrNode, dest, tmp)
14361436
# hack ahead; in order to fix bug #1781 we mark the temporary as
14371437
# permanent, so that it's not used for anything else:
1438-
c.prc.slots[tmp].kind = slotTempPerm
1438+
c.prc.regInfo[tmp].kind = slotTempPerm
14391439
# XXX this is still a hack
14401440
#message(c.congig, n.info, warnUser, "suspicious opcode used")
14411441
else:
@@ -1662,10 +1662,10 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
16621662
s.kind in {skParam, skResult}):
16631663
if dest < 0:
16641664
dest = s.position + ord(s.kind == skParam)
1665-
internalAssert(c.config, c.prc.slots[dest].kind < slotSomeTemp)
1665+
internalAssert(c.config, c.prc.regInfo[dest].kind < slotSomeTemp)
16661666
else:
16671667
# we need to generate an assignment:
1668-
let requiresCopy = c.prc.slots[dest].kind >= slotSomeTemp and
1668+
let requiresCopy = c.prc.regInfo[dest].kind >= slotSomeTemp and
16691669
gfIsParam notin flags
16701670
genAsgn(c, dest, n, requiresCopy)
16711671
else:
@@ -2188,10 +2188,10 @@ proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int =
21882188

21892189
proc genParams(c: PCtx; params: PNode) =
21902190
# res.sym.position is already 0
2191-
c.prc.slots[0] = (inUse: true, kind: slotFixedVar)
2191+
setLen(c.prc.regInfo, max(params.len, 1))
2192+
c.prc.regInfo[0] = (inUse: true, kind: slotFixedVar)
21922193
for i in 1..<params.len:
2193-
c.prc.slots[i] = (inUse: true, kind: slotFixedLet)
2194-
c.prc.maxSlots = max(params.len, 1)
2194+
c.prc.regInfo[i] = (inUse: true, kind: slotFixedLet)
21952195

21962196
proc finalJumpTarget(c: PCtx; pc, diff: int) =
21972197
internalAssert(c.config, regBxMin < diff and diff < regBxMax)
@@ -2201,12 +2201,12 @@ proc finalJumpTarget(c: PCtx; pc, diff: int) =
22012201
TInstrType(diff+wordExcess) shl regBxShift).TInstr
22022202

22032203
proc genGenericParams(c: PCtx; gp: PNode) =
2204-
var base = c.prc.maxSlots
2204+
var base = c.prc.regInfo.len
2205+
setLen c.prc.regInfo, base + gp.len
22052206
for i in 0..<gp.len:
22062207
var param = gp[i].sym
22072208
param.position = base + i # XXX: fix this earlier; make it consistent with templates
2208-
c.prc.slots[base + i] = (inUse: true, kind: slotFixedLet)
2209-
c.prc.maxSlots = base + gp.len
2209+
c.prc.regInfo[base + i] = (inUse: true, kind: slotFixedLet)
22102210

22112211
proc optimizeJumps(c: PCtx; start: int) =
22122212
const maxIterations = 10
@@ -2280,19 +2280,18 @@ proc genProc(c: PCtx; s: PSym): int =
22802280
if tfCapturesEnv in s.typ.flags:
22812281
#let env = s.ast[paramsPos].lastSon.sym
22822282
#assert env.position == 2
2283-
c.prc.slots[c.prc.maxSlots] = (inUse: true, kind: slotFixedLet)
2284-
inc c.prc.maxSlots
2283+
c.prc.regInfo.add (inUse: true, kind: slotFixedLet)
22852284
gen(c, body)
22862285
# generate final 'return' statement:
22872286
c.gABC(body, opcRet)
22882287
c.patch(procStart)
22892288
c.gABC(body, opcEof, eofInstr.regA)
22902289
c.optimizeJumps(result)
2291-
s.offset = c.prc.maxSlots
2290+
s.offset = c.prc.regInfo.len
22922291
#if s.name.s == "main" or s.name.s == "[]":
22932292
# echo renderTree(body)
22942293
# c.echoCode(result)
22952294
c.prc = oldPrc
22962295
else:
2297-
c.prc.maxSlots = s.offset
2296+
c.prc.regInfo.setLen s.offset
22982297
result = pos

0 commit comments

Comments
 (0)