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:
parent
a1beeb313f
commit
13c08f3ab4
7 changed files with 199 additions and 35 deletions
|
|
@ -469,6 +469,7 @@ type
|
||||||
nfExplicitCall # x.y() was used instead of x.y
|
nfExplicitCall # x.y() was used instead of x.y
|
||||||
nfExprCall # this is an attempt to call a regular expression
|
nfExprCall # this is an attempt to call a regular expression
|
||||||
nfIsRef # this node is a 'ref' node; used for the VM
|
nfIsRef # this node is a 'ref' node; used for the VM
|
||||||
|
nfIsPtr # this node is a 'ptr' node; used for the VM
|
||||||
nfPreventCg # this node should be ignored by the codegen
|
nfPreventCg # this node should be ignored by the codegen
|
||||||
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
|
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
|
||||||
nfFromTemplate # a top-level node returned from a template
|
nfFromTemplate # a top-level node returned from a template
|
||||||
|
|
@ -856,6 +857,9 @@ type
|
||||||
loc*: TLoc
|
loc*: TLoc
|
||||||
annex*: PLib # additional fields (seldom used, so we use a
|
annex*: PLib # additional fields (seldom used, so we use a
|
||||||
# reference to another object to save space)
|
# reference to another object to save space)
|
||||||
|
when hasFFI:
|
||||||
|
cname*: string # resolved C declaration name in importc decl, eg:
|
||||||
|
# proc fun() {.importc: "$1aux".} => cname = funaux
|
||||||
constraint*: PNode # additional constraints like 'lit|result'; also
|
constraint*: PNode # additional constraints like 'lit|result'; also
|
||||||
# misused for the codegenDecl pragma in the hope
|
# misused for the codegenDecl pragma in the hope
|
||||||
# it won't cause problems
|
# it won't cause problems
|
||||||
|
|
@ -978,12 +982,13 @@ const
|
||||||
tyTuple, tySequence}
|
tyTuple, tySequence}
|
||||||
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr,
|
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr,
|
||||||
tyProc, tyError}
|
tyProc, tyError}
|
||||||
|
PtrLikeKinds*: TTypeKinds = {tyPointer, tyPtr} # for VM
|
||||||
ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType,
|
ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType,
|
||||||
skIterator,
|
skIterator,
|
||||||
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
|
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
|
||||||
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
|
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
|
||||||
nfDotSetter, nfDotField,
|
nfDotSetter, nfDotField,
|
||||||
nfIsRef, nfPreventCg, nfLL,
|
nfIsRef, nfIsPtr, nfPreventCg, nfLL,
|
||||||
nfFromTemplate, nfDefaultRefsParam,
|
nfFromTemplate, nfDefaultRefsParam,
|
||||||
nfExecuteOnReload}
|
nfExecuteOnReload}
|
||||||
namePos* = 0
|
namePos* = 0
|
||||||
|
|
|
||||||
|
|
@ -700,7 +700,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||||
|
|
||||||
proc mangleDynLibProc(sym: PSym): Rope =
|
proc mangleDynLibProc(sym: PSym): Rope =
|
||||||
# we have to build this as a single rope in order not to trip the
|
# we have to build this as a single rope in order not to trip the
|
||||||
# optimization in genInfixCall
|
# optimization in genInfixCall, see test tests/cpp/t8241.nim
|
||||||
if sfCompilerProc in sym.flags:
|
if sfCompilerProc in sym.flags:
|
||||||
# NOTE: sym.loc.r is the external name!
|
# NOTE: sym.loc.r is the external name!
|
||||||
result = rope(sym.name.s)
|
result = rope(sym.name.s)
|
||||||
|
|
|
||||||
|
|
@ -46,19 +46,12 @@ proc getDll(conf: ConfigRef, cache: var TDllCache; dll: string; info: TLineInfo)
|
||||||
const
|
const
|
||||||
nkPtrLit = nkIntLit # hopefully we can get rid of this hack soon
|
nkPtrLit = nkIntLit # hopefully we can get rid of this hack soon
|
||||||
|
|
||||||
var myerrno {.importc: "errno", header: "<errno.h>".}: cint ## error variable
|
|
||||||
|
|
||||||
proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode =
|
proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode =
|
||||||
let name = $sym.loc.r
|
let name = sym.cname # $sym.loc.r would point to internal name
|
||||||
# the AST does not support untyped pointers directly, so we use an nkIntLit
|
# the AST does not support untyped pointers directly, so we use an nkIntLit
|
||||||
# that contains the address instead:
|
# that contains the address instead:
|
||||||
result = newNodeIT(nkPtrLit, sym.info, sym.typ)
|
result = newNodeIT(nkPtrLit, sym.info, sym.typ)
|
||||||
case name
|
when true:
|
||||||
of "stdin": result.intVal = cast[ByteAddress](system.stdin)
|
|
||||||
of "stdout": result.intVal = cast[ByteAddress](system.stdout)
|
|
||||||
of "stderr": result.intVal = cast[ByteAddress](system.stderr)
|
|
||||||
of "vmErrnoWrapper": result.intVal = cast[ByteAddress](myerrno)
|
|
||||||
else:
|
|
||||||
let lib = sym.annex
|
let lib = sym.annex
|
||||||
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
|
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
|
||||||
globalError(conf, sym.info, "dynlib needs to be a string lit")
|
globalError(conf, sym.info, "dynlib needs to be a string lit")
|
||||||
|
|
@ -74,7 +67,7 @@ proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode =
|
||||||
let dll = if lib.kind == libHeader: libcDll else: lib.path.strVal
|
let dll = if lib.kind == libHeader: libcDll else: lib.path.strVal
|
||||||
let dllhandle = getDll(conf, gDllCache, dll, sym.info)
|
let dllhandle = getDll(conf, gDllCache, dll, sym.info)
|
||||||
theAddr = dllhandle.symAddr(name)
|
theAddr = dllhandle.symAddr(name)
|
||||||
if theAddr.isNil: globalError(conf, sym.info, "cannot import: " & sym.name.s)
|
if theAddr.isNil: globalError(conf, sym.info, "cannot import: " & name)
|
||||||
result.intVal = cast[ByteAddress](theAddr)
|
result.intVal = cast[ByteAddress](theAddr)
|
||||||
|
|
||||||
proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.TType =
|
proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.TType =
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,8 @@ proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) =
|
||||||
s.loc.r = rope(extname % s.name.s)
|
s.loc.r = rope(extname % s.name.s)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
|
localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
|
||||||
|
when hasFFI:
|
||||||
|
s.cname = $s.loc.r
|
||||||
if c.config.cmd == cmdPretty and '$' notin extname:
|
if c.config.cmd == cmdPretty and '$' notin extname:
|
||||||
# note that '{.importc.}' is transformed into '{.importc: "$1".}'
|
# note that '{.importc.}' is transformed into '{.importc: "$1".}'
|
||||||
s.loc.flags.incl(lfFullExternalName)
|
s.loc.flags.incl(lfFullExternalName)
|
||||||
|
|
|
||||||
172
compiler/vm.nim
172
compiler/vm.nim
|
|
@ -140,6 +140,40 @@ template decodeBx(k: untyped) {.dirty.} =
|
||||||
template move(a, b: untyped) {.dirty.} = system.shallowCopy(a, b)
|
template move(a, b: untyped) {.dirty.} = system.shallowCopy(a, b)
|
||||||
# XXX fix minor 'shallowCopy' overloading bug in compiler
|
# XXX fix minor 'shallowCopy' overloading bug in compiler
|
||||||
|
|
||||||
|
proc derefPtrToReg(address: BiggestInt, typ: PType, r: var TFullReg, isAssign: bool): bool =
|
||||||
|
# nim bug: `isAssign: static bool` doesn't work, giving odd compiler error
|
||||||
|
template fun(field, T, rkind) =
|
||||||
|
if isAssign:
|
||||||
|
cast[ptr T](address)[] = T(r.field)
|
||||||
|
else:
|
||||||
|
# ensureKind(rkind)
|
||||||
|
if r.kind != rkind:
|
||||||
|
myreset(r)
|
||||||
|
r.kind = rkind
|
||||||
|
let val = cast[ptr T](address)[]
|
||||||
|
when T is SomeInteger:
|
||||||
|
r.field = BiggestInt(val)
|
||||||
|
else:
|
||||||
|
r.field = val
|
||||||
|
return true
|
||||||
|
|
||||||
|
## see also typeinfo.getBiggestInt
|
||||||
|
case typ.kind
|
||||||
|
of tyInt: fun(intVal, int, rkInt)
|
||||||
|
of tyInt8: fun(intVal, int8, rkInt)
|
||||||
|
of tyInt16: fun(intVal, int16, rkInt)
|
||||||
|
of tyInt32: fun(intVal, int32, rkInt)
|
||||||
|
of tyInt64: fun(intVal, int64, rkInt)
|
||||||
|
of tyUInt: fun(intVal, uint, rkInt)
|
||||||
|
of tyUInt8: fun(intVal, uint8, rkInt)
|
||||||
|
of tyUInt16: fun(intVal, uint16, rkInt)
|
||||||
|
of tyUInt32: fun(intVal, uint32, rkInt)
|
||||||
|
of tyUInt64: fun(intVal, uint64, rkInt) # note: differs from typeinfo.getBiggestInt
|
||||||
|
of tyFloat: fun(floatVal, float, rkFloat)
|
||||||
|
of tyFloat32: fun(floatVal, float32, rkFloat)
|
||||||
|
of tyFloat64: fun(floatVal, float64, rkFloat)
|
||||||
|
else: return false
|
||||||
|
|
||||||
proc createStrKeepNode(x: var TFullReg; keepNode=true) =
|
proc createStrKeepNode(x: var TFullReg; keepNode=true) =
|
||||||
if x.node.isNil or not keepNode:
|
if x.node.isNil or not keepNode:
|
||||||
x.node = newNode(nkStrLit)
|
x.node = newNode(nkStrLit)
|
||||||
|
|
@ -242,14 +276,20 @@ proc writeField(n: var PNode, x: TFullReg) =
|
||||||
of rkNodeAddr: n = x.nodeAddr[]
|
of rkNodeAddr: n = x.nodeAddr[]
|
||||||
|
|
||||||
proc putIntoReg(dest: var TFullReg; n: PNode) =
|
proc putIntoReg(dest: var TFullReg; n: PNode) =
|
||||||
|
template funInt() =
|
||||||
|
dest.kind = rkInt
|
||||||
|
dest.intVal = n.intVal
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkStrLit..nkTripleStrLit:
|
of nkStrLit..nkTripleStrLit:
|
||||||
dest.kind = rkNode
|
dest.kind = rkNode
|
||||||
createStr(dest)
|
createStr(dest)
|
||||||
dest.node.strVal = n.strVal
|
dest.node.strVal = n.strVal
|
||||||
of nkCharLit..nkUInt64Lit:
|
of nkIntLit: # use `nkPtrLit` once this is added
|
||||||
dest.kind = rkInt
|
if dest.kind == rkNode: dest.node = n
|
||||||
dest.intVal = n.intVal
|
elif n.typ != nil and n.typ.kind in PtrLikeKinds:
|
||||||
|
dest = TFullReg(kind: rkNode, node: n)
|
||||||
|
else: funInt()
|
||||||
|
of {nkCharLit..nkUInt64Lit} - {nkIntLit}: funInt()
|
||||||
of nkFloatLit..nkFloat128Lit:
|
of nkFloatLit..nkFloat128Lit:
|
||||||
dest.kind = rkFloat
|
dest.kind = rkFloat
|
||||||
dest.floatVal = n.floatVal
|
dest.floatVal = n.floatVal
|
||||||
|
|
@ -567,6 +607,33 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
let rb = instr.regB
|
let rb = instr.regB
|
||||||
ensureKind(rkFloat)
|
ensureKind(rkFloat)
|
||||||
regs[ra].floatVal = cast[float64](int64(regs[rb].intVal))
|
regs[ra].floatVal = cast[float64](int64(regs[rb].intVal))
|
||||||
|
|
||||||
|
of opcCastPtrToInt: # RENAME opcCastPtrOrRefToInt
|
||||||
|
decodeBImm(rkInt)
|
||||||
|
case imm
|
||||||
|
of 1: # PtrLikeKinds
|
||||||
|
case regs[rb].kind
|
||||||
|
of rkNode:
|
||||||
|
regs[ra].intVal = cast[int](regs[rb].node.intVal)
|
||||||
|
of rkNodeAddr:
|
||||||
|
regs[ra].intVal = cast[int](regs[rb].nodeAddr)
|
||||||
|
else:
|
||||||
|
stackTrace(c, tos, pc, "opcCastPtrToInt: got " & $regs[rb].kind)
|
||||||
|
of 2: # tyRef
|
||||||
|
regs[ra].intVal = cast[int](regs[rb].node)
|
||||||
|
else: assert false, $imm
|
||||||
|
of opcCastIntToPtr:
|
||||||
|
let rb = instr.regB
|
||||||
|
let typ = regs[ra].node.typ
|
||||||
|
let node2 = newNodeIT(nkIntLit, c.debug[pc], typ)
|
||||||
|
case regs[rb].kind
|
||||||
|
of rkInt: node2.intVal = regs[rb].intVal
|
||||||
|
of rkNode:
|
||||||
|
if regs[rb].node.typ.kind notin PtrLikeKinds:
|
||||||
|
stackTrace(c, tos, pc, "opcCastIntToPtr: regs[rb].node.typ: " & $regs[rb].node.typ.kind)
|
||||||
|
node2.intVal = regs[rb].node.intVal
|
||||||
|
else: stackTrace(c, tos, pc, "opcCastIntToPtr: regs[rb].kind: " & $regs[rb].kind)
|
||||||
|
regs[ra].node = node2
|
||||||
of opcAsgnComplex:
|
of opcAsgnComplex:
|
||||||
asgnComplex(regs[ra], regs[instr.regB])
|
asgnComplex(regs[ra], regs[instr.regB])
|
||||||
of opcFastAsgnComplex:
|
of opcFastAsgnComplex:
|
||||||
|
|
@ -651,7 +718,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
let src = regs[rb].node
|
let src = regs[rb].node
|
||||||
case src.kind
|
case src.kind
|
||||||
of nkEmpty..nkNilLit:
|
of nkEmpty..nkNilLit:
|
||||||
stackTrace(c, tos, pc, errNilAccess)
|
# for nkPtrLit, this could be supported in the future, use something like:
|
||||||
|
# derefPtrToReg(src.intVal + offsetof(src.typ, rc), typ_field, regs[ra], isAssign = false)
|
||||||
|
# where we compute the offset in bytes for field rc
|
||||||
|
stackTrace(c, tos, pc, errNilAccess & " " & $("kind", src.kind, "typ", typeToString(src.typ), "rc", rc))
|
||||||
of nkObjConstr:
|
of nkObjConstr:
|
||||||
let n = src[rc + 1].skipColon
|
let n = src[rc + 1].skipColon
|
||||||
regs[ra].node = n
|
regs[ra].node = n
|
||||||
|
|
@ -718,10 +788,23 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
if regs[rb].node.kind == nkRefTy:
|
if regs[rb].node.kind == nkRefTy:
|
||||||
regs[ra].node = regs[rb].node[0]
|
regs[ra].node = regs[rb].node[0]
|
||||||
else:
|
else:
|
||||||
ensureKind(rkNode)
|
let node = regs[rb].node
|
||||||
regs[ra].node = regs[rb].node
|
let typ = node.typ
|
||||||
|
# see also `nfIsPtr`
|
||||||
|
if node.kind == nkIntLit:
|
||||||
|
var typ2 = typ
|
||||||
|
doAssert typ != nil
|
||||||
|
if typ.kind == tyPtr:
|
||||||
|
typ2 = typ2[0]
|
||||||
|
if not derefPtrToReg(node.intVal, typ2, regs[ra], isAssign = false):
|
||||||
|
# tyObject not supported in this context
|
||||||
|
stackTrace(c, tos, pc, "opcLdDeref unsupported ptr type: " & $(typeToString(typ), typ.kind))
|
||||||
|
else:
|
||||||
|
## eg: typ.kind = tyObject
|
||||||
|
ensureKind(rkNode)
|
||||||
|
regs[ra].node = regs[rb].node
|
||||||
else:
|
else:
|
||||||
stackTrace(c, tos, pc, errNilAccess)
|
stackTrace(c, tos, pc, errNilAccess & " kind: " & $regs[rb].kind)
|
||||||
of opcWrDeref:
|
of opcWrDeref:
|
||||||
# a[] = c; b unused
|
# a[] = c; b unused
|
||||||
let ra = instr.regA
|
let ra = instr.regA
|
||||||
|
|
@ -742,8 +825,18 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of rkNode:
|
of rkNode:
|
||||||
if regs[ra].node.kind == nkNilLit:
|
if regs[ra].node.kind == nkNilLit:
|
||||||
stackTrace(c, tos, pc, errNilAccess)
|
stackTrace(c, tos, pc, errNilAccess)
|
||||||
regs[ra].node[] = regs[rc].regToNode[]
|
let node = regs[ra].node
|
||||||
regs[ra].node.flags.incl nfIsRef
|
let typ = node.typ
|
||||||
|
if nfIsPtr in node.flags or (typ != nil and typ.kind == tyPtr):
|
||||||
|
assert node.kind == nkIntLit, $(node.kind)
|
||||||
|
var typ2 = typ
|
||||||
|
if typ.kind == tyPtr:
|
||||||
|
typ2 = typ2[0]
|
||||||
|
if not derefPtrToReg(node.intVal, typ2, regs[rc], isAssign = true):
|
||||||
|
stackTrace(c, tos, pc, "opcWrDeref unsupported ptr type: " & $(typeToString(typ), typ.kind))
|
||||||
|
else:
|
||||||
|
regs[ra].node[] = regs[rc].regToNode[]
|
||||||
|
regs[ra].node.flags.incl nfIsRef
|
||||||
else: stackTrace(c, tos, pc, errNilAccess)
|
else: stackTrace(c, tos, pc, errNilAccess)
|
||||||
of opcAddInt:
|
of opcAddInt:
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
|
|
@ -918,22 +1011,40 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
regs[ra].intVal = ord(regs[rb].intVal <% regs[rc].intVal)
|
regs[ra].intVal = ord(regs[rb].intVal <% regs[rc].intVal)
|
||||||
of opcEqRef:
|
of opcEqRef:
|
||||||
|
var ret = false
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
|
template getTyp(n): untyped =
|
||||||
|
n.typ.skipTypes(abstractInst)
|
||||||
|
proc ptrEquality(n1: ptr PNode, n2: PNode): bool =
|
||||||
|
## true if n2.intVal represents a ptr equal to n1
|
||||||
|
let p1 = cast[int](n1)
|
||||||
|
case n2.kind
|
||||||
|
of nkNilLit: return p1 == 0
|
||||||
|
of nkIntLit: # TODO: nkPtrLit
|
||||||
|
# for example, n1.kind == nkFloatLit (ptr float)
|
||||||
|
# the problem is that n1.typ == nil so we can't compare n1.typ and n2.typ
|
||||||
|
# this is the best we can do (pending making sure we assign a valid n1.typ to nodeAddr's)
|
||||||
|
let t2 = n2.getTyp
|
||||||
|
return t2.kind in PtrLikeKinds and n2.intVal == p1
|
||||||
|
else: return false
|
||||||
|
|
||||||
if regs[rb].kind == rkNodeAddr:
|
if regs[rb].kind == rkNodeAddr:
|
||||||
if regs[rc].kind == rkNodeAddr:
|
if regs[rc].kind == rkNodeAddr:
|
||||||
regs[ra].intVal = ord(regs[rb].nodeAddr == regs[rc].nodeAddr)
|
ret = regs[rb].nodeAddr == regs[rc].nodeAddr
|
||||||
else:
|
else:
|
||||||
assert regs[rc].kind == rkNode
|
ret = ptrEquality(regs[rb].nodeAddr, regs[rc].node)
|
||||||
# we know these cannot be equal
|
|
||||||
regs[ra].intVal = ord(false)
|
|
||||||
elif regs[rc].kind == rkNodeAddr:
|
elif regs[rc].kind == rkNodeAddr:
|
||||||
assert regs[rb].kind == rkNode
|
ret = ptrEquality(regs[rc].nodeAddr, regs[rb].node)
|
||||||
# we know these cannot be equal
|
|
||||||
regs[ra].intVal = ord(false)
|
|
||||||
else:
|
else:
|
||||||
regs[ra].intVal = ord((regs[rb].node.kind == nkNilLit and
|
let nb = regs[rb].node
|
||||||
regs[rc].node.kind == nkNilLit) or
|
let nc = regs[rc].node
|
||||||
regs[rb].node == regs[rc].node)
|
if nb.kind != nc.kind: discard
|
||||||
|
elif (nb == nc) or (nb.kind == nkNilLit): ret = true
|
||||||
|
elif nb.kind == nkIntLit and nb.intVal == nc.intVal: # TODO: nkPtrLit
|
||||||
|
let tb = nb.getTyp
|
||||||
|
let tc = nc.getTyp
|
||||||
|
ret = tb.kind in PtrLikeKinds and tc.kind == tb.kind
|
||||||
|
regs[ra].intVal = ord(ret)
|
||||||
of opcEqNimNode:
|
of opcEqNimNode:
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
regs[ra].intVal =
|
regs[ra].intVal =
|
||||||
|
|
@ -1338,6 +1449,29 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
let rb = instr.regBx - wordExcess - 1
|
let rb = instr.regBx - wordExcess - 1
|
||||||
ensureKind(rkNode)
|
ensureKind(rkNode)
|
||||||
regs[ra].node = c.globals[rb]
|
regs[ra].node = c.globals[rb]
|
||||||
|
of opcLdGlobalDerefFFI:
|
||||||
|
let rb = instr.regBx - wordExcess - 1
|
||||||
|
let node = c.globals[rb]
|
||||||
|
let typ = node.typ
|
||||||
|
doAssert node.kind == nkIntLit, $(node.kind)
|
||||||
|
if typ.kind == tyPtr:
|
||||||
|
ensureKind(rkNode)
|
||||||
|
# use nkPtrLit once this is added
|
||||||
|
let node2 = newNodeIT(nkIntLit, c.debug[pc], typ)
|
||||||
|
node2.intVal = cast[ptr int](node.intVal)[]
|
||||||
|
node2.flags.incl nfIsPtr
|
||||||
|
regs[ra].node = node2
|
||||||
|
elif not derefPtrToReg(node.intVal, typ, regs[ra], isAssign = false):
|
||||||
|
stackTrace(c, tos, pc, "opcLdDeref unsupported type: " & $(typeToString(typ), typ[0].kind))
|
||||||
|
of opcLdGlobalAddrDerefFFI:
|
||||||
|
let rb = instr.regBx - wordExcess - 1
|
||||||
|
let node = c.globals[rb]
|
||||||
|
let typ = node.typ
|
||||||
|
var node2 = newNodeIT(nkIntLit, node.info, typ)
|
||||||
|
node2.intVal = node.intVal
|
||||||
|
node2.flags.incl nfIsPtr
|
||||||
|
ensureKind(rkNode)
|
||||||
|
regs[ra].node = node2
|
||||||
of opcLdGlobalAddr:
|
of opcLdGlobalAddr:
|
||||||
let rb = instr.regBx - wordExcess - 1
|
let rb = instr.regBx - wordExcess - 1
|
||||||
ensureKind(rkNodeAddr)
|
ensureKind(rkNodeAddr)
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,8 @@ type
|
||||||
opcCastIntToFloat64, # int and float must be of the same byte size
|
opcCastIntToFloat64, # int and float must be of the same byte size
|
||||||
opcCastFloatToInt32, # int and float must be of the same byte size
|
opcCastFloatToInt32, # int and float must be of the same byte size
|
||||||
opcCastFloatToInt64, # int and float must be of the same byte size
|
opcCastFloatToInt64, # int and float must be of the same byte size
|
||||||
|
opcCastPtrToInt,
|
||||||
|
opcCastIntToPtr,
|
||||||
opcFastAsgnComplex,
|
opcFastAsgnComplex,
|
||||||
opcNodeToReg,
|
opcNodeToReg,
|
||||||
|
|
||||||
|
|
@ -169,6 +171,8 @@ type
|
||||||
opcAsgnConst, # dest = copy(constants[Bx])
|
opcAsgnConst, # dest = copy(constants[Bx])
|
||||||
opcLdGlobal, # dest = globals[Bx]
|
opcLdGlobal, # dest = globals[Bx]
|
||||||
opcLdGlobalAddr, # dest = addr(globals[Bx])
|
opcLdGlobalAddr, # dest = addr(globals[Bx])
|
||||||
|
opcLdGlobalDerefFFI, # dest = globals[Bx][]
|
||||||
|
opcLdGlobalAddrDerefFFI, # globals[Bx][] = ...
|
||||||
|
|
||||||
opcLdImmInt, # dest = immediate value
|
opcLdImmInt, # dest = immediate value
|
||||||
opcNBindSym, opcNDynBindSym,
|
opcNBindSym, opcNDynBindSym,
|
||||||
|
|
|
||||||
|
|
@ -885,8 +885,21 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
c.gABC(n, opcCastFloatToInt64, dest, tmp)
|
c.gABC(n, opcCastFloatToInt64, dest, tmp)
|
||||||
# narrowing for 64 bits not needed (no extended sign bits available).
|
# narrowing for 64 bits not needed (no extended sign bits available).
|
||||||
c.freeTemp(tmp)
|
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:
|
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) =
|
proc genVoidABC(c: PCtx, n: PNode, dest: TDest, opcode: TOpcode) =
|
||||||
unused(c, n, dest)
|
unused(c, n, dest)
|
||||||
|
|
@ -1474,11 +1487,17 @@ proc getOwner(c: PCtx): PSym =
|
||||||
result = c.prc.sym
|
result = c.prc.sym
|
||||||
if result.isNil: result = c.module
|
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) =
|
proc checkCanEval(c: PCtx; n: PNode) =
|
||||||
# we need to ensure that we don't evaluate 'x' here:
|
# we need to ensure that we don't evaluate 'x' here:
|
||||||
# proc foo() = var x ...
|
# proc foo() = var x ...
|
||||||
let s = n.sym
|
let s = n.sym
|
||||||
if {sfCompileTime, sfGlobal} <= s.flags: return
|
if {sfCompileTime, sfGlobal} <= s.flags: return
|
||||||
|
if s.importcCondVar: return
|
||||||
if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
|
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:
|
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
|
# 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
|
assert card(flags * {gfNodeAddr, gfNode}) < 2
|
||||||
let s = n.sym
|
let s = n.sym
|
||||||
if s.isGlobal:
|
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
|
discard
|
||||||
elif s.position == 0:
|
elif s.position == 0:
|
||||||
cannotEval(c, n)
|
cannotEval(c, n)
|
||||||
if s.position == 0:
|
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)
|
else: genGlobalInit(c, n, s)
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
assert s.typ != nil
|
assert s.typ != nil
|
||||||
|
|
||||||
if gfNodeAddr in flags:
|
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:
|
elif fitsRegister(s.typ) and gfNode notin flags:
|
||||||
var cc = c.getTemp(n.typ)
|
var cc = c.getTemp(n.typ)
|
||||||
c.gABx(n, opcLdGlobal, cc, s.position)
|
c.gABx(n, opcLdGlobal, cc, s.position)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue