Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vm: move ExpandToAst logic into own instruction #281

Merged
merged 1 commit into from
Apr 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 29 additions & 19 deletions compiler/vm/vm.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1287,6 +1287,34 @@ proc rawExecute(c: var TCtx, pc: var int, tos: var StackFrameIndex): TFullReg =
ast[i] = a.sym.ast[i]
ast[bodyPos] = transformBody(c.graph, c.idgen, a.sym, cache=true)
ast.copyTree()
of opcExpandToAst:
decodeBC(rkNode)

let
callExprAst = c.constants[regs[rb].intVal.int]
prc = callExprAst[0].sym
prevFrame = c.sframes[tos].next

assert callExprAst.kind in nkCallKinds
assert prc.kind == skTemplate

let genSymOwner = if prevFrame > 0 and c.sframes[prevFrame].prc != nil:
c.sframes[prevFrame].prc
else:
c.module
var templCall = newNodeI(nkCall, c.debug[pc])
templCall.add(newSymNode(prc))
for i in 1..rc-1:
let node = regs[rb+i].regToNode
node.info = c.debug[pc]
templCall.add(node)

var a = evalTemplate(templCall, prc, genSymOwner, c.config, c.cache, c.templInstCounter, c.idgen)
if a.kind == nkStmtList and a.len == 1: # flatten if a single statement
a = a[0]
a.recSetFlagIsRef
regs[ra].node = a

of opcSymOwner:
decodeB(rkNode)
let a = regs[rb].node
Expand Down Expand Up @@ -1370,7 +1398,7 @@ proc rawExecute(c: var TCtx, pc: var int, tos: var StackFrameIndex): TFullReg =
currentException: c.currentExceptionA,
currentLineInfo: c.debug[pc]))

elif prc.kind != skTemplate:
else:
let newPc = compile(c, prc)
# tricky: a recursion is also a jump back, so we use the same
# logic as for loops:
Expand All @@ -1387,24 +1415,6 @@ proc rawExecute(c: var TCtx, pc: var int, tos: var StackFrameIndex): TFullReg =
pushFrame(newFrame)
# -1 for the following 'inc pc'
pc = newPc-1
else:
let prevFrame = c.sframes[tos].next
# for 'getAst' support we need to support template expansion here:
let genSymOwner = if prevFrame > 0 and c.sframes[prevFrame].prc != nil:
c.sframes[prevFrame].prc
else:
c.module
var macroCall = newNodeI(nkCall, c.debug[pc])
macroCall.add(newSymNode(prc))
for i in 1..rc-1:
let node = regs[rb+i].regToNode
node.info = c.debug[pc]
macroCall.add(node)
var a = evalTemplate(macroCall, prc, genSymOwner, c.config, c.cache, c.templInstCounter, c.idgen)
if a.kind == nkStmtList and a.len == 1: a = a[0]
a.recSetFlagIsRef
ensureKind(rkNode)
regs[ra].node = a
of opcTJmp:
# jump Bx if A != 0
let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc'
Expand Down
4 changes: 3 additions & 1 deletion compiler/vm/vm_enums.nim
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ type
opcEqIdent,
opcStrToIdent,
opcGetImpl,
opcGetImplTransf
opcGetImplTransf,

opcExpandToAst,

opcEcho,
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
Expand Down
27 changes: 24 additions & 3 deletions compiler/vm/vmgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1411,7 +1411,26 @@ proc genMagic(c: var TCtx; n: PNode; dest: var TDest; m: TMagic) =
#if arg[0].kind != nkSym or arg[0].sym.kind notin {skTemplate, skMacro}:
# "ExpandToAst: expanded symbol is no macro or template"
if dest < 0: dest = c.getTemp(n.typ)
c.genCall(arg, dest)

if arg[0].sym.kind == skTemplate:
let x = c.getTempRange(arg.len, slotTempUnknown)

# Pass the whole call expression as the first value. Since the node
# might have a nil type, we can't use `genLit`. Instead load the
# constant index and make the instruction do the lookup itself
c.gABx(n, opcLdImmInt, TRegister(x), c.genLiteral(arg))

# Generate the arguments
for i in 1..<arg.len:
var d = TDest(x+i)
c.gen(arg[i], d, {gfIsParam})

c.gABC(arg, opcExpandToAst, dest, x, arg.len)
c.freeTempRange(x, arg.len)
else:
# macros are still invoked via the opcIndCall mechanism
c.genCall(arg, dest)

# do not call clearDest(n, dest) here as getAst has a meta-type as such
# produces a value
else:
Expand Down Expand Up @@ -2081,13 +2100,15 @@ proc gen(c: var TCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
of skVar, skForVar, skTemp, skLet, skParam, skResult:
genRdVar(c, n, dest, flags)

of skProc, skFunc, skConverter, skMacro, skTemplate, skMethod, skIterator:
# 'skTemplate' is only allowed for 'getAst' support:
of skProc, skFunc, skConverter, skMacro, skMethod, skIterator:
if s.kind == skIterator and s.typ.callConv == TCallingConvention.ccClosure:
fail(n.info, rsemVmNoClosureIterators, sym = s)
if procIsCallback(c, s): discard
elif importcCond(c, s): fail(n.info, rsemVmCannotImportc, sym = s)
genLit(c, n, dest)
of skTemplate:
# template symbols can be used as arguments in a `getAst` expression
genLit(c, n, dest)
of skConst:
let constVal = if s.ast != nil: s.ast else: s.typ.n
gen(c, constVal, dest)
Expand Down