new VM: globals kinda work

This commit is contained in:
Araq 2013-12-13 01:21:23 +01:00
commit 328f193292
7 changed files with 45 additions and 12 deletions

View file

@ -557,7 +557,7 @@ proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool =
proc gstmts(g: var TSrcGen, n: PNode, c: TContext) = proc gstmts(g: var TSrcGen, n: PNode, c: TContext) =
if n.kind == nkEmpty: return if n.kind == nkEmpty: return
if (n.kind == nkStmtList) or (n.kind == nkStmtListExpr): if n.kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
indentNL(g) indentNL(g)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
optNL(g) optNL(g)
@ -1069,7 +1069,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkSpaces, Space) put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=") putWithSpace(g, tkEquals, "=")
gsub(g, n.sons[1]) gsub(g, n.sons[1])
of nkStmtList, nkStmtListExpr: gstmts(g, n, emptyContext) of nkStmtList, nkStmtListExpr, nkStmtListType: gstmts(g, n, emptyContext)
of nkIfStmt: of nkIfStmt:
putWithSpace(g, tkIf, "if") putWithSpace(g, tkIf, "if")
gif(g, n) gif(g, n)
@ -1246,8 +1246,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkBracketLe, "[") put(g, tkBracketLe, "[")
gcomma(g, n) gcomma(g, n)
put(g, tkBracketRi, "]") put(g, tkBracketRi, "]")
of nkMetaNode:
put(g, tkParLe, "(META|")
gsub(g, n.sons[0])
put(g, tkParRi, ")")
else: else:
#nkNone, nkMetaNode, nkExplicitTypeListCall: #nkNone, nkExplicitTypeListCall:
InternalError(n.info, "rnimsyn.gsub(" & $n.kind & ')') InternalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string = proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =

View file

@ -51,7 +51,9 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
checkMinSonsLen(n, 2) checkMinSonsLen(n, 2)
let t = n.sons[1].typ let t = n.sons[1].typ
internalAssert t != nil internalAssert t != nil
if not containsGenericType(t): if t.kind == tyTypeDesc and t.len == 0:
result = n
elif not containsGenericType(t):
result = evalTypeTrait(n[0], t, GetCurrOwner()) result = evalTypeTrait(n[0], t, GetCurrOwner())
else: else:
# a typedesc variable, pass unmodified to evals # a typedesc variable, pass unmodified to evals

View file

@ -1027,6 +1027,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
if c.code[pc].opcode in {opcWrGlobal, opcWrGlobalRef} and if c.code[pc].opcode in {opcWrGlobal, opcWrGlobalRef} and
c.code[pc].regBx == rb: c.code[pc].regBx == rb:
break break
of opcGlobalAlias:
let rb = instr.regBx - wordExcess - 1
regs[ra] = c.globals.sons[rb]
inc pc inc pc
proc fixType(result, n: PNode) {.inline.} = proc fixType(result, n: PNode) {.inline.} =
@ -1135,11 +1138,14 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
# setup arguments: # setup arguments:
var L = n.safeLen var L = n.safeLen
if L == 0: L = 1 if L == 0: L = 1
InternalAssert tos.slots.len >= L # This is wrong for tests/reject/tind1.nim where the passed 'else' part
# doesn't end up in the parameter:
#InternalAssert tos.slots.len >= L
# return value: # return value:
tos.slots[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0]) tos.slots[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
# setup parameters: # setup parameters:
for i in 1 .. < L: tos.slots[i] = setupMacroParam(n.sons[i]) for i in 1 .. < min(tos.slots.len, L):
tos.slots[i] = setupMacroParam(n.sons[i])
# temporary storage: # temporary storage:
for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty) for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
result = rawExecute(c, start, tos) result = rawExecute(c, start, tos)

View file

@ -122,6 +122,7 @@ type
opcLdImmInt, # dest = immediate value opcLdImmInt, # dest = immediate value
opcWrGlobal, opcWrGlobal,
opcWrGlobalRef, opcWrGlobalRef,
opcGlobalAlias, # load an alias to a global into a register
opcGlobalOnce, # used to introduce an assignment to a global once opcGlobalOnce, # used to introduce an assignment to a global once
opcSetType, # dest.typ = types[Bx] opcSetType, # dest.typ = types[Bx]
opcTypeTrait opcTypeTrait
@ -162,6 +163,8 @@ type
blocks*: seq[TBlock] # blocks; temp data structure blocks*: seq[TBlock] # blocks; temp data structure
slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]] slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
maxSlots*: int maxSlots*: int
globals*: array[TRegister, int] # hack: to support passing globals byref
# we map a slot persistently to a global
PCtx* = ref TCtx PCtx* = ref TCtx
TCtx* = object of passes.TPassContext # code gen context TCtx* = object of passes.TPassContext # code gen context
@ -185,7 +188,7 @@ type
proc newCtx*(module: PSym): PCtx = proc newCtx*(module: PSym): PCtx =
PCtx(code: @[], debug: @[], PCtx(code: @[], debug: @[],
globals: newNode(nkStmtList), constants: newNode(nkStmtList), types: @[], globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
prc: PProc(blocks: @[]), module: module) prc: PProc(blocks: @[]), module: module)
proc refresh*(c: PCtx, module: PSym) = proc refresh*(c: PCtx, module: PSym) =

View file

@ -134,6 +134,21 @@ proc getTemp(c: PCtx; typ: PType): TRegister =
c.slots[c.maxSlots] = (inUse: true, kind: k) c.slots[c.maxSlots] = (inUse: true, kind: k)
inc c.maxSlots inc c.maxSlots
proc getGlobalSlot(c: PCtx; n: PNode; s: PSym): TRegister =
let p = c.prc
for i in 0 .. p.maxSlots-1:
if p.globals[i] == s.id: return TRegister(i)
result = TRegister(p.maxSlots)
p.slots[p.maxSlots] = (inUse: true, kind: slotFixedVar)
p.globals[p.maxSlots] = s.id
inc p.maxSlots
# XXX this is still not correct! We need to load the global in a proc init
# section, otherwise control flow could lead to a usage before it's been
# loaded.
c.gABx(n, opcGlobalAlias, result, s.position)
# XXX add some internal asserts here
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 >= slotSomeTemp: c.slots[r].inUse = false if c.slots[r].kind >= slotSomeTemp: c.slots[r].inUse = false
@ -929,7 +944,7 @@ proc cannotEval(n: PNode) {.noinline.} =
n.renderTree) n.renderTree)
proc genGlobalInit(c: PCtx; n: PNode; s: PSym) = proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
c.globals.add(emptyNode) c.globals.add(emptyNode.copyNode)
s.position = c.globals.len s.position = c.globals.len
# This is rather hard to support, due to the laziness of the VM code # This is rather hard to support, due to the laziness of the VM code
# generator. See tests/compile/tmacro2 for why this is necesary: # generator. See tests/compile/tmacro2 for why this is necesary:
@ -946,11 +961,14 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
discard discard
else: else:
cannotEval(n) cannotEval(n)
if dest < 0: dest = c.getTemp(s.typ)
if s.position == 0: if s.position == 0:
if sfImportc in s.flags: c.importcSym(n.info, s) if sfImportc in s.flags: c.importcSym(n.info, s)
else: genGlobalInit(c, n, s) else: genGlobalInit(c, n, s)
c.gABx(n, opcLdGlobal, dest, s.position) if dest < 0:
dest = c.getGlobalSlot(n, s)
#c.gABx(n, opcAliasGlobal, dest, s.position)
else:
c.gABx(n, opcLdGlobal, dest, s.position)
else: else:
if s.position > 0 or (s.position == 0 and s.kind in {skParam, skResult}): if s.position > 0 or (s.position == 0 and s.kind in {skParam, skResult}):
if dest < 0: if dest < 0:

View file

@ -26,7 +26,7 @@ macro importImpl_forward(name, returns): stmt {.immediate.} =
p2.add newIdentNode("errors") p2.add newIdentNode("errors")
p2.add newNimNode(nnkVarTy) p2.add newNimNode(nnkVarTy)
p2.add newNimNode(nnkEmpty) p2.add newNimNode(nnkEmpty)
p2[1].add newNimNOde(nnkBracketExpr) p2[1].add newNimNode(nnkBracketExpr)
p2[1][0].add newIdentNode("seq") p2[1][0].add newIdentNode("seq")
p2[1][0].add newIdentNode("string") p2[1][0].add newIdentNode("string")
res[3].add p2 res[3].add p2

View file

@ -1,5 +1,5 @@
discard """ discard """
line: 14 line: 12
errormsg: "type mismatch" errormsg: "type mismatch"
""" """