VM: refactoring [backport] (#25280)

Note to @narimiran backport because IC requires it.
This commit is contained in:
Andreas Rumpf
2025-11-12 19:04:21 +01:00
committed by GitHub
parent d5549a3c65
commit 5da72efbde
3 changed files with 29 additions and 31 deletions

View File

@@ -480,9 +480,9 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType):
else:
asgnComplex(dest, src)
proc compile(c: PCtx, s: PSym): int =
proc compile(c: PCtx, s: PSym): VmProcInfo =
result = vmgen.genProc(c, s)
when debugEchoCode: c.echoCode result
when debugEchoCode: c.echoCode result.pc
#c.echoCode
template handleJmpBack() {.dirty.} =
@@ -1435,13 +1435,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
else:
globalError(c.config, c.debug[pc], "VM not built with FFI support")
elif prc.kind != skTemplate:
let newPc = compile(c, prc)
let procInfo = compile(c, prc)
# tricky: a recursion is also a jump back, so we use the same
# logic as for loops:
if newPc < pc: handleJmpBack()
if procInfo.pc < pc: handleJmpBack()
#echo "new pc ", newPc, " calling: ", prc.name.s
var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
newSeq(newFrame.slots, prc.offset+ord(isClosure))
newSeq(newFrame.slots, procInfo.usedRegisters+ord(isClosure))
# setup slot for proc result:
let ret {.cursor.} = prc.typ.returnType
# hot spot ahead!
@@ -1467,7 +1467,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
tos = newFrame
updateRegsAlias
# -1 for the following 'inc pc'
pc = newPc-1
pc = procInfo.pc-1
else:
# for 'getAst' support we need to support template expansion here:
let genSymOwner = if tos.next != nil and tos.next.prc != nil:
@@ -2351,8 +2351,7 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
let start = genProc(c, sym)
var tos = PStackFrame(prc: sym, comesFrom: 0, next: nil)
let maxSlots = sym.offset
newSeq(tos.slots, maxSlots)
newSeq(tos.slots, start.usedRegisters)
# setup parameters:
if not isEmptyType(sym.typ.returnType) or sym.kind == skMacro:
@@ -2361,7 +2360,7 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
for i in 0..<sym.typ.paramsLen:
putIntoReg(tos.slots[i+1], args[i])
result = rawExecute(c, start, tos).regToNode
result = rawExecute(c, start.pc, tos).regToNode
else:
result = nil
localError(c.config, sym.info,
@@ -2550,8 +2549,7 @@ proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstC
return errorNode(idgen, module, n)
var tos = PStackFrame(prc: sym, comesFrom: 0, next: nil)
let maxSlots = sym.offset
newSeq(tos.slots, maxSlots)
newSeq(tos.slots, start.usedRegisters)
# setup arguments:
var L = n.safeLen
if L == 0: L = 1
@@ -2578,7 +2576,7 @@ proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstC
" generic parameter(s)")
# temporary storage:
#for i in L..<maxSlots: tos.slots[i] = newNode(nkEmpty)
result = rawExecute(c, start, tos).regToNode
result = rawExecute(c, start.pc, tos).regToNode
if result.info.line < 0: result.info = n.info
if cyclicTree(result): globalError(c.config, n.info, "macro produced a cyclic tree")
dec(g.config.evalMacroCounter)

View File

@@ -243,6 +243,11 @@ type
VmCallback* = proc (args: VmArgs) {.closure.}
PCtx* = ref TCtx
VmProcInfo* = object
pc*: int32
usedRegisters*: int32
TCtx* = object of TPassContext # code gen context
code*: seq[TInstr]
debug*: seq[TLineInfo] # line info for every instruction; kept separate
@@ -271,7 +276,7 @@ type
profiler*: Profiler
templInstCounter*: ref int # gives every template instantiation a unique ID, needed here for getAst
vmstateDiff*: seq[(PSym, PNode)] # we remember the "diff" to global state here (feature for IC)
procToCodePos*: Table[int, int]
procToCodePos*: Table[int, VmProcInfo]
cannotEval*: bool
locals*: IntSet
@@ -293,6 +298,9 @@ type
PEvalContext* = PCtx
const
NoVmProcInfo* = VmProcInfo(pc: 0'i32, usedRegisters: -1'i32)
proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph; idgen: IdGenerator): PCtx =
PCtx(code: @[], debug: @[],
globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],

View File

@@ -2128,7 +2128,7 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
c.preventFalseAlias(it, opcWrObj, dest, i.TRegister, tmp)
c.freeTemp(tmp)
proc genProc*(c: PCtx; s: PSym): int
proc genProc*(c: PCtx; s: PSym): VmProcInfo
proc toKey(s: PSym): string =
result = ""
@@ -2412,27 +2412,19 @@ proc optimizeJumps(c: PCtx; start: int) =
c.finalJumpTarget(i, d - i)
else: discard
proc genProc(c: PCtx; s: PSym): int =
let
pos = c.procToCodePos.getOrDefault(s.id)
wasNotGenProcBefore = pos == 0
noRegistersAllocated = s.offset == -1
if wasNotGenProcBefore or noRegistersAllocated:
# xxx: the noRegisterAllocated check is required in order to avoid issues
# where nimsuggest can crash due as a macro with pos will be loaded
# but it doesn't have offsets for register allocations see:
# https://github.com/nim-lang/Nim/issues/18385
# Improvements and further use of IC should remove the need for this.
proc genProc(c: PCtx; s: PSym): VmProcInfo =
result = c.procToCodePos.getOrDefault(s.id, NoVmProcInfo)
if result.usedRegisters < 0:
#if s.name.s == "outterMacro" or s.name.s == "innerProc":
# echo "GENERATING CODE FOR ", s.name.s
let last = c.code.len-1
var eofInstr: TInstr = default(TInstr)
var eofInstr = default(TInstr)
if last >= 0 and c.code[last].opcode == opcEof:
eofInstr = c.code[last]
c.code.setLen(last)
c.debug.setLen(last)
#c.removeLastEof
result = c.code.len+1 # skip the jump instruction
result.pc = (c.code.len+1).int32 # skip the jump instruction
c.procToCodePos[s.id] = result
# thanks to the jmp we can add top level statements easily and also nest
# procs easily:
@@ -2457,12 +2449,12 @@ proc genProc(c: PCtx; s: PSym): int =
c.gABC(body, opcRet)
c.patch(procStart)
c.gABC(body, opcEof, eofInstr.regA)
c.optimizeJumps(result)
s.offset = c.prc.regInfo.len.int32
c.optimizeJumps(result.pc)
result.usedRegisters = c.prc.regInfo.len.int32
c.procToCodePos[s.id] = result
#if s.name.s == "main" or s.name.s == "[]":
# echo renderTree(body)
# c.echoCode(result)
c.prc = oldPrc
else:
c.prc.regInfo.setLen s.offset
result = pos
c.prc.regInfo.setLen result.usedRegisters