C++ support: codegen generates C++'s references and avoids copies

This commit is contained in:
Araq 2015-02-03 13:21:05 +01:00
commit e75e421912
7 changed files with 156 additions and 101 deletions

View file

@ -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

View file

@ -45,6 +45,14 @@ 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 p.module.compileToCpp and lfSingleUse in d.flags:
# do not generate spurious temporaries for C++! For C we're better off
# with them to prevent undefined behaviour and because the codegen
# is free to emit expressions multiple times!
d.k = locCall
d.r = pl
excl d.flags, lfSingleUse
else:
if d.k == locNone: getTemp(p, typ.sons[0], d) if d.k == locNone: getTemp(p, typ.sons[0], d)
assert(d.t != nil) # generate an assignment to d: assert(d.t != nil) # generate an assignment to d:
var list: TLoc var list: TLoc
@ -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,6 +383,14 @@ 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 p.module.compileToCpp and lfSingleUse in d.flags:
# do not generate spurious temporaries for C++! For C we're better off
# with them to prevent undefined behaviour and because the codegen
# is free to emit expressions multiple times!
d.k = locCall
d.r = pl
excl d.flags, lfSingleUse
else:
if d.k == locNone: getTemp(p, typ.sons[0], d) if d.k == locNone: getTemp(p, typ.sons[0], d)
assert(d.t != nil) # generate an assignment to d: assert(d.t != nil) # generate an assignment to d:
var list: TLoc var list: TLoc

View file

@ -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,6 +1243,7 @@ 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
if t.kind != tyVar or not p.module.compileToCpp:
r = rfmt(nil, "(*$1)", r) 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:
@ -1863,6 +1871,7 @@ 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
if t.kind != tyVar or not p.module.compileToCpp:
r = ropef("(*$1)", [r]) r = ropef("(*$1)", [r])
t = skipTypes(t.lastSon, abstractInst) t = skipTypes(t.lastSon, abstractInst)
if not p.module.compileToCpp: if not p.module.compileToCpp:
@ -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)

View file

@ -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)

View file

@ -162,6 +162,12 @@ 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)
@ -183,6 +189,7 @@ proc isInvalidReturnType(rettype: PType): bool =
{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,6 +422,10 @@ 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)
# for importcpp'ed objects, we only need to set field.loc, but don't
# have to recurse via 'getTypeDescAux'. And not doing so prevents problems
# with heavily templatized C++ code:
if not isImportedCppType(rectype):
let fieldType = field.loc.t.skipTypes(abstractInst) let fieldType = field.loc.t.skipTypes(abstractInst)
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags: if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
appf(result, "$1 $2[SEQ_DECL_SIZE];$n", appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
@ -494,12 +499,14 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
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,10 +813,11 @@ 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)
if not isImportedCppType(typ):
genObjectFields(m, typ, typ.n, tmp) 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]
@ -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,22 +946,22 @@ 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:

View file

@ -402,9 +402,6 @@ 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))
else:
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) linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
result.k = locTemp result.k = locTemp
@ -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 localVarDecl(p: BProc; s: PSym): PRope =
if s.loc.k == locNone:
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
result = getTypeDesc(p.module, s.loc.t)
if s.constraint.isNil:
if sfRegister in s.flags: app(result, " register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# app(decl, " GC_GUARD")
if sfVolatile in s.flags: app(result, " volatile")
app(result, " ")
app(result, s.loc.r)
else:
result = ropef(s.cgDeclFrmt, result, s.loc.r)
proc assignLocalVar(p: BProc, s: PSym) = proc assignLocalVar(p: BProc, s: PSym) =
#assert(s.loc.k == locNone) // not yet assigned #assert(s.loc.k == locNone) // not yet assigned
# this need not be fullfilled for inline procs; they are regenerated # this need not be fullfilled for inline procs; they are regenerated
# for each module that uses them! # for each module that uses them!
if s.loc.k == locNone: let decl = localVarDecl(p, s).con(";" & tnl)
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
var decl = getTypeDesc(p.module, s.loc.t)
if s.constraint.isNil:
if sfRegister in s.flags: app(decl, " register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# app(decl, " GC_GUARD")
if sfVolatile in s.flags: app(decl, " volatile")
appf(decl, " $1;$n", [s.loc.r])
else:
decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r)
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")

View file

@ -80,6 +80,11 @@ elif defined(windows) or defined(dos):
# Native Windows Implementation # Native Windows Implementation
# ======================================================================= # =======================================================================
# #
when defined(cpp):
type
THINSTANCE {.importc: "HINSTANCE".} = object
x: pointer
else:
type type
THINSTANCE {.importc: "HINSTANCE".} = pointer THINSTANCE {.importc: "HINSTANCE".} = pointer