VM: support importc var, ptr/pointer types, cast int <=> ptr/pointer (#12877)

* VM: allow certain hardcoded special var variables at CT
* VM: allow all importc var, cast[int](ptr)
* fix tests tests/vm/tstaticprintseq.nim, tests/cpp/t8241.nim
* VM: == works for ptr/pointer nodes
* bugfix: ==, cast now also works for pointer, not just ptr
* VM supports cast PtrLikeKinds <=> PtrLikeKinds / int
* improve cname handling
* fixup + bug fix
* VM: support cast from ref to int
* address comment: opcLdGlobalDeref => opcLdGlobalDerefFFI
* defensive check against typ == nil
This commit is contained in:
Timothee Cour 2020-01-05 00:11:29 -08:00 • committed by Andreas Rumpf
commit 13c08f3ab4
7 changed files with 199 additions and 35 deletions

View file

@ -885,8 +885,21 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
c.gABC(n, opcCastFloatToInt64, dest, tmp)
# narrowing for 64 bits not needed (no extended sign bits available).
c.freeTemp(tmp)
elif src.kind in PtrLikeKinds + {tyRef} and dst.kind == tyInt:
let tmp = c.genx(n[1])
if dest < 0: dest = c.getTemp(n[0].typ)
var imm: BiggestInt = if src.kind in PtrLikeKinds: 1 else: 2
c.gABI(n, opcCastPtrToInt, dest, tmp, imm)
c.freeTemp(tmp)
elif src.kind in PtrLikeKinds + {tyInt} and dst.kind in PtrLikeKinds:
let tmp = c.genx(n[1])
if dest < 0: dest = c.getTemp(n[0].typ)
c.gABx(n, opcSetType, dest, c.genType(dst))
c.gABC(n, opcCastIntToPtr, dest, tmp)
c.freeTemp(tmp)
else:
globalError(c.config, n.info, "VM is only allowed to 'cast' between integers and/or floats of same size")
# todo: support cast from tyInt to tyRef
globalError(c.config, n.info, "VM does not support 'cast' from " & $src.kind & " to " & $dst.kind)
proc genVoidABC(c: PCtx, n: PNode, dest: TDest, opcode: TOpcode) =
unused(c, n, dest)
@ -1474,11 +1487,17 @@ proc getOwner(c: PCtx): PSym =
result = c.prc.sym
if result.isNil: result = c.module
proc importcCondVar*(s: PSym): bool {.inline.} =
# see also importcCond
if sfImportc in s.flags:
return s.kind in {skVar, skLet, skConst}
proc checkCanEval(c: PCtx; n: PNode) =
# we need to ensure that we don't evaluate 'x' here:
# proc foo() = var x ...
let s = n.sym
if {sfCompileTime, sfGlobal} <= s.flags: return
if s.importcCondVar: return
if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
not s.isOwnedBy(c.prc.sym) and s.owner != c.module and c.mode != emRepl:
# little hack ahead for bug #12612: assume gensym'ed variables
@ -1618,17 +1637,24 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
assert card(flags * {gfNodeAddr, gfNode}) < 2
let s = n.sym
if s.isGlobal:
if sfCompileTime in s.flags or c.mode == emRepl:
let isImportcVar = importcCondVar(s)
if sfCompileTime in s.flags or c.mode == emRepl or isImportcVar:
discard
elif s.position == 0:
cannotEval(c, n)
if s.position == 0:
if importcCond(s): c.importcSym(n.info, s)
if importcCond(s) or isImportcVar: c.importcSym(n.info, s)
else: genGlobalInit(c, n, s)
if dest < 0: dest = c.getTemp(n.typ)
assert s.typ != nil
if gfNodeAddr in flags:
c.gABx(n, opcLdGlobalAddr, dest, s.position)
if isImportcVar:
c.gABx(n, opcLdGlobalAddrDerefFFI, dest, s.position)
else:
c.gABx(n, opcLdGlobalAddr, dest, s.position)
elif isImportcVar:
c.gABx(n, opcLdGlobalDerefFFI, dest, s.position)
elif fitsRegister(s.typ) and gfNode notin flags:
var cc = c.getTemp(n.typ)
c.gABx(n, opcLdGlobal, cc, s.position)