C++ support: codegen generates C++'s references and avoids copies
This commit is contained in:
parent
a400e8f7f3
commit
e75e421912
7 changed files with 156 additions and 101 deletions
|
|
@ -655,7 +655,6 @@ type
|
||||||
locGlobalVar, # location is a global variable
|
locGlobalVar, # location is a global variable
|
||||||
locParam, # location is a parameter
|
locParam, # location is a parameter
|
||||||
locField, # location is a record field
|
locField, # location is a record field
|
||||||
locArrayElem, # location is an array element
|
|
||||||
locExpr, # "location" is really an expression
|
locExpr, # "location" is really an expression
|
||||||
locProc, # location is a proc (an address of a procedure)
|
locProc, # location is a proc (an address of a procedure)
|
||||||
locData, # location is a constant
|
locData, # location is a constant
|
||||||
|
|
@ -669,14 +668,15 @@ type
|
||||||
lfDynamicLib, # link symbol to dynamic library
|
lfDynamicLib, # link symbol to dynamic library
|
||||||
lfExportLib, # export symbol for dynamic library generation
|
lfExportLib, # export symbol for dynamic library generation
|
||||||
lfHeader, # include header file for symbol
|
lfHeader, # include header file for symbol
|
||||||
lfImportCompilerProc # ``importc`` of a compilerproc
|
lfImportCompilerProc, # ``importc`` of a compilerproc
|
||||||
|
lfSingleUse # no location yet and will only be used once
|
||||||
TStorageLoc* = enum
|
TStorageLoc* = enum
|
||||||
OnUnknown, # location is unknown (stack, heap or static)
|
OnUnknown, # location is unknown (stack, heap or static)
|
||||||
OnStack, # location is on hardware stack
|
OnStack, # location is on hardware stack
|
||||||
OnHeap # location is on heap or global
|
OnHeap # location is on heap or global
|
||||||
# (reference counting needed)
|
# (reference counting needed)
|
||||||
TLocFlags* = set[TLocFlag]
|
TLocFlags* = set[TLocFlag]
|
||||||
TLoc*{.final.} = object
|
TLoc* = object
|
||||||
k*: TLocKind # kind of location
|
k*: TLocKind # kind of location
|
||||||
s*: TStorageLoc
|
s*: TStorageLoc
|
||||||
flags*: TLocFlags # location's flags
|
flags*: TLocFlags # location's flags
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,20 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||||
else:
|
else:
|
||||||
app(pl, ~")")
|
app(pl, ~")")
|
||||||
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
if p.module.compileToCpp and lfSingleUse in d.flags:
|
||||||
assert(d.t != nil) # generate an assignment to d:
|
# do not generate spurious temporaries for C++! For C we're better off
|
||||||
var list: TLoc
|
# with them to prevent undefined behaviour and because the codegen
|
||||||
initLoc(list, locCall, d.t, OnUnknown)
|
# is free to emit expressions multiple times!
|
||||||
list.r = pl
|
d.k = locCall
|
||||||
genAssignment(p, d, list, {}) # no need for deep copying
|
d.r = pl
|
||||||
|
excl d.flags, lfSingleUse
|
||||||
|
else:
|
||||||
|
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
||||||
|
assert(d.t != nil) # generate an assignment to d:
|
||||||
|
var list: TLoc
|
||||||
|
initLoc(list, locCall, d.t, OnUnknown)
|
||||||
|
list.r = pl
|
||||||
|
genAssignment(p, d, list, {}) # no need for deep copying
|
||||||
else:
|
else:
|
||||||
app(pl, ~");$n")
|
app(pl, ~");$n")
|
||||||
line(p, cpsStmts, pl)
|
line(p, cpsStmts, pl)
|
||||||
|
|
@ -90,7 +98,8 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
|
||||||
of tyOpenArray, tyVarargs, tyArray, tyArrayConstr:
|
of tyOpenArray, tyVarargs, tyArray, tyArrayConstr:
|
||||||
"($1)+($2), ($3)-($2)+1"
|
"($1)+($2), ($3)-($2)+1"
|
||||||
of tyString, tySequence:
|
of tyString, tySequence:
|
||||||
if skipTypes(n.typ, abstractInst).kind == tyVar:
|
if skipTypes(n.typ, abstractInst).kind == tyVar and
|
||||||
|
not compileToCpp(p.module):
|
||||||
"(*$1)->data+($2), ($3)-($2)+1"
|
"(*$1)->data+($2), ($3)-($2)+1"
|
||||||
else:
|
else:
|
||||||
"$1->data+($2), ($3)-($2)+1"
|
"$1->data+($2), ($3)-($2)+1"
|
||||||
|
|
@ -102,7 +111,8 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
result = ropef("$1, $1Len0", [rdLoc(a)])
|
result = ropef("$1, $1Len0", [rdLoc(a)])
|
||||||
of tyString, tySequence:
|
of tyString, tySequence:
|
||||||
if skipTypes(n.typ, abstractInst).kind == tyVar:
|
if skipTypes(n.typ, abstractInst).kind == tyVar and
|
||||||
|
not compileToCpp(p.module):
|
||||||
result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)])
|
result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)])
|
||||||
else:
|
else:
|
||||||
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)])
|
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)])
|
||||||
|
|
@ -123,10 +133,14 @@ proc genArg(p: BProc, n: PNode, param: PSym): PRope =
|
||||||
var n = if n.kind != nkHiddenAddr: n else: n.sons[0]
|
var n = if n.kind != nkHiddenAddr: n else: n.sons[0]
|
||||||
result = openArrayLoc(p, n)
|
result = openArrayLoc(p, n)
|
||||||
elif ccgIntroducedPtr(param):
|
elif ccgIntroducedPtr(param):
|
||||||
initLocExpr(p, n, a)
|
initLocExprSingleUse(p, n, a)
|
||||||
result = addrLoc(a)
|
result = addrLoc(a)
|
||||||
|
elif p.module.compileToCpp and param.typ.kind == tyVar and
|
||||||
|
n.kind == nkHiddenAddr:
|
||||||
|
initLocExprSingleUse(p, n.sons[0], a)
|
||||||
|
result = rdLoc(a)
|
||||||
else:
|
else:
|
||||||
initLocExpr(p, n, a)
|
initLocExprSingleUse(p, n, a)
|
||||||
result = rdLoc(a)
|
result = rdLoc(a)
|
||||||
|
|
||||||
proc genArgNoParam(p: BProc, n: PNode): PRope =
|
proc genArgNoParam(p: BProc, n: PNode): PRope =
|
||||||
|
|
@ -134,7 +148,7 @@ proc genArgNoParam(p: BProc, n: PNode): PRope =
|
||||||
if n.kind == nkStringToCString:
|
if n.kind == nkStringToCString:
|
||||||
result = genArgStringToCString(p, n)
|
result = genArgStringToCString(p, n)
|
||||||
else:
|
else:
|
||||||
initLocExpr(p, n, a)
|
initLocExprSingleUse(p, n, a)
|
||||||
result = rdLoc(a)
|
result = rdLoc(a)
|
||||||
|
|
||||||
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
|
|
@ -274,26 +288,28 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
|
||||||
assert(typ.n.sons[i].kind == nkSym)
|
assert(typ.n.sons[i].kind == nkSym)
|
||||||
# if the parameter is lying (tyVar) and thus we required an additional deref,
|
# if the parameter is lying (tyVar) and thus we required an additional deref,
|
||||||
# skip the deref:
|
# skip the deref:
|
||||||
|
var ri = ri[i]
|
||||||
|
while ri.kind == nkObjDownConv: ri = ri[0]
|
||||||
if typ.sons[i].kind == tyVar:
|
if typ.sons[i].kind == tyVar:
|
||||||
let x = if ri[i].kind == nkHiddenAddr: ri[i][0] else: ri[i]
|
let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
|
||||||
if x.kind in {nkHiddenDeref, nkDerefExpr}:
|
if x.typ.kind == tyPtr:
|
||||||
result = genArgNoParam(p, x[0])
|
|
||||||
result.app("->")
|
|
||||||
elif x.typ.kind in {tyVar, tyPtr}:
|
|
||||||
result = genArgNoParam(p, x)
|
result = genArgNoParam(p, x)
|
||||||
result.app("->")
|
result.app("->")
|
||||||
|
elif x.kind in {nkHiddenDeref, nkDerefExpr}:
|
||||||
|
result = genArgNoParam(p, x[0])
|
||||||
|
result.app("->")
|
||||||
else:
|
else:
|
||||||
result = genArgNoParam(p, x)
|
result = genArgNoParam(p, x)
|
||||||
result.app(".")
|
result.app(".")
|
||||||
elif typ.sons[i].kind == tyPtr:
|
elif typ.sons[i].kind == tyPtr:
|
||||||
if ri.sons[i].kind in {nkAddr, nkHiddenAddr}:
|
if ri.kind in {nkAddr, nkHiddenAddr}:
|
||||||
result = genArgNoParam(p, ri.sons[i][0])
|
result = genArgNoParam(p, ri[0])
|
||||||
result.app(".")
|
result.app(".")
|
||||||
else:
|
else:
|
||||||
result = genArgNoParam(p, ri.sons[i])
|
result = genArgNoParam(p, ri)
|
||||||
result.app("->")
|
result.app("->")
|
||||||
else:
|
else:
|
||||||
result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
|
result = genArgNoParam(p, ri) #, typ.n.sons[i].sym)
|
||||||
result.app(".")
|
result.app(".")
|
||||||
|
|
||||||
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
|
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
|
||||||
|
|
@ -367,12 +383,20 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
# simpler version of 'fixupCall' that works with the pl+params combination:
|
# simpler version of 'fixupCall' that works with the pl+params combination:
|
||||||
var typ = skipTypes(ri.sons[0].typ, abstractInst)
|
var typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||||
if typ.sons[0] != nil:
|
if typ.sons[0] != nil:
|
||||||
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
if p.module.compileToCpp and lfSingleUse in d.flags:
|
||||||
assert(d.t != nil) # generate an assignment to d:
|
# do not generate spurious temporaries for C++! For C we're better off
|
||||||
var list: TLoc
|
# with them to prevent undefined behaviour and because the codegen
|
||||||
initLoc(list, locCall, d.t, OnUnknown)
|
# is free to emit expressions multiple times!
|
||||||
list.r = pl
|
d.k = locCall
|
||||||
genAssignment(p, d, list, {}) # no need for deep copying
|
d.r = pl
|
||||||
|
excl d.flags, lfSingleUse
|
||||||
|
else:
|
||||||
|
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
||||||
|
assert(d.t != nil) # generate an assignment to d:
|
||||||
|
var list: TLoc
|
||||||
|
initLoc(list, locCall, d.t, OnUnknown)
|
||||||
|
list.r = pl
|
||||||
|
genAssignment(p, d, list, {}) # no need for deep copying
|
||||||
else:
|
else:
|
||||||
app(pl, ~";$n")
|
app(pl, ~";$n")
|
||||||
line(p, cpsStmts, pl)
|
line(p, cpsStmts, pl)
|
||||||
|
|
|
||||||
|
|
@ -662,9 +662,13 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
|
ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
|
||||||
getSimpleTypeDesc(p.module, e.typ)]))
|
getSimpleTypeDesc(p.module, e.typ)]))
|
||||||
|
|
||||||
|
proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
|
||||||
|
result = p.module.compileToCpp and
|
||||||
|
skipTypes(typ, abstractInst).kind == tyVar
|
||||||
|
|
||||||
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
||||||
let mt = mapType(e.sons[0].typ)
|
let mt = mapType(e.sons[0].typ)
|
||||||
if mt in {ctArray, ctPtrToArray} and not enforceDeref:
|
if (mt in {ctArray, ctPtrToArray} and not enforceDeref):
|
||||||
# XXX the amount of hacks for C's arrays is incredible, maybe we should
|
# XXX the amount of hacks for C's arrays is incredible, maybe we should
|
||||||
# simply wrap them in a struct? --> Losing auto vectorization then?
|
# simply wrap them in a struct? --> Losing auto vectorization then?
|
||||||
#if e[0].kind != nkBracketExpr:
|
#if e[0].kind != nkBracketExpr:
|
||||||
|
|
@ -672,12 +676,15 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
||||||
expr(p, e.sons[0], d)
|
expr(p, e.sons[0], d)
|
||||||
else:
|
else:
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, e.sons[0], a)
|
initLocExprSingleUse(p, e.sons[0], a)
|
||||||
case skipTypes(a.t, abstractInst).kind
|
case skipTypes(a.t, abstractInst).kind
|
||||||
of tyRef:
|
of tyRef:
|
||||||
d.s = OnHeap
|
d.s = OnHeap
|
||||||
of tyVar:
|
of tyVar:
|
||||||
d.s = OnUnknown
|
d.s = OnUnknown
|
||||||
|
if p.module.compileToCpp:
|
||||||
|
putIntoDest(p, d, e.typ, rdLoc(a))
|
||||||
|
return
|
||||||
of tyPtr:
|
of tyPtr:
|
||||||
d.s = OnUnknown # BUGFIX!
|
d.s = OnUnknown # BUGFIX!
|
||||||
else: internalError(e.info, "genDeref " & $a.t.kind)
|
else: internalError(e.info, "genDeref " & $a.t.kind)
|
||||||
|
|
@ -698,7 +705,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
initLocExpr(p, e.sons[0], a)
|
initLocExpr(p, e.sons[0], a)
|
||||||
putIntoDest(p, d, e.typ, con("&", a.r))
|
putIntoDest(p, d, e.typ, con("&", a.r))
|
||||||
#Message(e.info, warnUser, "HERE NEW &")
|
#Message(e.info, warnUser, "HERE NEW &")
|
||||||
elif mapType(e.sons[0].typ) == ctArray:
|
elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ):
|
||||||
expr(p, e.sons[0], d)
|
expr(p, e.sons[0], d)
|
||||||
else:
|
else:
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
|
|
@ -1236,7 +1243,8 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
|
||||||
var t = skipTypes(a.t, abstractInst)
|
var t = skipTypes(a.t, abstractInst)
|
||||||
while t.kind in {tyVar, tyPtr, tyRef}:
|
while t.kind in {tyVar, tyPtr, tyRef}:
|
||||||
if t.kind != tyVar: nilCheck = r
|
if t.kind != tyVar: nilCheck = r
|
||||||
r = rfmt(nil, "(*$1)", r)
|
if t.kind != tyVar or not p.module.compileToCpp:
|
||||||
|
r = rfmt(nil, "(*$1)", r)
|
||||||
t = skipTypes(t.lastSon, typedescInst)
|
t = skipTypes(t.lastSon, typedescInst)
|
||||||
if not p.module.compileToCpp:
|
if not p.module.compileToCpp:
|
||||||
while t.kind == tyObject and t.sons[0] != nil:
|
while t.kind == tyObject and t.sons[0] != nil:
|
||||||
|
|
@ -1863,7 +1871,8 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
|
||||||
var t = skipTypes(a.t, abstractInst)
|
var t = skipTypes(a.t, abstractInst)
|
||||||
while t.kind in {tyVar, tyPtr, tyRef}:
|
while t.kind in {tyVar, tyPtr, tyRef}:
|
||||||
if t.kind != tyVar: nilCheck = r
|
if t.kind != tyVar: nilCheck = r
|
||||||
r = ropef("(*$1)", [r])
|
if t.kind != tyVar or not p.module.compileToCpp:
|
||||||
|
r = ropef("(*$1)", [r])
|
||||||
t = skipTypes(t.lastSon, abstractInst)
|
t = skipTypes(t.lastSon, abstractInst)
|
||||||
if not p.module.compileToCpp:
|
if not p.module.compileToCpp:
|
||||||
while t.kind == tyObject and t.sons[0] != nil:
|
while t.kind == tyObject and t.sons[0] != nil:
|
||||||
|
|
@ -2073,9 +2082,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
genAsgn(p, n, fastAsgn=p.prc != nil)
|
genAsgn(p, n, fastAsgn=p.prc != nil)
|
||||||
of nkDiscardStmt:
|
of nkDiscardStmt:
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
var a: TLoc
|
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
initLocExpr(p, n.sons[0], a)
|
var a: TLoc
|
||||||
|
initLocExprSingleUse(p, n.sons[0], a)
|
||||||
of nkAsmStmt: genAsmStmt(p, n)
|
of nkAsmStmt: genAsmStmt(p, n)
|
||||||
of nkTryStmt:
|
of nkTryStmt:
|
||||||
if p.module.compileToCpp: genTryCpp(p, n, d)
|
if p.module.compileToCpp: genTryCpp(p, n, d)
|
||||||
|
|
|
||||||
|
|
@ -202,8 +202,19 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||||
genVarPrototypeAux(generatedHeader, v)
|
genVarPrototypeAux(generatedHeader, v)
|
||||||
registerGcRoot(p, v)
|
registerGcRoot(p, v)
|
||||||
else:
|
else:
|
||||||
|
let imm = isAssignedImmediately(a.sons[2])
|
||||||
|
if imm and p.module.compileToCpp:
|
||||||
|
# C++ really doesn't like things like 'Foo f; f = x' as that invokes a
|
||||||
|
# parameterless constructor followed by an assignment operator. So we
|
||||||
|
# generate better code here:
|
||||||
|
genLineDir(p, a)
|
||||||
|
let decl = localVarDecl(p, v)
|
||||||
|
var tmp: TLoc
|
||||||
|
initLocExprSingleUse(p, a.sons[2], tmp)
|
||||||
|
lineF(p, cpsStmts, "$# = $#;$n", decl, tmp.rdLoc)
|
||||||
|
return
|
||||||
assignLocalVar(p, v)
|
assignLocalVar(p, v)
|
||||||
initLocalVar(p, v, isAssignedImmediately(a.sons[2]))
|
initLocalVar(p, v, imm)
|
||||||
|
|
||||||
if a.sons[2].kind != nkEmpty:
|
if a.sons[2].kind != nkEmpty:
|
||||||
genLineDir(targetProc, a)
|
genLineDir(targetProc, a)
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,13 @@ proc mapType(typ: PType): TCTypeKind =
|
||||||
proc mapReturnType(typ: PType): TCTypeKind =
|
proc mapReturnType(typ: PType): TCTypeKind =
|
||||||
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
|
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
|
||||||
else: result = mapType(typ)
|
else: result = mapType(typ)
|
||||||
|
|
||||||
|
proc isImportedType(t: PType): bool =
|
||||||
|
result = t.sym != nil and sfImportc in t.sym.flags
|
||||||
|
|
||||||
|
proc isImportedCppType(t: PType): bool =
|
||||||
|
result = t.sym != nil and sfInfixCall in t.sym.flags
|
||||||
|
|
||||||
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope
|
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope
|
||||||
proc needsComplexAssignment(typ: PType): bool =
|
proc needsComplexAssignment(typ: PType): bool =
|
||||||
result = containsGarbageCollectedRef(typ)
|
result = containsGarbageCollectedRef(typ)
|
||||||
|
|
@ -170,19 +176,20 @@ proc isObjLackingTypeField(typ: PType): bool {.inline.} =
|
||||||
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
|
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
|
||||||
(typ.sons[0] == nil) or isPureObject(typ))
|
(typ.sons[0] == nil) or isPureObject(typ))
|
||||||
|
|
||||||
proc isInvalidReturnType(rettype: PType): bool =
|
proc isInvalidReturnType(rettype: PType): bool =
|
||||||
# Arrays and sets cannot be returned by a C procedure, because C is
|
# Arrays and sets cannot be returned by a C procedure, because C is
|
||||||
# such a poor programming language.
|
# such a poor programming language.
|
||||||
# We exclude records with refs too. This enhances efficiency and
|
# We exclude records with refs too. This enhances efficiency and
|
||||||
# is necessary for proper code generation of assignments.
|
# is necessary for proper code generation of assignments.
|
||||||
if rettype == nil: result = true
|
if rettype == nil: result = true
|
||||||
else:
|
else:
|
||||||
case mapType(rettype)
|
case mapType(rettype)
|
||||||
of ctArray:
|
of ctArray:
|
||||||
result = not (skipTypes(rettype, typedescInst).kind in
|
result = not (skipTypes(rettype, typedescInst).kind in
|
||||||
{tyVar, tyRef, tyPtr})
|
{tyVar, tyRef, tyPtr})
|
||||||
of ctStruct:
|
of ctStruct:
|
||||||
let t = skipTypes(rettype, typedescInst)
|
let t = skipTypes(rettype, typedescInst)
|
||||||
|
if rettype.isImportedCppType or t.isImportedCppType: return false
|
||||||
result = needsComplexAssignment(t) or
|
result = needsComplexAssignment(t) or
|
||||||
(t.kind == tyObject and not isObjLackingTypeField(t))
|
(t.kind == tyObject and not isObjLackingTypeField(t))
|
||||||
else: result = false
|
else: result = false
|
||||||
|
|
@ -297,12 +304,6 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
||||||
else: app(params, ")")
|
else: app(params, ")")
|
||||||
params = con("(", params)
|
params = con("(", params)
|
||||||
|
|
||||||
proc isImportedType(t: PType): bool =
|
|
||||||
result = t.sym != nil and sfImportc in t.sym.flags
|
|
||||||
|
|
||||||
proc isImportedCppType(t: PType): bool =
|
|
||||||
result = t.sym != nil and sfInfixCall in t.sym.flags
|
|
||||||
|
|
||||||
proc typeNameOrLiteral(t: PType, literal: string): PRope =
|
proc typeNameOrLiteral(t: PType, literal: string): PRope =
|
||||||
if (t.sym != nil) and (sfImportc in t.sym.flags) and (t.sym.magic == mNone):
|
if (t.sym != nil) and (sfImportc in t.sym.flags) and (t.sym.magic == mNone):
|
||||||
result = getTypeName(t)
|
result = getTypeName(t)
|
||||||
|
|
@ -421,14 +422,18 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||||
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
|
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
|
||||||
else: ae = sname
|
else: ae = sname
|
||||||
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
|
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
|
||||||
let fieldType = field.loc.t.skipTypes(abstractInst)
|
# for importcpp'ed objects, we only need to set field.loc, but don't
|
||||||
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
|
# have to recurse via 'getTypeDescAux'. And not doing so prevents problems
|
||||||
appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
|
# with heavily templatized C++ code:
|
||||||
[getTypeDescAux(m, fieldType.elemType, check), sname])
|
if not isImportedCppType(rectype):
|
||||||
else:
|
let fieldType = field.loc.t.skipTypes(abstractInst)
|
||||||
# don't use fieldType here because we need the
|
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
|
||||||
# tyGenericInst for C++ template support
|
appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
|
||||||
appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
|
[getTypeDescAux(m, fieldType.elemType, check), sname])
|
||||||
|
else:
|
||||||
|
# don't use fieldType here because we need the
|
||||||
|
# tyGenericInst for C++ template support
|
||||||
|
appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
|
||||||
else: internalError(n.info, "genRecordFieldsAux()")
|
else: internalError(n.info, "genRecordFieldsAux()")
|
||||||
|
|
||||||
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope =
|
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||||
|
|
@ -493,13 +498,15 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||||
if t.sym != nil: useHeader(m, t.sym)
|
if t.sym != nil: useHeader(m, t.sym)
|
||||||
result = getTypePre(m, t)
|
result = getTypePre(m, t)
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
if containsOrIncl(check, t.id):
|
if containsOrIncl(check, t.id):
|
||||||
|
if isImportedCppType(typ) or isImportedCppType(t): return
|
||||||
internalError("cannot generate C type for: " & typeToString(typ))
|
internalError("cannot generate C type for: " & typeToString(typ))
|
||||||
# XXX: this BUG is hard to fix -> we need to introduce helper structs,
|
# XXX: this BUG is hard to fix -> we need to introduce helper structs,
|
||||||
# but determining when this needs to be done is hard. We should split
|
# but determining when this needs to be done is hard. We should split
|
||||||
# C type generation into an analysis and a code generation phase somehow.
|
# C type generation into an analysis and a code generation phase somehow.
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyRef, tyPtr, tyVar:
|
of tyRef, tyPtr, tyVar:
|
||||||
|
let star = if t.kind == tyVar and compileToCpp(m): "&" else: "*"
|
||||||
var et = t.lastSon
|
var et = t.lastSon
|
||||||
var etB = et.skipTypes(abstractInst)
|
var etB = et.skipTypes(abstractInst)
|
||||||
if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}:
|
if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}:
|
||||||
|
|
@ -510,12 +517,12 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||||
case etB.kind
|
case etB.kind
|
||||||
of tyObject, tyTuple:
|
of tyObject, tyTuple:
|
||||||
if isImportedCppType(etB) and et.kind == tyGenericInst:
|
if isImportedCppType(etB) and et.kind == tyGenericInst:
|
||||||
result = con(getTypeDescAux(m, et, check), "*")
|
result = con(getTypeDescAux(m, et, check), star)
|
||||||
else:
|
else:
|
||||||
# no restriction! We have a forward declaration for structs
|
# no restriction! We have a forward declaration for structs
|
||||||
let x = getUniqueType(etB)
|
let x = getUniqueType(etB)
|
||||||
let name = getTypeForward(m, x)
|
let name = getTypeForward(m, x)
|
||||||
result = con(name, "*")
|
result = con(name, star)
|
||||||
idTablePut(m.typeCache, t, result)
|
idTablePut(m.typeCache, t, result)
|
||||||
pushType(m, x)
|
pushType(m, x)
|
||||||
of tySequence:
|
of tySequence:
|
||||||
|
|
@ -527,7 +534,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||||
pushType(m, x)
|
pushType(m, x)
|
||||||
else:
|
else:
|
||||||
# else we have a strong dependency :-(
|
# else we have a strong dependency :-(
|
||||||
result = con(getTypeDescAux(m, et, check), "*")
|
result = con(getTypeDescAux(m, et, check), star)
|
||||||
idTablePut(m.typeCache, t, result)
|
idTablePut(m.typeCache, t, result)
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
result = con(getTypeDescAux(m, t.sons[0], check), "*")
|
result = con(getTypeDescAux(m, t.sons[0], check), "*")
|
||||||
|
|
@ -696,16 +703,7 @@ proc getNimNode(m: BModule): PRope =
|
||||||
result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)])
|
result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)])
|
||||||
inc(m.typeNodes)
|
inc(m.typeNodes)
|
||||||
|
|
||||||
when false:
|
proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: PRope) =
|
||||||
proc getNimType(m: BModule): PRope =
|
|
||||||
result = ropef("$1[$2]", [m.nimTypesName, toRope(m.nimTypes)])
|
|
||||||
inc(m.nimTypes)
|
|
||||||
|
|
||||||
proc allocMemTI(m: BModule, typ: PType, name: PRope) =
|
|
||||||
var tmp = getNimType(m)
|
|
||||||
appf(m.s[cfsTypeInit2], "$2 = &$1;$n", [tmp, name])
|
|
||||||
|
|
||||||
proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
|
|
||||||
var nimtypeKind: int
|
var nimtypeKind: int
|
||||||
#allocMemTI(m, typ, name)
|
#allocMemTI(m, typ, name)
|
||||||
if isObjLackingTypeField(typ):
|
if isObjLackingTypeField(typ):
|
||||||
|
|
@ -715,6 +713,7 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
|
||||||
|
|
||||||
var size: PRope
|
var size: PRope
|
||||||
if tfIncompleteStruct in typ.flags: size = toRope"void*"
|
if tfIncompleteStruct in typ.flags: size = toRope"void*"
|
||||||
|
elif m.compileToCpp: size = getTypeDesc(m, origType)
|
||||||
else: size = getTypeDesc(m, typ)
|
else: size = getTypeDesc(m, typ)
|
||||||
appf(m.s[cfsTypeInit3],
|
appf(m.s[cfsTypeInit3],
|
||||||
"$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
|
"$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
|
||||||
|
|
@ -730,13 +729,13 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
|
||||||
appf(m.s[cfsVars], "TNimType $1; /* $2 */$n",
|
appf(m.s[cfsVars], "TNimType $1; /* $2 */$n",
|
||||||
[name, toRope(typeToString(typ))])
|
[name, toRope(typeToString(typ))])
|
||||||
|
|
||||||
proc genTypeInfoAux(m: BModule, typ: PType, name: PRope) =
|
proc genTypeInfoAux(m: BModule, typ, origType: PType, name: PRope) =
|
||||||
var base: PRope
|
var base: PRope
|
||||||
if (sonsLen(typ) > 0) and (typ.sons[0] != nil):
|
if (sonsLen(typ) > 0) and (typ.sons[0] != nil):
|
||||||
base = genTypeInfo(m, typ.sons[0])
|
base = genTypeInfo(m, typ.sons[0])
|
||||||
else:
|
else:
|
||||||
base = toRope("0")
|
base = toRope("0")
|
||||||
genTypeInfoAuxBase(m, typ, name, base)
|
genTypeInfoAuxBase(m, typ, origType, name, base)
|
||||||
|
|
||||||
proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
|
proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
|
||||||
# bugfix: we need to search the type that contains the discriminator:
|
# bugfix: we need to search the type that contains the discriminator:
|
||||||
|
|
@ -814,11 +813,12 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
|
||||||
field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)])
|
field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)])
|
||||||
else: internalError(n.info, "genObjectFields")
|
else: internalError(n.info, "genObjectFields")
|
||||||
|
|
||||||
proc genObjectInfo(m: BModule, typ: PType, name: PRope) =
|
proc genObjectInfo(m: BModule, typ, origType: PType, name: PRope) =
|
||||||
if typ.kind == tyObject: genTypeInfoAux(m, typ, name)
|
if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name)
|
||||||
else: genTypeInfoAuxBase(m, typ, name, toRope("0"))
|
else: genTypeInfoAuxBase(m, typ, origType, name, toRope("0"))
|
||||||
var tmp = getNimNode(m)
|
var tmp = getNimNode(m)
|
||||||
genObjectFields(m, typ, typ.n, tmp)
|
if not isImportedCppType(typ):
|
||||||
|
genObjectFields(m, typ, typ.n, tmp)
|
||||||
appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
|
appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
|
||||||
var t = typ.sons[0]
|
var t = typ.sons[0]
|
||||||
while t != nil:
|
while t != nil:
|
||||||
|
|
@ -827,7 +827,7 @@ proc genObjectInfo(m: BModule, typ: PType, name: PRope) =
|
||||||
t = t.sons[0]
|
t = t.sons[0]
|
||||||
|
|
||||||
proc genTupleInfo(m: BModule, typ: PType, name: PRope) =
|
proc genTupleInfo(m: BModule, typ: PType, name: PRope) =
|
||||||
genTypeInfoAuxBase(m, typ, name, toRope("0"))
|
genTypeInfoAuxBase(m, typ, typ, name, toRope("0"))
|
||||||
var expr = getNimNode(m)
|
var expr = getNimNode(m)
|
||||||
var length = sonsLen(typ)
|
var length = sonsLen(typ)
|
||||||
if length > 0:
|
if length > 0:
|
||||||
|
|
@ -854,7 +854,7 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
|
||||||
# optimizations here: The ``typ`` field is never set, as it is redundant
|
# optimizations here: The ``typ`` field is never set, as it is redundant
|
||||||
# anyway. We generate a cstring array and a loop over it. Exceptional
|
# anyway. We generate a cstring array and a loop over it. Exceptional
|
||||||
# positions will be reset after the loop.
|
# positions will be reset after the loop.
|
||||||
genTypeInfoAux(m, typ, name)
|
genTypeInfoAux(m, typ, typ, name)
|
||||||
var nodePtrs = getTempName()
|
var nodePtrs = getTempName()
|
||||||
var length = sonsLen(typ.n)
|
var length = sonsLen(typ.n)
|
||||||
appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
|
appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
|
||||||
|
|
@ -894,13 +894,13 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
|
||||||
|
|
||||||
proc genSetInfo(m: BModule, typ: PType, name: PRope) =
|
proc genSetInfo(m: BModule, typ: PType, name: PRope) =
|
||||||
assert(typ.sons[0] != nil)
|
assert(typ.sons[0] != nil)
|
||||||
genTypeInfoAux(m, typ, name)
|
genTypeInfoAux(m, typ, typ, name)
|
||||||
var tmp = getNimNode(m)
|
var tmp = getNimNode(m)
|
||||||
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
|
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
|
||||||
[tmp, toRope(firstOrd(typ)), name])
|
[tmp, toRope(firstOrd(typ)), name])
|
||||||
|
|
||||||
proc genArrayInfo(m: BModule, typ: PType, name: PRope) =
|
proc genArrayInfo(m: BModule, typ: PType, name: PRope) =
|
||||||
genTypeInfoAuxBase(m, typ, name, genTypeInfo(m, typ.sons[1]))
|
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1]))
|
||||||
|
|
||||||
proc fakeClosureType(owner: PSym): PType =
|
proc fakeClosureType(owner: PSym): PType =
|
||||||
# we generate the same RTTI as for a tuple[pointer, ref tuple[]]
|
# we generate the same RTTI as for a tuple[pointer, ref tuple[]]
|
||||||
|
|
@ -946,23 +946,23 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyEmpty: result = toRope"0"
|
of tyEmpty: result = toRope"0"
|
||||||
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
|
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
|
||||||
genTypeInfoAuxBase(m, t, result, toRope"0")
|
genTypeInfoAuxBase(m, t, t, result, toRope"0")
|
||||||
of tyProc:
|
of tyProc:
|
||||||
if t.callConv != ccClosure:
|
if t.callConv != ccClosure:
|
||||||
genTypeInfoAuxBase(m, t, result, toRope"0")
|
genTypeInfoAuxBase(m, t, t, result, toRope"0")
|
||||||
else:
|
else:
|
||||||
genTupleInfo(m, fakeClosureType(t.owner), result)
|
genTupleInfo(m, fakeClosureType(t.owner), result)
|
||||||
of tySequence, tyRef:
|
of tySequence, tyRef:
|
||||||
genTypeInfoAux(m, t, result)
|
genTypeInfoAux(m, t, t, result)
|
||||||
if gSelectedGC >= gcMarkAndSweep:
|
if gSelectedGC >= gcMarkAndSweep:
|
||||||
let markerProc = genTraverseProc(m, t, tiNew)
|
let markerProc = genTraverseProc(m, t, tiNew)
|
||||||
appf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
|
appf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
|
||||||
of tyPtr, tyRange: genTypeInfoAux(m, t, result)
|
of tyPtr, tyRange: genTypeInfoAux(m, t, t, result)
|
||||||
of tyArrayConstr, tyArray: genArrayInfo(m, t, result)
|
of tyArrayConstr, tyArray: genArrayInfo(m, t, result)
|
||||||
of tySet: genSetInfo(m, t, result)
|
of tySet: genSetInfo(m, t, result)
|
||||||
of tyEnum: genEnumInfo(m, t, result)
|
of tyEnum: genEnumInfo(m, t, result)
|
||||||
of tyObject: genObjectInfo(m, t, result)
|
of tyObject: genObjectInfo(m, t, origType, result)
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
# if t.n != nil: genObjectInfo(m, t, result)
|
# if t.n != nil: genObjectInfo(m, t, result)
|
||||||
# else:
|
# else:
|
||||||
# BUGFIX: use consistently RTTI without proper field names; otherwise
|
# BUGFIX: use consistently RTTI without proper field names; otherwise
|
||||||
|
|
|
||||||
|
|
@ -402,11 +402,8 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||||
|
|
||||||
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
if gCmd == cmdCompileToLLVM:
|
result.r = con("LOC", toRope(p.labels))
|
||||||
result.r = con("%LOC", toRope(p.labels))
|
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
|
||||||
else:
|
|
||||||
result.r = con("LOC", toRope(p.labels))
|
|
||||||
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
|
|
||||||
result.k = locTemp
|
result.k = locTemp
|
||||||
#result.a = - 1
|
#result.a = - 1
|
||||||
result.t = getUniqueType(t)
|
result.t = getUniqueType(t)
|
||||||
|
|
@ -494,22 +491,26 @@ proc localDebugInfo(p: BProc, s: PSym) =
|
||||||
inc(p.maxFrameLen)
|
inc(p.maxFrameLen)
|
||||||
inc p.blocks[p.blocks.len-1].frameLen
|
inc p.blocks[p.blocks.len-1].frameLen
|
||||||
|
|
||||||
proc assignLocalVar(p: BProc, s: PSym) =
|
proc localVarDecl(p: BProc; s: PSym): PRope =
|
||||||
#assert(s.loc.k == locNone) // not yet assigned
|
|
||||||
# this need not be fullfilled for inline procs; they are regenerated
|
|
||||||
# for each module that uses them!
|
|
||||||
if s.loc.k == locNone:
|
if s.loc.k == locNone:
|
||||||
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
|
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
|
||||||
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
|
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
|
||||||
var decl = getTypeDesc(p.module, s.loc.t)
|
result = getTypeDesc(p.module, s.loc.t)
|
||||||
if s.constraint.isNil:
|
if s.constraint.isNil:
|
||||||
if sfRegister in s.flags: app(decl, " register")
|
if sfRegister in s.flags: app(result, " register")
|
||||||
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
||||||
# app(decl, " GC_GUARD")
|
# app(decl, " GC_GUARD")
|
||||||
if sfVolatile in s.flags: app(decl, " volatile")
|
if sfVolatile in s.flags: app(result, " volatile")
|
||||||
appf(decl, " $1;$n", [s.loc.r])
|
app(result, " ")
|
||||||
|
app(result, s.loc.r)
|
||||||
else:
|
else:
|
||||||
decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r)
|
result = ropef(s.cgDeclFrmt, result, s.loc.r)
|
||||||
|
|
||||||
|
proc assignLocalVar(p: BProc, s: PSym) =
|
||||||
|
#assert(s.loc.k == locNone) // not yet assigned
|
||||||
|
# this need not be fullfilled for inline procs; they are regenerated
|
||||||
|
# for each module that uses them!
|
||||||
|
let decl = localVarDecl(p, s).con(";" & tnl)
|
||||||
line(p, cpsLocals, decl)
|
line(p, cpsLocals, decl)
|
||||||
localDebugInfo(p, s)
|
localDebugInfo(p, s)
|
||||||
|
|
||||||
|
|
@ -586,6 +587,11 @@ proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
|
||||||
initLoc(result, locNone, e.typ, OnUnknown)
|
initLoc(result, locNone, e.typ, OnUnknown)
|
||||||
expr(p, e, result)
|
expr(p, e, result)
|
||||||
|
|
||||||
|
proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
|
||||||
|
initLoc(result, locNone, e.typ, OnUnknown)
|
||||||
|
result.flags.incl lfSingleUse
|
||||||
|
expr(p, e, result)
|
||||||
|
|
||||||
proc lenField(p: BProc): PRope =
|
proc lenField(p: BProc): PRope =
|
||||||
result = toRope(if p.module.compileToCpp: "len" else: "Sup.len")
|
result = toRope(if p.module.compileToCpp: "len" else: "Sup.len")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,8 +80,13 @@ elif defined(windows) or defined(dos):
|
||||||
# Native Windows Implementation
|
# Native Windows Implementation
|
||||||
# =======================================================================
|
# =======================================================================
|
||||||
#
|
#
|
||||||
type
|
when defined(cpp):
|
||||||
THINSTANCE {.importc: "HINSTANCE".} = pointer
|
type
|
||||||
|
THINSTANCE {.importc: "HINSTANCE".} = object
|
||||||
|
x: pointer
|
||||||
|
else:
|
||||||
|
type
|
||||||
|
THINSTANCE {.importc: "HINSTANCE".} = pointer
|
||||||
|
|
||||||
proc freeLibrary(lib: THINSTANCE) {.
|
proc freeLibrary(lib: THINSTANCE) {.
|
||||||
importc: "FreeLibrary", header: "<windows.h>", stdcall.}
|
importc: "FreeLibrary", header: "<windows.h>", stdcall.}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue