From 6e584c42c2d340a31acad85add79b579b3e56f0b Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 21 Feb 2014 17:23:37 +0100 Subject: vm2: new representation of registers --- compiler/vmgen.nim | 128 ++++++++++++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 65 deletions(-) (limited to 'compiler/vmgen.nim') diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 206cca0d7..b01514167 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -139,25 +139,12 @@ proc getTemp(c: PCtx; typ: PType): TRegister = if not c.slots[i].inUse: c.slots[i] = (inUse: true, kind: k) return TRegister(i) + if c.maxSlots >= high(TRegister): + internalError("cannot generate code; too many registers required") result = TRegister(c.maxSlots) c.slots[c.maxSlots] = (inUse: true, kind: k) 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) = let c = c.prc if c.slots[r].kind >= slotSomeTemp: c.slots[r].inUse = false @@ -322,13 +309,7 @@ proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) = c.patch(L1) proc nilLiteral(n: PNode): PNode = - if n.kind == nkNilLit and n.typ.sym != nil and - n.typ.sym.magic == mPNimrodNode: - let nilo = newNodeIT(nkNilLit, n.info, n.typ) - result = newNodeIT(nkMetaNode, n.info, n.typ) - result.add nilo - else: - result = n + result = n proc rawGenLiteral(c: PCtx; n: PNode): int = result = c.constants.len @@ -471,20 +452,24 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) = c.freeTempRange(x, n.len) proc needsAsgnPatch(n: PNode): bool = - n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr} + n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr, + nkDerefExpr, nkHiddenDeref} proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) = case le.kind of nkBracketExpr: - let dest = c.genx(le.sons[0]) + let dest = c.genx(le.sons[0], {gfAddrOf}) let idx = c.genx(le.sons[1]) - c.gABC(le, opcWrArrRef, dest, idx, value) + c.gABC(le, opcWrArr, dest, idx, value) of nkDotExpr, nkCheckedFieldExpr: # XXX field checks here let left = if le.kind == nkDotExpr: le else: le.sons[0] - let dest = c.genx(left.sons[0]) + let dest = c.genx(left.sons[0], {gfAddrOf}) let idx = c.genx(left.sons[1]) - c.gABC(left, opcWrObjRef, dest, idx, value) + c.gABC(left, opcWrObj, dest, idx, value) + of nkDerefExpr, nkHiddenDeref: + let dest = c.genx(le.sons[0], {gfAddrOf}) + c.gABC(le, opcWrDeref, dest, value) else: discard @@ -598,6 +583,7 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) = if dest < 0: dest = c.getTemp(n.typ) c.gABC(n, opc, dest, tmp) c.gABx(n, opc, 0, genType(c, n.typ)) + if opc == opcConv: c.gABx(n, opc, 0, genType(c, arg.typ)) c.freeTemp(tmp) proc genCard(c: PCtx; n: PNode; dest: var TDest) = @@ -905,6 +891,10 @@ const tyFloat, tyFloat32, tyFloat64, tyFloat128, tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64} +proc fitsRegister*(t: PType): bool = + t.skipTypes(abstractInst-{tyTypeDesc}).kind in { + tyRange, tyEnum, tyBool, tyInt..tyUInt64} + proc requiresCopy(n: PNode): bool = if n.typ.skipTypes(abstractInst-{tyTypeDesc}).kind in atomicTypes: result = false @@ -919,7 +909,8 @@ proc unneededIndirection(n: PNode): bool = proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; flags: TGenFlags) = # a nop for certain types - let flags = if opc == opcAddr: flags+{gfAddrOf} else: flags + let isAddr = opc in {opcAddrNode, opcAddrReg} + let flags = if isAddr: flags+{gfAddrOf} else: flags # consider: # proc foo(f: var ref int) = # f = new(int) @@ -929,12 +920,17 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; # # The type of 'f' is 'var ref int' and of 'x' is 'ref int'. Hence for # nkAddr we must not use 'unneededIndirection', but for deref we use it. - if opc != opcAddr and unneededIndirection(n.sons[0]): + if not isAddr and unneededIndirection(n.sons[0]): gen(c, n.sons[0], dest, flags) else: let tmp = c.genx(n.sons[0], flags) if dest < 0: dest = c.getTemp(n.typ) - gABC(c, n, opc, dest, tmp) + if not isAddr: + gABC(c, n, opc, dest, tmp) + elif c.prc.slots[tmp].kind >= slotTempUnknown: + gABC(c, n, opcAddrReg, dest, tmp) + else: + gABC(c, n, opcAddrNode, dest, tmp) c.freeTemp(tmp) proc whichAsgnOpc(n: PNode): TOpcode = @@ -952,8 +948,7 @@ proc whichAsgnOpc(n: PNode): TOpcode = proc isRef(t: PType): bool = t.skipTypes(abstractRange-{tyTypeDesc}).kind == tyRef -proc whichAsgnOpc(n: PNode; opc: TOpcode): TOpcode = - if isRef(n.typ): succ(opc) else: opc +proc whichAsgnOpc(n: PNode; opc: TOpcode): TOpcode = opc proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) = let tmp = c.genx(ri) @@ -974,29 +969,36 @@ proc setSlot(c: PCtx; v: PSym) = proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = case le.kind of nkBracketExpr: - let dest = c.genx(le.sons[0]) + let dest = c.genx(le.sons[0], {gfAddrOf}) let idx = c.genx(le.sons[1]) let tmp = c.genx(ri) if le.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in { tyString, tyCString}: c.gABC(le, opcWrStrIdx, dest, idx, tmp) else: - c.gABC(le, whichAsgnOpc(le, opcWrArr), dest, idx, tmp) + c.gABC(le, opcWrArr, dest, idx, tmp) c.freeTemp(tmp) of nkDotExpr, nkCheckedFieldExpr: # XXX field checks here let left = if le.kind == nkDotExpr: le else: le.sons[0] - let dest = c.genx(left.sons[0]) + let dest = c.genx(left.sons[0], {gfAddrOf}) let idx = c.genx(left.sons[1]) let tmp = c.genx(ri) - c.gABC(left, whichAsgnOpc(left, opcWrObj), dest, idx, tmp) + c.gABC(left, opcWrObj, dest, idx, tmp) + c.freeTemp(tmp) + of nkDerefExpr, nkHiddenDeref: + let dest = c.genx(le, {gfAddrOf}) + let tmp = c.genx(ri) + c.gABC(le, opcWrDeref, dest, tmp) c.freeTemp(tmp) of nkSym: let s = le.sym if s.isGlobal: withTemp(tmp, le.typ): - gen(c, ri, tmp) - c.gABx(le, whichAsgnOpc(le, opcWrGlobal), tmp, s.position) + c.gen(le, tmp, {gfAddrOf}) + let val = c.genx(ri) + c.gABC(le, opcWrDeref, tmp, val) + c.freeTemp(val) else: if s.kind == skForVar and c.mode == emRepl: c.setSlot s internalAssert s.position > 0 or (s.position == 0 and @@ -1004,7 +1006,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = var dest: TRegister = s.position + ord(s.kind == skParam) gen(c, ri, dest) else: - let dest = c.genx(le) + let dest = c.genx(le, {gfAddrOf}) genAsgn(c, dest, ri, requiresCopy) proc genLit(c: PCtx; n: PNode; dest: var TDest) = @@ -1040,10 +1042,6 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) = # This is rather hard to support, due to the laziness of the VM code # generator. See tests/compile/tmacro2 for why this is necesary: # var decls{.compileTime.}: seq[PNimrodNode] = @[] - c.gABx(n, opcGlobalOnce, 0, s.position) - let tmp = c.genx(s.ast) - c.gABx(n, whichAsgnOpc(n, opcWrGlobal), tmp, s.position) - c.freeTemp(tmp) proc genRdVar(c: PCtx; n: PNode; dest: var TDest) = let s = n.sym @@ -1055,11 +1053,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) = if s.position == 0: if sfImportc in s.flags: c.importcSym(n.info, s) else: genGlobalInit(c, n, s) - if dest < 0: - dest = c.getGlobalSlot(n, s) - #c.gABx(n, opcAliasGlobal, dest, s.position) - else: - c.gABx(n, opcLdGlobal, dest, s.position) + c.gABx(n, opcLdGlobal, dest, s.position) else: if s.kind == skForVar and c.mode == emRepl: c.setSlot s if s.position > 0 or (s.position == 0 and @@ -1078,7 +1072,13 @@ proc genAccess(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; let a = c.genx(n.sons[0], flags) let b = c.genx(n.sons[1], {}) if dest < 0: dest = c.getTemp(n.typ) - c.gABC(n, (if gfAddrOf in flags: succ(opc) else: opc), dest, a, b) + if gfAddrOf notin flags and fitsRegister(n.typ): + var cc = c.getTemp(n.typ) + c.gABC(n, opc, cc, a, b) + c.gABC(n, opcNodeToReg, dest, cc) + c.freeTemp(cc) + else: + c.gABC(n, opc, dest, a, b) c.freeTemp(a) c.freeTemp(b) @@ -1121,12 +1121,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode = result = newNodeIT(nkFloatLit, info, t) of tyVar, tyPointer, tyPtr, tyCString, tySequence, tyString, tyExpr, tyStmt, tyTypeDesc, tyStatic, tyRef: - if t.sym != nil and t.sym.magic == mPNimrodNode: - let nilo = newNodeIT(nkNilLit, info, t) - result = newNodeIT(nkMetaNode, info, t) - result.add nilo - else: - result = newNodeIT(nkNilLit, info, t) + result = newNodeIT(nkNilLit, info, t) of tyProc: if t.callConv != ccClosure: result = newNodeIT(nkNilLit, info, t) @@ -1154,6 +1149,9 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode = result = newNodeIT(nkCurly, info, t) else: internalError("getNullValue: " & $t.kind) +proc ldNullOpcode(t: PType): TOpcode = + if fitsRegister(t): opcLdNullReg else: opcLdNull + proc genVarSection(c: PCtx; n: PNode) = for a in n: if a.kind == nkCommentStmt: continue @@ -1165,7 +1163,7 @@ proc genVarSection(c: PCtx; n: PNode) = # v = t[i] var v: TDest = -1 genRdVar(c, a[i], v) - c.gABC(n, opcLdObj, v, tmp, i) + c.gABC(n, opcWrObj, v, tmp, i) # XXX globals? c.freeTemp(tmp) elif a.sons[0].kind == nkSym: @@ -1177,27 +1175,27 @@ proc genVarSection(c: PCtx; n: PNode) = let sa = if s.ast.isNil: getNullValue(s.typ, a.info) else: s.ast c.globals.add(sa) s.position = c.globals.len - # "Once support" is unnecessary here if a.sons[2].kind == nkEmpty: when false: withTemp(tmp, s.typ): c.gABx(a, opcLdNull, tmp, c.genType(s.typ)) c.gABx(a, whichAsgnOpc(a.sons[0], opcWrGlobal), tmp, s.position) else: - let tmp = genx(c, a.sons[2]) - c.gABx(a, whichAsgnOpc(a.sons[0], opcWrGlobal), tmp, s.position) - c.freeTemp(tmp) + let tmp = c.genx(a.sons[0], {gfAddrOf}) + let val = c.genx(a.sons[2]) + c.gABC(a, opcWrDeref, tmp, val) + c.freeTemp(val) else: setSlot(c, s) if a.sons[2].kind == nkEmpty: - c.gABx(a, opcLdNull, s.position, c.genType(s.typ)) + c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ)) else: gen(c, a.sons[2], s.position.TRegister) else: # assign to a.sons[0]; happens for closures if a.sons[2].kind == nkEmpty: let tmp = genx(c, a.sons[0]) - c.gABx(a, opcLdNull, tmp, c.genType(a.sons[0].typ)) + c.gABx(a, ldNullOpcode(a[0].typ), tmp, c.genType(a.sons[0].typ)) c.freeTemp(tmp) else: genAsgn(c, a.sons[0], a.sons[2], true) @@ -1208,7 +1206,7 @@ proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) = if n.len > 0: let intType = getSysType(tyInt) var tmp = getTemp(c, intType) - c.gABx(n, opcLdNull, tmp, c.genType(intType)) + c.gABx(n, opcLdNullReg, tmp, c.genType(intType)) for x in n: let a = c.genx(x) c.gABC(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a) @@ -1320,8 +1318,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = of nkDotExpr: genObjAccess(c, n, dest, flags) of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags) of nkBracketExpr: genArrAccess(c, n, dest, flags) - of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcDeref, flags) - of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddr, flags) + of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcLdDeref, flags) + of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddrNode, flags) of nkWhenStmt, nkIfStmt, nkIfExpr: genIf(c, n, dest) of nkCaseStmt: genCase(c, n, dest) of nkWhileStmt: -- cgit 1.4.1-2-gfad0 From ee74706c3b1e040dded3baf2ee3c05ae111c968a Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 22 Feb 2014 01:09:43 +0100 Subject: fixed opcConv --- compiler/astalgo.nim | 10 ++++++++-- compiler/vm.nim | 32 +++++++++++++++++++++++++------- compiler/vmgen.nim | 5 ++--- todo.txt | 1 - 4 files changed, 35 insertions(+), 13 deletions(-) (limited to 'compiler/vmgen.nim') diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 64c1b717c..cce2cc215 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -337,7 +337,10 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int, appf(result, ",$N$1\"floatVal\": $2", [istr, toRope(n.floatVal.toStrMaxPrecision)]) of nkStrLit..nkTripleStrLit: - appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) + if n.strVal.isNil: + appf(result, ",$N$1\"strVal\": null", [istr]) + else: + appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) of nkSym: appf(result, ",$N$1\"sym\": $2", [istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)]) @@ -407,7 +410,10 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope = appf(result, ",$N$1\"floatVal\": $2", [istr, toRope(n.floatVal.toStrMaxPrecision)]) of nkStrLit..nkTripleStrLit: - appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) + if n.strVal.isNil: + appf(result, ",$N$1\"strVal\": null", [istr]) + else: + appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) of nkSym: appf(result, ",$N$1\"sym\": $2_$3", [istr, toRope(n.sym.name.s), toRope(n.sym.id)]) diff --git a/compiler/vm.nim b/compiler/vm.nim index 8480cd1c6..f17da1c69 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -257,11 +257,25 @@ proc opConv*(dest: var TRegister, src: TRegister, desttyp, srctyp: PType): bool myreset(dest) dest.kind = rkStr dest.node = newNode(nkStrLit) - case srctyp.skipTypes(abstractRange).kind - of tyEnum: - dest.node.strVal = "too implement" #ordinalValToString(src) - of tyInt..tyInt64, tyUInt..tyUInt64: + let styp = srctyp.skipTypes(abstractRange) + case styp.kind + of tyEnum: + let n = styp.n + let x = src.intVal.int + if x <% n.len and (let f = n.sons[x].sym; f.position == x): + dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal + else: + for i in 0.. Date: Mon, 24 Feb 2014 01:30:40 +0100 Subject: new VM is getting stable --- compiler/msgs.nim | 4 ++-- compiler/rodread.nim | 2 +- compiler/sem.nim | 2 +- compiler/semexprs.nim | 4 ++++ compiler/semstmts.nim | 9 +++++--- compiler/vm.nim | 50 +++++++++++++++++++++++++++------------- compiler/vmdef.nim | 3 +-- compiler/vmgen.nim | 59 +++++++++++++++++++++++++++++++++++++++--------- tests/macros/tmacro5.nim | 2 +- todo.txt | 2 -- 10 files changed, 98 insertions(+), 39 deletions(-) (limited to 'compiler/vmgen.nim') diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 268205361..ae673bd0e 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -67,7 +67,7 @@ type errAmbiguousCallXYZ, errWrongNumberOfArguments, errXCannotBePassedToProcVar, errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed, - errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValue, + errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX, errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice, errInvalidOrderInArrayConstructor, errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry, @@ -264,7 +264,7 @@ const errImplOfXNotAllowed: "implementation of \'$1\' is not allowed", errImplOfXexpected: "implementation of \'$1\' expected", errNoSymbolToBorrowFromFound: "no symbol to borrow from found", - errDiscardValue: "value returned by statement has to be discarded", + errDiscardValueX: "value of type '$1' has to be discarded", errInvalidDiscard: "statement returns no value that can be discarded", errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid", errCannotBindXTwice: "cannot bind parameter \'$1\' twice", diff --git a/compiler/rodread.nim b/compiler/rodread.nim index b53135a95..036e6cc3c 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -890,7 +890,7 @@ proc loadStub*(s: PSym) = # deactivate the GC here because we do a deep recursion and generate no # garbage when restoring parts of the object graph anyway. - # Since we die with internal errors if this fails, so no try-finally is + # Since we die with internal errors if this fails, no try-finally is # necessary. GC_disable() rawLoadStub(s) diff --git a/compiler/sem.nim b/compiler/sem.nim index 09b2511f1..5ee46654e 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -220,7 +220,7 @@ proc tryConstExpr(c: PContext, n: PNode): PNode = return nil result = fixupTypeAfterEval(c, result, e) - except: + except ERecoverableError: return nil proc semConstExpr(c: PContext, n: PNode): PNode = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c271911ab..538489490 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -641,9 +641,11 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = result = evalStaticExpr(c.module, call, c.p.owner) if result.isNil: localError(n.info, errCannotInterpretNodeX, renderTree(call)) + else: result = fixupTypeAfterEval(c, result, n) else: result = evalConstExpr(c.module, call) if result.isNil: result = n + else: result = fixupTypeAfterEval(c, result, n) #if result != n: # echo "SUCCESS evaluated at compile time: ", call.renderTree @@ -653,6 +655,8 @@ proc semStaticExpr(c: PContext, n: PNode): PNode = if result.isNil: localError(n.info, errCannotInterpretNodeX, renderTree(n)) result = emptyNode + else: + result = fixupTypeAfterEval(c, result, a) proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, flags: TExprFlags): PNode = diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 503ea4bc1..1a2f9a6a6 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -126,7 +126,7 @@ proc implicitlyDiscardable(n: PNode): bool = proc fixNilType(n: PNode) = if isAtom(n): if n.kind != nkNilLit and n.typ != nil: - localError(n.info, errDiscardValue) + localError(n.info, errDiscardValueX, n.typ.typeToString) elif n.kind in {nkStmtList, nkStmtListExpr}: n.kind = nkStmtList for it in n: fixNilType(it) @@ -154,7 +154,7 @@ proc discardCheck(c: PContext, result: PNode) = else: var n = result while n.kind in skipForDiscardable: n = n.lastSon - localError(n.info, errDiscardValue) + localError(n.info, errDiscardValueX, result.typ.typeToString) proc semIf(c: PContext, n: PNode): PNode = result = n @@ -331,6 +331,7 @@ proc checkNilable(v: PSym) = proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var b: PNode result = copyNode(n) + var hasCompileTime = false for i in countup(0, sonsLen(n)-1): var a = n.sons[i] if gCmd == cmdIdeTools: suggestStmt(c, a) @@ -405,7 +406,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = v.typ = tup.sons[j] b.sons[j] = newSymNode(v) checkNilable(v) - + if sfCompileTime in v.flags: hasCompileTime = true + if hasCompileTime: vm.setupCompileTimeVar(c.module, result) + proc semConst(c: PContext, n: PNode): PNode = result = copyNode(n) for i in countup(0, sonsLen(n) - 1): diff --git a/compiler/vm.nim b/compiler/vm.nim index 820a2022c..6277b2dc6 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -109,11 +109,17 @@ template decodeBx(k: expr) {.immediate, dirty.} = template move(a, b: expr) {.immediate, dirty.} = system.shallowCopy(a, b) # XXX fix minor 'shallowCopy' overloading bug in compiler -template createStr(x) = - if x.node.isNil: x.node = newNode(nkStrLit) +template createStrKeepNode(x) = + if x.node.isNil: + x.node = newNode(nkStrLit) elif x.node.kind == nkNilLit: system.reset(x.node[]) x.node.kind = nkStrLit + else: + assert x.node.kind in {nkStrLit..nkTripleStrLit} + +template createStr(x) = + x.node = newNode(nkStrLit) proc moveConst(x: var TRegister, y: TRegister) = if x.kind != y.kind: @@ -254,7 +260,7 @@ proc opConv*(dest: var TRegister, src: TRegister, desttyp, srctyp: PType): bool if dest.kind != rkNode: myreset(dest) dest.kind = rkNode - dest.node = newNode(nkStrLit) + dest.node = newNode(nkStrLit) let styp = srctyp.skipTypes(abstractRange) case styp.kind of tyEnum: @@ -329,8 +335,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister = #{.computedGoto.} let instr = c.code[pc] let ra = instr.regA - #echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra - #message(c.debug[pc], warnUser, "gah") + #if c.traceActive: + # echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra + # message(c.debug[pc], warnUser, "Trace") case instr.opcode of opcEof: return regs[ra] of opcRet: @@ -354,7 +361,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister = regs[ra].intVal = regs[rb].intVal of opcAsgnStr: decodeB(rkNode) - createStr regs[ra] + createStrKeepNode regs[ra] regs[ra].node.strVal = regs[rb].node.strVal of opcAsgnFloat: decodeB(rkFloat) @@ -454,7 +461,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister = of opcWrDeref: # a[] = b decodeBC(rkNode) - putIntoNode(regs[ra].node, regs[rc]) + putIntoNode(regs[ra].node, regs[rb]) of opcAddInt: decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal + regs[rc].intVal @@ -484,8 +491,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister = of opcInclRange: decodeBC(rkNode) var r = newNode(nkRange) - r.add regs[rb].node - r.add regs[rc].node + r.add regs[rb].regToNode + r.add regs[rc].regToNode addSon(regs[ra].node, r.copyTree) of opcExcl: decodeB(rkNode) @@ -643,15 +650,18 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister = regs[ra].node.strVal.add getstr(regs[i]) of opcAddStrCh: decodeB(rkNode) - createStr regs[ra] + createStrKeepNode regs[ra] regs[ra].node.strVal.add(regs[rb].intVal.chr) of opcAddStrStr: decodeB(rkNode) - createStr regs[ra] + createStrKeepNode regs[ra] regs[ra].node.strVal.add(regs[rb].node.strVal) of opcAddSeqElem: decodeB(rkNode) - regs[ra].node.add(copyTree(regs[rb].node)) + if regs[ra].node.kind == nkBracket: + regs[ra].node.add(copyTree(regs[rb].regToNode)) + else: + stackTrace(c, tos, pc, errNilAccess) of opcEcho: let rb = instr.regB for i in ra..ra+rb-1: @@ -660,7 +670,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister = writeln(stdout, "") of opcContainsSet: decodeBC(rkInt) - regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].node)) + regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode)) of opcSubStr: decodeBC(rkNode) inc pc @@ -815,8 +825,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister = ensureKind(rkNode) let typ = c.types[instr.regBx - wordExcess] regs[ra].node = getNullValue(typ, c.debug[pc]) - if regs[ra].node.kind in {nkStrLit..nkTripleStrLit}: - regs[ra].kind = rkNode + # opcLdNull really is the gist of the VM's problems: should it load + # a fresh null to regs[ra].node or to regs[ra].node[]? This really + # depends on whether regs[ra] represents the variable itself or wether + # it holds the indirection! Due to the way registers are re-used we cannot + # say for sure here! --> The codegen has to deal with it + # via 'genAsgnPatch'. of opcLdNullReg: let typ = c.types[instr.regBx - wordExcess] if typ.skipTypes(abstractInst+{tyRange}-{tyTypeDesc}).kind in { @@ -858,7 +872,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister = return TRegister(kind: rkNone) of opcSetLenStr: decodeB(rkNode) - createStr regs[ra] + createStrKeepNode regs[ra] regs[ra].node.strVal.setLen(regs[rb].intVal.int) of opcOf: decodeBC(rkInt) @@ -1209,6 +1223,9 @@ proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode = proc evalStaticStmt*(module: PSym, e: PNode, prc: PSym) = discard evalConstExprAux(module, prc, e, emStaticStmt) +proc setupCompileTimeVar*(module: PSym, n: PNode) = + discard evalConstExprAux(module, nil, n, emStaticStmt) + proc setupMacroParam(x: PNode): PNode = result = x if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1] @@ -1250,3 +1267,4 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode = if cyclicTree(result): globalError(n.info, errCyclicTree) dec(evalMacroCounter) c.callsite = nil + #debug result diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index ea7c94856..72689c879 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -163,8 +163,6 @@ type blocks*: seq[TBlock] # blocks; temp data structure slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]] maxSlots*: int - globals*: array[TRegister, int] # hack: to support passing globals byref - # we map a slot persistently to a global PCtx* = ref TCtx TCtx* = object of passes.TPassContext # code gen context @@ -181,6 +179,7 @@ type callsite*: PNode mode*: TEvalMode features*: TSandboxFlags + traceActive*: bool TPosition* = distinct int diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index cddda7bd3..b594c00a9 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -451,9 +451,11 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) = c.gABC(n, opcIndCallAsgn, dest, x, n.len) c.freeTempRange(x, n.len) +template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar + proc needsAsgnPatch(n: PNode): bool = n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr, - nkDerefExpr, nkHiddenDeref} + nkDerefExpr, nkHiddenDeref} or (n.kind == nkSym and n.sym.isGlobal) proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) = case le.kind @@ -461,15 +463,25 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) = let dest = c.genx(le.sons[0], {gfAddrOf}) let idx = c.genx(le.sons[1]) c.gABC(le, opcWrArr, dest, idx, value) + c.freeTemp(dest) + c.freeTemp(idx) of nkDotExpr, nkCheckedFieldExpr: # XXX field checks here let left = if le.kind == nkDotExpr: le else: le.sons[0] let dest = c.genx(left.sons[0], {gfAddrOf}) let idx = c.genx(left.sons[1]) c.gABC(left, opcWrObj, dest, idx, value) + c.freeTemp(dest) + c.freeTemp(idx) of nkDerefExpr, nkHiddenDeref: let dest = c.genx(le.sons[0], {gfAddrOf}) c.gABC(le, opcWrDeref, dest, value) + c.freeTemp(dest) + of nkSym: + if le.sym.isGlobal: + let dest = c.genx(le, {gfAddrOf}) + c.gABC(le, opcWrDeref, dest, value) + c.freeTemp(dest) else: discard @@ -608,6 +620,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) = c.genAddSubInt(n, dest, opcAddInt) of mInc, mDec: unused(n, dest) + # XXX generates inefficient code for globals var d = c.genx(n.sons[1]).TDest c.genAddSubInt(n, d, if m == mInc: opcAddInt else: opcSubInt) c.genAsgnPatch(n.sons[1], d) @@ -621,6 +634,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) = c.genNewSeq(n) of mNewString: genUnaryABC(c, n, dest, opcNewStr) + # XXX buggy of mNewStringOfCap: # we ignore the 'cap' argument and translate it as 'newString(0)'. # eval n.sons[1] for possible side effects: @@ -629,6 +643,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) = if dest < 0: dest = c.getTemp(n.typ) c.gABC(n, opcNewStr, dest, tmp) c.freeTemp(tmp) + # XXX buggy of mLengthOpenArray, mLengthArray, mLengthSeq: genUnaryABI(c, n, dest, opcLenSeq) of mLengthStr: @@ -955,8 +970,6 @@ proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) = gABC(c, ri, whichAsgnOpc(ri), dest, tmp) c.freeTemp(tmp) -template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar - proc setSlot(c: PCtx; v: PSym) = # XXX generate type initialization here? if v.position == 0: @@ -1035,14 +1048,22 @@ proc cannotEval(n: PNode) {.noinline.} = globalError(n.info, errGenerated, "cannot evaluate at compile time: " & n.renderTree) +proc getNullValue*(typ: PType, info: TLineInfo): PNode + proc genGlobalInit(c: PCtx; n: PNode; s: PSym) = - c.globals.add(emptyNode.copyNode) + c.globals.add(getNullValue(s.typ, n.info)) s.position = c.globals.len # This is rather hard to support, due to the laziness of the VM code # generator. See tests/compile/tmacro2 for why this is necesary: # var decls{.compileTime.}: seq[PNimrodNode] = @[] + let dest = c.getTemp(s.typ) + c.gABx(n, opcLdGlobal, dest, s.position) + let tmp = c.genx(s.ast) + c.gABC(n, opcWrDeref, dest, tmp) + c.freeTemp(dest) + c.freeTemp(tmp) -proc genRdVar(c: PCtx; n: PNode; dest: var TDest) = +proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = let s = n.sym if s.isGlobal: if sfCompileTime in s.flags or c.mode == emRepl: @@ -1052,7 +1073,14 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) = if s.position == 0: if sfImportc in s.flags: c.importcSym(n.info, s) else: genGlobalInit(c, n, s) - c.gABx(n, opcLdGlobal, dest, s.position) + if dest < 0: dest = c.getTemp(n.typ) + if gfAddrOf notin flags and fitsRegister(s.typ): + var cc = c.getTemp(n.typ) + c.gABx(n, opcLdGlobal, cc, s.position) + c.gABC(n, opcNodeToReg, dest, cc) + c.freeTemp(cc) + else: + c.gABx(n, opcLdGlobal, dest, s.position) else: if s.kind == skForVar and c.mode == emRepl: c.setSlot s if s.position > 0 or (s.position == 0 and @@ -1095,7 +1123,6 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = else: genAccess(c, n, dest, opcLdArr, flags) -proc getNullValue*(typ: PType, info: TLineInfo): PNode proc getNullValueAux(obj: PNode, result: PNode) = case obj.kind of nkRecList: @@ -1161,7 +1188,7 @@ proc genVarSection(c: PCtx; n: PNode) = setSlot(c, a[i].sym) # v = t[i] var v: TDest = -1 - genRdVar(c, a[i], v) + genRdVar(c, a[i], v, {gfAddrOf}) c.gABC(n, opcWrObj, v, tmp, i) # XXX globals? c.freeTemp(tmp) @@ -1184,6 +1211,7 @@ proc genVarSection(c: PCtx; n: PNode) = let val = c.genx(a.sons[2]) c.gABC(a, opcWrDeref, tmp, val) c.freeTemp(val) + c.freeTemp(tmp) else: setSlot(c, s) if a.sons[2].kind == nkEmpty: @@ -1202,8 +1230,17 @@ proc genVarSection(c: PCtx; n: PNode) = proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) = if dest < 0: dest = c.getTemp(n.typ) c.gABx(n, opcLdNull, dest, c.genType(n.typ)) + + let intType = getSysType(tyInt) + let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc}) + if seqType.kind == tySequence: + var tmp = c.getTemp(intType) + c.gABx(n, opcLdImmInt, tmp, n.len) + c.gABx(n, opcNewSeq, dest, c.genType(seqType)) + c.gABx(n, opcNewSeq, tmp, 0) + c.freeTemp(tmp) + if n.len > 0: - let intType = getSysType(tyInt) var tmp = getTemp(c, intType) c.gABx(n, opcLdNullReg, tmp, c.genType(intType)) for x in n: @@ -1271,7 +1308,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = let s = n.sym case s.kind of skVar, skForVar, skTemp, skLet, skParam, skResult: - genRdVar(c, n, dest) + genRdVar(c, n, dest, flags) of skProc, skConverter, skMacro, skTemplate, skMethod, skIterator: # 'skTemplate' is only allowed for 'getAst' support: if sfImportc in s.flags: c.importcSym(n.info, s) @@ -1503,7 +1540,7 @@ proc genProc(c: PCtx; s: PSym): int = c.gABC(body, opcEof, eofInstr.regA) c.optimizeJumps(result) s.offset = c.prc.maxSlots - #if s.name.s == "traverse": + #if s.name.s == "importImpl_forward" or s.name.s == "importImpl": # c.echoCode(result) # echo renderTree(body) c.prc = oldPrc diff --git a/tests/macros/tmacro5.nim b/tests/macros/tmacro5.nim index 39324e497..9882ad90d 100644 --- a/tests/macros/tmacro5.nim +++ b/tests/macros/tmacro5.nim @@ -51,7 +51,7 @@ macro okayy:stmt = for node in decls: result.add node for node in impls: result.add node -importimpl(Item, int): +importImpl(Item, int): echo 42 importImpl(Foo, int16): echo 77 diff --git a/todo.txt b/todo.txt index 7009d9a84..4bee45516 100644 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,6 @@ version 0.9.4 ============= -- fix macros\tstringinterp.nim - fix GC issues - test and fix showoff @@ -24,7 +23,6 @@ version 0.9.x - implement 'union' and 'bits' pragmas - fix closures -- test and fix exception handling - ensure (ref T)(a, b) works as a type conversion and type constructor - optimize 'genericReset'; 'newException' leads to code bloat - stack-less GC -- cgit 1.4.1-2-gfad0