diff options
Diffstat (limited to 'compiler/vmgen.nim')
-rw-r--r-- | compiler/vmgen.nim | 157 |
1 files changed, 123 insertions, 34 deletions
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index e612d7a2a..1f2a3e6d1 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -29,7 +29,7 @@ import strutils, ast, astalgo, types, msgs, renderer, vmdef, - trees, intsets, magicsys, options, lowerings, lineinfos + trees, intsets, magicsys, options, lowerings, lineinfos, transf import platform from os import splitFile @@ -182,7 +182,10 @@ const HighRegisterPressure = 40 proc bestEffort(c: PCtx): TLineInfo = - (if c.prc == nil: c.module.info else: c.prc.sym.info) + if c.prc != nil and c.prc.sym != nil: + c.prc.sym.info + else: + c.module.info proc getTemp(cc: PCtx; tt: PType): TRegister = let typ = tt.skipTypesOrNil({tyStatic}) @@ -562,6 +565,8 @@ proc genIndex(c: PCtx; n: PNode; arr: PType): TRegister = else: result = c.genx(n) +proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) + proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) = case le.kind of nkBracketExpr: @@ -570,12 +575,16 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) = 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], {gfNode}) - let idx = genField(c, left.sons[1]) - c.gABC(left, opcWrObj, dest, idx, value) + of nkCheckedFieldExpr: + var objR: TDest = -1 + genCheckedObjAccessAux(c, le, objR, {gfNode}) + let idx = genField(c, le[0].sons[1]) + c.gABC(le[0], opcWrObj, objR, idx, value) + c.freeTemp(objR) + of nkDotExpr: + let dest = c.genx(le.sons[0], {gfNode}) + let idx = genField(c, le.sons[1]) + c.gABC(le, opcWrObj, dest, idx, value) c.freeTemp(dest) of nkDerefExpr, nkHiddenDeref: let dest = c.genx(le.sons[0], {gfNode}) @@ -763,18 +772,18 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) = c.gABC(n, opcCard, dest, tmp) c.freeTemp(tmp) -proc genIntCast(c: PCtx; n: PNode; dest: var TDest) = +proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) = const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar} var signedIntegers = {tyInt8..tyInt32} var unsignedIntegers = {tyUInt8..tyUInt32, tyChar} let src = n.sons[1].typ.skipTypes(abstractRange)#.kind let dst = n.sons[0].typ.skipTypes(abstractRange)#.kind let src_size = getSize(c.config, src) - + let dst_size = getSize(c.config, dst) if c.config.target.intSize < 8: signedIntegers.incl(tyInt) unsignedIntegers.incl(tyUInt) - if src_size == getSize(c.config, dst) and src.kind in allowedIntegers and + if src_size == dst_size and src.kind in allowedIntegers and dst.kind in allowedIntegers: let tmp = c.genx(n.sons[1]) var tmp2 = c.getTemp(n.sons[1].typ) @@ -803,8 +812,28 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) = c.freeTemp(tmp) c.freeTemp(tmp2) c.freeTemp(tmp3) + elif src_size == dst_size and src.kind in allowedIntegers and + dst.kind in {tyFloat, tyFloat32, tyFloat64}: + let tmp = c.genx(n[1]) + if dest < 0: dest = c.getTemp(n[0].typ) + if dst.kind == tyFloat32: + c.gABC(n, opcAsgnFloat32FromInt, dest, tmp) + else: + c.gABC(n, opcAsgnFloat64FromInt, dest, tmp) + c.freeTemp(tmp) + + elif src_size == dst_size and src.kind in {tyFloat, tyFloat32, tyFloat64} and + dst.kind in allowedIntegers: + let tmp = c.genx(n[1]) + if dest < 0: dest = c.getTemp(n[0].typ) + if src.kind == tyFloat32: + c.gABC(n, opcAsgnIntFromFloat32, dest, tmp) + else: + c.gABC(n, opcAsgnIntFromFloat64, dest, tmp) + c.freeTemp(tmp) + else: - globalError(c.config, n.info, "VM is only allowed to 'cast' between integers of same size") + globalError(c.config, n.info, "VM is only allowed to 'cast' between integers and/or floats of same size") proc genVoidABC(c: PCtx, n: PNode, dest: TDest, opcode: TOpcode) = unused(c, n, dest) @@ -1069,13 +1098,11 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = var tmp = c.genx(n.sons[1]) var idx = c.getTemp(getSysType(c.graph, n.info, tyInt)) var typ = n.sons[2].typ - if m == mOf: typ = typ.skipTypes(abstractPtrs-{tyTypeDesc}) + if m == mOf: typ = typ.skipTypes(abstractPtrs) c.gABx(n, opcLdImmInt, idx, c.genType(typ)) c.gABC(n, if m == mOf: opcOf else: opcIs, dest, tmp, idx) c.freeTemp(tmp) c.freeTemp(idx) - of mSizeOf: - globalError(c.config, n.info, "cannot run in the VM: " & renderTree(n)) of mHigh: if dest < 0: dest = c.getTemp(n.typ) let tmp = c.genx(n.sons[1]) @@ -1088,13 +1115,14 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mEcho: unused(c, n, dest) let n = n[1].skipConv - let x = c.getTempRange(n.len, slotTempUnknown) - internalAssert c.config, n.kind == nkBracket - for i in 0..<n.len: - var r: TRegister = x+i - c.gen(n.sons[i], r) - c.gABC(n, opcEcho, x, n.len) - c.freeTempRange(x, n.len) + if n.kind == nkBracket: + # can happen for nim check, see bug #9609 + let x = c.getTempRange(n.len, slotTempUnknown) + for i in 0..<n.len: + var r: TRegister = x+i + c.gen(n.sons[i], r) + c.gABC(n, opcEcho, x, n.len) + c.freeTempRange(x, n.len) of mAppendStrCh: unused(c, n, dest) genBinaryStmtVar(c, n, opcAddStrCh) @@ -1118,7 +1146,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mStaticExec: genBinaryABCD(c, n, dest, opcGorge) of mNLen: genUnaryABI(c, n, dest, opcLenSeq, nimNodeFlag) of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl) + of mGetImplTransf: genUnaryABC(c, n, dest, opcGetImplTransf) of mSymOwner: genUnaryABC(c, n, dest, opcSymOwner) + of mSymIsInstantiationOf: genBinaryABC(c, n, dest, opcSymIsInstantiationOf) of mNChild: genBinaryABC(c, n, dest, opcNChild) of mNSetChild: genVoidABC(c, n, dest, opcNSetChild) of mNDel: genVoidABC(c, n, dest, opcNDel) @@ -1209,8 +1239,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = if dest < 0: dest = c.getTemp(n.typ) c.gABC(n, opcCallSite, dest) of mNGenSym: genBinaryABC(c, n, dest, opcGenSym) - of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI, - mDotDot: + of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI, mDotDot: c.genCall(n, dest) of mExpandToAst: if n.len != 2: @@ -1225,8 +1254,11 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = # produces a value else: globalError(c.config, n.info, "expandToAst requires a call expression") + of mSizeOf, mAlignOf: + globalError(c.config, n.info, "cannot evaluate 'sizeof/alignof' because its type is not defined completely") of mRunnableExamples: discard "just ignore any call to runnableExamples" + of mDestroy: discard "ignore calls to the default destructor" else: # mGCref, mGCunref, globalError(c.config, n.info, "cannot generate code for: " & $m) @@ -1419,13 +1451,19 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = else: c.preventFalseAlias(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], {gfNode}) - let idx = genField(c, left.sons[1]) + of nkCheckedFieldExpr: + var objR: TDest = -1 + genCheckedObjAccessAux(c, le, objR, {gfNode}) + let idx = genField(c, le[0].sons[1]) + let tmp = c.genx(ri) + c.preventFalseAlias(le[0], opcWrObj, objR, idx, tmp) + c.freeTemp(tmp) + c.freeTemp(objR) + of nkDotExpr: + let dest = c.genx(le.sons[0], {gfNode}) + let idx = genField(c, le.sons[1]) let tmp = c.genx(ri) - c.preventFalseAlias(left, opcWrObj, dest, idx, tmp) + c.preventFalseAlias(le, opcWrObj, dest, idx, tmp) c.freeTemp(tmp) of nkDerefExpr, nkHiddenDeref: let dest = c.genx(le.sons[0], {gfNode}) @@ -1561,9 +1599,59 @@ proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = c.gABC(n, opcLdObj, dest, a, b) c.freeTemp(a) +proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = + internalAssert c.config, n.kind == nkCheckedFieldExpr + # nkDotExpr to access the requested field + let accessExpr = n[0] + # nkCall to check if the discriminant is valid + var checkExpr = n[1] + + let negCheck = checkExpr[0].sym.magic == mNot + if negCheck: + checkExpr = checkExpr[^1] + + # Discriminant symbol + let disc = checkExpr[2] + internalAssert c.config, disc.sym.kind == skField + + # Load the object in `dest` + c.gen(accessExpr[0], dest, flags) + # Load the discriminant + var discVal = c.getTemp(disc.typ) + c.gABC(n, opcLdObj, discVal, dest, genField(c, disc)) + # Check if its value is contained in the supplied set + let setLit = c.genx(checkExpr[1]) + var rs = c.getTemp(getSysType(c.graph, n.info, tyBool)) + c.gABC(n, opcContainsSet, rs, setLit, discVal) + c.freeTemp(setLit) + # If the check fails let the user know + let L1 = c.xjmp(n, if negCheck: opcFJmp else: opcTJmp, rs) + c.freeTemp(rs) + # Not ideal but will do for the moment + c.gABC(n, opcQuit) + c.patch(L1) + proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = - # XXX implement field checks! - genObjAccess(c, n.sons[0], dest, flags) + var objR: TDest = -1 + genCheckedObjAccessAux(c, n, objR, flags) + + let accessExpr = n[0] + # Field symbol + var field = accessExpr[1] + internalAssert c.config, field.sym.kind == skField + + # Load the content now + if dest < 0: dest = c.getTemp(n.typ) + let fieldPos = genField(c, field) + if needsRegLoad(): + var cc = c.getTemp(accessExpr.typ) + c.gABC(n, opcLdObj, cc, objR, fieldPos) + c.gABC(n, opcNodeToReg, dest, cc) + c.freeTemp(cc) + else: + c.gABC(n, opcLdObj, dest, objR, fieldPos) + + c.freeTemp(objR) proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = let arrayType = n.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind @@ -1945,7 +2033,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = if allowCast in c.features: genConv(c, n, n.sons[1], dest, opcCast) else: - genIntCast(c, n, dest) + genCastIntFloat(c, n, dest) of nkTypeOfExpr: genTypeLit(c, n.typ, dest) of nkComesFrom: @@ -2067,7 +2155,8 @@ proc genProc(c: PCtx; s: PSym): int = s.ast.sons[miscPos] = x # thanks to the jmp we can add top level statements easily and also nest # procs easily: - let body = s.getBody + let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s), + noDestructors = true) let procStart = c.xjmp(body, opcJmp, 0) var p = PProc(blocks: @[], sym: s) let oldPrc = c.prc |