mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-22 00:41:28 +00:00
use cbuilder for most of ccgcalls (#24407)
The only missing parts are Objective C named param calls and `genThisArg` for C++ interop.
This commit is contained in:
@@ -75,9 +75,14 @@ proc initCallBuilder(builder: var Builder, callee: Snippet): CallBuilder =
|
||||
builder.add(callee)
|
||||
builder.add("(")
|
||||
|
||||
proc addArgumentSeparator(builder: var Builder) =
|
||||
# no-op on NIFC
|
||||
# used by "single argument" builders
|
||||
builder.add(", ")
|
||||
|
||||
template addArgument(builder: var Builder, call: var CallBuilder, valueBody: typed) =
|
||||
if call.needsComma:
|
||||
builder.add(", ")
|
||||
builder.addArgumentSeparator()
|
||||
else:
|
||||
call.needsComma = true
|
||||
valueBody
|
||||
|
||||
@@ -84,20 +84,21 @@ proc cleanupTemp(p: BProc; returnType: PType, tmp: TLoc): bool =
|
||||
let dtor = getAttachedOp(p.module.g.graph, returnType, attachedDestructor)
|
||||
var op = initLocExpr(p, newSymNode(dtor))
|
||||
var callee = rdLoc(op)
|
||||
let destroy = if dtor.typ.firstParamType.kind == tyVar:
|
||||
callee & "(&" & rdLoc(tmp) & ")"
|
||||
let destroyArg =
|
||||
if dtor.typ.firstParamType.kind == tyVar:
|
||||
cAddr(rdLoc(tmp))
|
||||
else:
|
||||
callee & "(" & rdLoc(tmp) & ")"
|
||||
rdLoc(tmp)
|
||||
let destroy = cCall(callee, destroyArg)
|
||||
raiseExitCleanup(p, destroy)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
callee, params: Rope) =
|
||||
result: var Builder, call: var CallBuilder) =
|
||||
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
|
||||
genLineDir(p, ri)
|
||||
var pl = callee & "(" & params
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||
if typ.returnType != nil:
|
||||
@@ -106,7 +107,6 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
# perhaps generate no temp if the call doesn't have side effects
|
||||
flags.incl needTempForOpenArray
|
||||
if isInvalidReturnType(p.config, typ):
|
||||
if params.len != 0: pl.add(", ")
|
||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
|
||||
# Great, we can use 'd':
|
||||
@@ -114,33 +114,39 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
elif d.k notin {locTemp} and not hasNoInit(ri):
|
||||
# reset before pass as 'result' var:
|
||||
discard "resetLoc(p, d)"
|
||||
pl.add(addrLoc(p.config, d))
|
||||
pl.add(");\n")
|
||||
line(p, cpsStmts, pl)
|
||||
let rad = addrLoc(p.config, d)
|
||||
result.addArgument(call):
|
||||
result.add(rad)
|
||||
result.finishCallBuilder(call)
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(extract(result))
|
||||
else:
|
||||
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
|
||||
pl.add(addrLoc(p.config, tmp))
|
||||
pl.add(");\n")
|
||||
line(p, cpsStmts, pl)
|
||||
let ratmp = addrLoc(p.config, tmp)
|
||||
result.addArgument(call):
|
||||
result.add(ratmp)
|
||||
result.finishCallBuilder(call)
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(extract(result))
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
if canRaise: raiseExit(p)
|
||||
else:
|
||||
pl.add(")")
|
||||
result.finishCallBuilder(call)
|
||||
if p.module.compileToCpp:
|
||||
if 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.snippet = pl
|
||||
d.snippet = extract(result)
|
||||
excl d.flags, lfSingleUse
|
||||
else:
|
||||
if d.k == locNone and p.splitDecls == 0:
|
||||
d = getTempCpp(p, typ.returnType, pl)
|
||||
d = getTempCpp(p, typ.returnType, extract(result))
|
||||
else:
|
||||
if d.k == locNone: d = getTemp(p, typ.returnType)
|
||||
var list = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.snippet = pl
|
||||
list.snippet = extract(result)
|
||||
genAssignment(p, d, list, {needAssignCall}) # no need for deep copying
|
||||
if canRaise: raiseExit(p)
|
||||
|
||||
@@ -151,7 +157,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
d = getTemp(p, typ.returnType)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.snippet = pl
|
||||
list.snippet = extract(result)
|
||||
genAssignment(p, d, list, flags+{needAssignCall}) # no need for deep copying
|
||||
if canRaise:
|
||||
if not (useTemp and cleanupTemp(p, typ.returnType, d)):
|
||||
@@ -159,15 +165,16 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
else:
|
||||
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
|
||||
var list = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.snippet = pl
|
||||
list.snippet = extract(result)
|
||||
genAssignment(p, tmp, list, flags+{needAssignCall}) # no need for deep copying
|
||||
if canRaise:
|
||||
if not cleanupTemp(p, typ.returnType, tmp):
|
||||
raiseExit(p)
|
||||
genAssignment(p, d, tmp, {})
|
||||
else:
|
||||
pl.add(");\n")
|
||||
line(p, cpsStmts, pl)
|
||||
finishCallBuilder(result, call)
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(extract(result))
|
||||
if canRaise: raiseExit(p)
|
||||
|
||||
proc genBoundsCheck(p: BProc; arr, a, b: TLoc; arrTyp: PType)
|
||||
@@ -199,48 +206,49 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
|
||||
if optBoundsCheck in p.options:
|
||||
genBoundsCheck(p, a, b, c, ty)
|
||||
if prepareForMutation:
|
||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||
let bra = byRefLoc(p, a)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimPrepareStrMutationV2"),
|
||||
bra)
|
||||
let dest = getTypeDesc(p.module, destType)
|
||||
let lengthExpr = "($1)-($2)+1" % [rdLoc(c), rdLoc(b)]
|
||||
let ra = rdLoc(a)
|
||||
let rb = rdLoc(b)
|
||||
let rc = rdLoc(c)
|
||||
let lengthExpr = cOp(Add, "NI", cOp(Sub, "NI", rc, rb), cIntValue(1))
|
||||
case ty.kind
|
||||
of tyArray:
|
||||
let first = toInt64(firstOrd(p.config, ty))
|
||||
if first == 0:
|
||||
result = ("($3*)(($1)+($2))" % [rdLoc(a), rdLoc(b), dest],
|
||||
lengthExpr)
|
||||
result = (cCast(ptrType(dest), cOp(Add, "NI", ra, rb)), lengthExpr)
|
||||
else:
|
||||
let lit = cIntLiteral(first)
|
||||
result = ("($4*)($1)+(($2)-($3))" %
|
||||
[rdLoc(a), rdLoc(b), lit, dest],
|
||||
lengthExpr)
|
||||
result = (cCast(ptrType(dest), cOp(Add, "NI", ra, cOp(Sub, "NI", rb, lit))), lengthExpr)
|
||||
of tyOpenArray, tyVarargs:
|
||||
if reifiedOpenArray(q[1]):
|
||||
result = ("($3*)($1.Field0)+($2)" % [rdLoc(a), rdLoc(b), dest],
|
||||
lengthExpr)
|
||||
else:
|
||||
result = ("($3*)($1)+($2)" % [rdLoc(a), rdLoc(b), dest],
|
||||
lengthExpr)
|
||||
let data = if reifiedOpenArray(q[1]): dotField(ra, "Field0") else: ra
|
||||
result = (cCast(ptrType(dest), cOp(Add, "NI", data, rb)), lengthExpr)
|
||||
of tyUncheckedArray, tyCstring:
|
||||
result = ("($3*)($1)+($2)" % [rdLoc(a), rdLoc(b), dest],
|
||||
lengthExpr)
|
||||
result = (cCast(ptrType(dest), cOp(Add, "NI", ra, rb)), lengthExpr)
|
||||
of tyString, tySequence:
|
||||
let atyp = skipTypes(a.t, abstractInst)
|
||||
if formalType.skipTypes(abstractInst).kind in {tyVar} and atyp.kind == tyString and
|
||||
optSeqDestructors in p.config.globalOptions:
|
||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||
let bra = byRefLoc(p, a)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimPrepareStrMutationV2"),
|
||||
bra)
|
||||
var val: Snippet
|
||||
if atyp.kind in {tyVar} and not compileToCpp(p.module):
|
||||
result = ("(($5) ? (($4*)(*$1)$3+($2)) : NIM_NIL)" %
|
||||
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, "*" & rdLoc(a))],
|
||||
lengthExpr)
|
||||
val = cDeref(ra)
|
||||
else:
|
||||
result = ("(($5) ? (($4*)$1$3+($2)) : NIM_NIL)" %
|
||||
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, rdLoc(a))],
|
||||
lengthExpr)
|
||||
val = ra
|
||||
result = (
|
||||
cIfExpr(dataFieldAccessor(p, val),
|
||||
cCast(ptrType(dest), cOp(Add, "NI", dataField(p, val), rb)),
|
||||
"NIM_NIL"),
|
||||
lengthExpr)
|
||||
else:
|
||||
result = ("", "")
|
||||
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
|
||||
|
||||
proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
|
||||
proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Builder) =
|
||||
var q = skipConv(n)
|
||||
var skipped = false
|
||||
while q.kind == nkStmtListExpr and q.len > 0:
|
||||
@@ -255,42 +263,66 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
|
||||
genStmts(p, q[i])
|
||||
q = q.lastSon
|
||||
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ.elementType)
|
||||
result.add x & ", " & y
|
||||
result.add(x)
|
||||
result.addArgumentSeparator()
|
||||
result.add(y)
|
||||
else:
|
||||
var a = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n)
|
||||
case skipTypes(a.t, abstractVar+{tyStatic}).kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
let ra = rdLoc(a)
|
||||
if reifiedOpenArray(n):
|
||||
if a.t.kind in {tyVar, tyLent}:
|
||||
result.add "$1->Field0, $1->Field1" % [rdLoc(a)]
|
||||
result.add(derefField(ra, "Field0"))
|
||||
result.addArgumentSeparator()
|
||||
result.add(derefField(ra, "Field1"))
|
||||
else:
|
||||
result.add "$1.Field0, $1.Field1" % [rdLoc(a)]
|
||||
result.add(dotField(ra, "Field0"))
|
||||
result.addArgumentSeparator()
|
||||
result.add(dotField(ra, "Field1"))
|
||||
else:
|
||||
result.add "$1, $1Len_0" % [rdLoc(a)]
|
||||
result.add(ra)
|
||||
result.addArgumentSeparator()
|
||||
result.add(ra & "Len_0")
|
||||
of tyString, tySequence:
|
||||
let ntyp = skipTypes(n.typ, abstractInst)
|
||||
if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and
|
||||
optSeqDestructors in p.config.globalOptions:
|
||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||
let bra = byRefLoc(p, a)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimPrepareStrMutationV2"),
|
||||
bra)
|
||||
if ntyp.kind in {tyVar} and not compileToCpp(p.module):
|
||||
var t = TLoc(snippet: "(*$1)" % [a.rdLoc])
|
||||
result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" %
|
||||
[a.rdLoc, lenExpr(p, t), dataField(p),
|
||||
dataFieldAccessor(p, "*" & a.rdLoc)]
|
||||
let ra = a.rdLoc
|
||||
var t = TLoc(snippet: cDeref(ra))
|
||||
let lt = lenExpr(p, t)
|
||||
result.add(cIfExpr(dataFieldAccessor(p, t.snippet), dataField(p, t.snippet), "NIM_NIL"))
|
||||
result.addArgumentSeparator()
|
||||
result.add(lt)
|
||||
else:
|
||||
result.add "($4) ? ($1$3) : NIM_NIL, $2" %
|
||||
[a.rdLoc, lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)]
|
||||
let ra = a.rdLoc
|
||||
let la = lenExpr(p, a)
|
||||
result.add(cIfExpr(dataFieldAccessor(p, ra), dataField(p, ra), "NIM_NIL"))
|
||||
result.addArgumentSeparator()
|
||||
result.add(la)
|
||||
of tyArray:
|
||||
result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))]
|
||||
let ra = rdLoc(a)
|
||||
result.add(ra)
|
||||
result.addArgumentSeparator()
|
||||
result.addIntValue(lengthOrd(p.config, a.t))
|
||||
of tyPtr, tyRef:
|
||||
case elementType(a.t).kind
|
||||
of tyString, tySequence:
|
||||
var t = TLoc(snippet: "(*$1)" % [a.rdLoc])
|
||||
result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" %
|
||||
[a.rdLoc, lenExpr(p, t), dataField(p),
|
||||
dataFieldAccessor(p, "*" & a.rdLoc)]
|
||||
let ra = a.rdLoc
|
||||
var t = TLoc(snippet: cDeref(ra))
|
||||
let lt = lenExpr(p, t)
|
||||
result.add(cIfExpr(dataFieldAccessor(p, t.snippet), dataField(p, t.snippet), "NIM_NIL"))
|
||||
result.addArgumentSeparator()
|
||||
result.add(lt)
|
||||
of tyArray:
|
||||
result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, elementType(a.t)))]
|
||||
let ra = rdLoc(a)
|
||||
result.add(ra)
|
||||
result.addArgumentSeparator()
|
||||
result.addIntValue(lengthOrd(p.config, elementType(a.t)))
|
||||
else:
|
||||
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
|
||||
else: internalError(p.config, "openArrayLoc: " & typeToString(a.t))
|
||||
@@ -310,11 +342,12 @@ proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc =
|
||||
result = getTemp(p, a.lode.typ, needsInit=false)
|
||||
genAssignment(p, result, a, {})
|
||||
|
||||
proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} =
|
||||
proc genArgStringToCString(p: BProc, n: PNode; result: var Builder; needsTmp: bool) {.inline.} =
|
||||
var a = initLocExpr(p, n[0])
|
||||
appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc])
|
||||
let ra = withTmpIfNeeded(p, a, needsTmp).rdLoc
|
||||
result.addCall(cgsymValue(p.module, "nimToCStringConv"), ra)
|
||||
|
||||
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) =
|
||||
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Builder; needsTmp = false) =
|
||||
var a: TLoc
|
||||
if n.kind == nkStringToCString:
|
||||
genArgStringToCString(p, n, result, needsTmp)
|
||||
@@ -355,12 +388,11 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
|
||||
if param.typ.kind in {tyVar, tyPtr, tyRef, tySink}:
|
||||
let typ = skipTypes(param.typ, abstractPtrs)
|
||||
if not sameBackendTypePickyAliases(typ, n.typ.skipTypes(abstractPtrs)):
|
||||
a.snippet = "(($1) ($2))" %
|
||||
[getTypeDesc(p.module, param.typ), rdCharLoc(a)]
|
||||
a.snippet = cCast(getTypeDesc(p.module, param.typ), rdCharLoc(a))
|
||||
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
|
||||
#assert result != nil
|
||||
|
||||
proc genArgNoParam(p: BProc, n: PNode; result: var Rope; needsTmp = false) =
|
||||
proc genArgNoParam(p: BProc, n: PNode; result: var Builder; needsTmp = false) =
|
||||
var a: TLoc
|
||||
if n.kind == nkStringToCString:
|
||||
genArgStringToCString(p, n, result, needsTmp)
|
||||
@@ -423,7 +455,7 @@ proc getPotentialReads(n: PNode; result: var seq[PNode]) =
|
||||
for s in n:
|
||||
getPotentialReads(s, result)
|
||||
|
||||
proc genParams(p: BProc, ri: PNode, typ: PType; result: var Rope) =
|
||||
proc genParams(p: BProc, ri: PNode, typ: PType; result: var Builder, argBuilder: var CallBuilder) =
|
||||
# We must generate temporaries in cases like #14396
|
||||
# to keep the strict Left-To-Right evaluation
|
||||
var needTmp = newSeq[bool](ri.len - 1)
|
||||
@@ -445,21 +477,22 @@ proc genParams(p: BProc, ri: PNode, typ: PType; result: var Rope) =
|
||||
# Optimization: don't use a temp, if we would only take the address anyway
|
||||
needTmp[i - 1] = false
|
||||
|
||||
var oldLen = result.len
|
||||
for i in 1..<ri.len:
|
||||
if i < typ.n.len:
|
||||
assert(typ.n[i].kind == nkSym)
|
||||
let paramType = typ.n[i]
|
||||
if not paramType.typ.isCompileTimeOnly:
|
||||
if oldLen != result.len:
|
||||
result.add(", ")
|
||||
oldLen = result.len
|
||||
genArg(p, ri[i], paramType.sym, ri, result, needTmp[i-1])
|
||||
var arg = newBuilder("")
|
||||
genArg(p, ri[i], paramType.sym, ri, arg, needTmp[i-1])
|
||||
if arg.buf.len != 0:
|
||||
result.addArgument(argBuilder):
|
||||
result.add(extract(arg))
|
||||
else:
|
||||
if oldLen != result.len:
|
||||
result.add(", ")
|
||||
oldLen = result.len
|
||||
genArgNoParam(p, ri[i], result, needTmp[i-1])
|
||||
var arg = newBuilder("")
|
||||
genArgNoParam(p, ri[i], arg, needTmp[i-1])
|
||||
if arg.buf.len != 0:
|
||||
result.addArgument(argBuilder):
|
||||
result.add(extract(arg))
|
||||
|
||||
proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
|
||||
if sym.flags * {sfImportc, sfNonReloadable} == {} and sym.loc.k == locProc and
|
||||
@@ -473,21 +506,39 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var typ = skipTypes(ri[0].typ, abstractInstOwned)
|
||||
assert(typ.kind == tyProc)
|
||||
|
||||
var params = newRopeAppender()
|
||||
genParams(p, ri, typ, params)
|
||||
|
||||
var callee = rdLoc(op)
|
||||
if p.hcrOn and ri[0].kind == nkSym:
|
||||
callee.addActualSuffixForHCR(p.module.module, ri[0].sym)
|
||||
fixupCall(p, le, ri, d, callee, params)
|
||||
|
||||
var res = newBuilder("")
|
||||
var call = initCallBuilder(res, callee)
|
||||
genParams(p, ri, typ, res, call)
|
||||
fixupCall(p, le, ri, d, res, call)
|
||||
|
||||
proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
|
||||
proc addComma(r: Rope): Rope =
|
||||
if r.len == 0: r else: r & ", "
|
||||
template callProc(rp, params, pTyp: Snippet): Snippet =
|
||||
let e = dotField(rp, "ClE_0")
|
||||
let p = dotField(rp, "ClP_0")
|
||||
let eCall =
|
||||
# note `params` here is actually multiple params
|
||||
if params.len == 0:
|
||||
cCall(p, e)
|
||||
else:
|
||||
cCall(p, params, e)
|
||||
cIfExpr(e,
|
||||
eCall,
|
||||
cCall(cCast(pTyp, p), params))
|
||||
|
||||
const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)"
|
||||
const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists
|
||||
template callIter(rp, params: Snippet): Snippet =
|
||||
# we know the env exists
|
||||
let e = dotField(rp, "ClE_0")
|
||||
let p = dotField(rp, "ClP_0")
|
||||
# note `params` here is actually multiple params
|
||||
if params.len == 0:
|
||||
cCall(p, e)
|
||||
else:
|
||||
cCall(p, params, e)
|
||||
|
||||
var op = initLocExpr(p, ri[0])
|
||||
|
||||
@@ -495,20 +546,23 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var typ = skipTypes(ri[0].typ, abstractInstOwned)
|
||||
assert(typ.kind == tyProc)
|
||||
|
||||
var pl = newRopeAppender()
|
||||
genParams(p, ri, typ, pl)
|
||||
var params = newBuilder("")
|
||||
var argBuilder = default(CallBuilder) # not initCallBuilder, we just want the params
|
||||
genParams(p, ri, typ, params, argBuilder)
|
||||
|
||||
template genCallPattern {.dirty.} =
|
||||
if tfIterator in typ.flags:
|
||||
lineF(p, cpsStmts, PatIter & ";$n", [rdLoc(op), pl, pl.addComma, rawProc])
|
||||
else:
|
||||
lineF(p, cpsStmts, PatProc & ";$n", [rdLoc(op), pl, pl.addComma, rawProc])
|
||||
let rp = rdLoc(op)
|
||||
let pars = extract(params)
|
||||
p.s(cpsStmts).addStmt():
|
||||
if tfIterator in typ.flags:
|
||||
p.s(cpsStmts).add(callIter(rp, pars))
|
||||
else:
|
||||
p.s(cpsStmts).add(callProc(rp, pars, rawProc))
|
||||
|
||||
let rawProc = getClosureType(p.module, typ, clHalf)
|
||||
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
|
||||
if typ.returnType != nil:
|
||||
if isInvalidReturnType(p.config, typ):
|
||||
if ri.len > 1: pl.add(", ")
|
||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
|
||||
# Great, we can use 'd':
|
||||
@@ -517,12 +571,14 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
elif d.k notin {locTemp} and not hasNoInit(ri):
|
||||
# reset before pass as 'result' var:
|
||||
discard "resetLoc(p, d)"
|
||||
pl.add(addrLoc(p.config, d))
|
||||
params.addArgument(argBuilder):
|
||||
params.add(addrLoc(p.config, d))
|
||||
genCallPattern()
|
||||
if canRaise: raiseExit(p)
|
||||
else:
|
||||
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
|
||||
pl.add(addrLoc(p.config, tmp))
|
||||
params.addArgument(argBuilder):
|
||||
params.add(addrLoc(p.config, tmp))
|
||||
genCallPattern()
|
||||
if canRaise: raiseExit(p)
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
@@ -530,20 +586,24 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
if d.k == locNone: d = getTemp(p, typ.returnType)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
|
||||
let rp = rdLoc(op)
|
||||
let pars = extract(params)
|
||||
if tfIterator in typ.flags:
|
||||
list.snippet = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
list.snippet = callIter(rp, pars)
|
||||
else:
|
||||
list.snippet = PatProc % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
list.snippet = callProc(rp, pars, rawProc)
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
if canRaise: raiseExit(p)
|
||||
else:
|
||||
var tmp: TLoc = getTemp(p, typ.returnType)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
|
||||
let rp = rdLoc(op)
|
||||
let pars = extract(params)
|
||||
if tfIterator in typ.flags:
|
||||
list.snippet = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
list.snippet = callIter(rp, pars)
|
||||
else:
|
||||
list.snippet = PatProc % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
list.snippet = callProc(rp, pars, rawProc)
|
||||
genAssignment(p, tmp, list, {})
|
||||
if canRaise: raiseExit(p)
|
||||
genAssignment(p, d, tmp, {})
|
||||
@@ -551,8 +611,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
genCallPattern()
|
||||
if canRaise: raiseExit(p)
|
||||
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope;
|
||||
argsCounter: var int) =
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder;
|
||||
argBuilder: var CallBuilder) =
|
||||
if i < typ.n.len:
|
||||
# 'var T' is 'T&' in C++. This means we ignore the request of
|
||||
# any nkHiddenAddr when it's a 'var T'.
|
||||
@@ -561,20 +621,17 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope;
|
||||
if paramType.typ.isCompileTimeOnly:
|
||||
discard
|
||||
elif paramType.typ.kind in {tyVar} and ri[i].kind == nkHiddenAddr:
|
||||
if argsCounter > 0: result.add ", "
|
||||
genArgNoParam(p, ri[i][0], result)
|
||||
inc argsCounter
|
||||
result.addArgument(argBuilder):
|
||||
genArgNoParam(p, ri[i][0], result)
|
||||
else:
|
||||
if argsCounter > 0: result.add ", "
|
||||
genArgNoParam(p, ri[i], result) #, typ.n[i].sym)
|
||||
inc argsCounter
|
||||
result.addArgument(argBuilder):
|
||||
genArgNoParam(p, ri[i], result) #, typ.n[i].sym)
|
||||
else:
|
||||
if tfVarargs notin typ.flags:
|
||||
localError(p.config, ri.info, "wrong argument count")
|
||||
else:
|
||||
if argsCounter > 0: result.add ", "
|
||||
genArgNoParam(p, ri[i], result)
|
||||
inc argsCounter
|
||||
result.addArgument(argBuilder):
|
||||
genArgNoParam(p, ri[i], result)
|
||||
|
||||
discard """
|
||||
Dot call syntax in C++
|
||||
@@ -631,7 +688,7 @@ proc skipAddrDeref(node: PNode): PNode =
|
||||
else:
|
||||
result = node
|
||||
|
||||
proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope) =
|
||||
proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder) =
|
||||
# for better or worse c2nim translates the 'this' argument to a 'var T'.
|
||||
# However manual wrappers may also use 'ptr T'. In any case we support both
|
||||
# for convenience.
|
||||
@@ -666,15 +723,15 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope) =
|
||||
genArgNoParam(p, ri, result) #, typ.n[i].sym)
|
||||
result.add(".")
|
||||
|
||||
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Rope) =
|
||||
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Builder) =
|
||||
var i = 0
|
||||
var j = 1
|
||||
while i < pat.len:
|
||||
case pat[i]
|
||||
of '@':
|
||||
var argsCounter = 0
|
||||
var callBuilder = default(CallBuilder) # not init call builder
|
||||
for k in j..<ri.len:
|
||||
genOtherArg(p, ri, k, typ, result, argsCounter)
|
||||
genOtherArg(p, ri, k, typ, result, callBuilder)
|
||||
inc i
|
||||
of '#':
|
||||
if i+1 < pat.len and pat[i+1] in {'+', '@'}:
|
||||
@@ -684,11 +741,11 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
|
||||
if pat[i+1] == '+': genArgNoParam(p, ri[0], result)
|
||||
result.add("(")
|
||||
if 1 < ri.len:
|
||||
var argsCounterB = 0
|
||||
genOtherArg(p, ri, 1, typ, result, argsCounterB)
|
||||
var callBuilder: CallBuilder = default(CallBuilder)
|
||||
genOtherArg(p, ri, 1, typ, result, callBuilder)
|
||||
for k in j+1..<ri.len:
|
||||
var argsCounterB = 0
|
||||
genOtherArg(p, ri, k, typ, result, argsCounterB)
|
||||
var callBuilder: CallBuilder = default(CallBuilder)
|
||||
genOtherArg(p, ri, k, typ, result, callBuilder)
|
||||
result.add(")")
|
||||
else:
|
||||
localError(p.config, ri.info, "call expression expected for C++ pattern")
|
||||
@@ -702,8 +759,8 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
|
||||
genArgNoParam(p, arg, result)
|
||||
#result.add debugTree(arg, 0, 10)
|
||||
else:
|
||||
var argsCounter = 0
|
||||
genOtherArg(p, ri, j, typ, result, argsCounter)
|
||||
var callBuilder = default(CallBuilder) # not init call builder
|
||||
genOtherArg(p, ri, j, typ, result, callBuilder)
|
||||
inc j
|
||||
inc i
|
||||
of '\'':
|
||||
@@ -729,7 +786,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
let pat = $ri[0].sym.loc.snippet
|
||||
internalAssert p.config, pat.len > 0
|
||||
if pat.contains({'#', '(', '@', '\''}):
|
||||
var pl = newRopeAppender()
|
||||
var pl = newBuilder("")
|
||||
genPatternCall(p, ri, pat, typ, pl)
|
||||
# simpler version of 'fixupCall' that works with the pl+params combination:
|
||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||
@@ -739,32 +796,32 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
# with them to prevent undefined behaviour and because the codegen
|
||||
# is free to emit expressions multiple times!
|
||||
d.k = locCall
|
||||
d.snippet = pl
|
||||
d.snippet = extract(pl)
|
||||
excl d.flags, lfSingleUse
|
||||
else:
|
||||
if d.k == locNone: d = getTemp(p, typ.returnType)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.snippet = pl
|
||||
list.snippet = extract(pl)
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
pl.add(";\n")
|
||||
line(p, cpsStmts, pl)
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(extract(pl))
|
||||
else:
|
||||
var pl = newRopeAppender()
|
||||
var argsCounter = 0
|
||||
var pl = newBuilder("")
|
||||
if 1 < ri.len:
|
||||
genThisArg(p, ri, 1, typ, pl)
|
||||
pl.add(op.snippet)
|
||||
var params = newRopeAppender()
|
||||
var res = newBuilder("")
|
||||
var call = initCallBuilder(res, extract(pl))
|
||||
for i in 2..<ri.len:
|
||||
genOtherArg(p, ri, i, typ, params, argsCounter)
|
||||
fixupCall(p, le, ri, d, pl, params)
|
||||
genOtherArg(p, ri, i, typ, res, call)
|
||||
fixupCall(p, le, ri, d, res, call)
|
||||
|
||||
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
# generates a crappy ObjC call
|
||||
var op = initLocExpr(p, ri[0])
|
||||
var pl = "["
|
||||
var pl = newBuilder("[")
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
@@ -806,24 +863,27 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
if d.k == locNone: d = getTemp(p, typ.returnType, needsInit=true)
|
||||
pl.add("Result: ")
|
||||
pl.add(addrLoc(p.config, d))
|
||||
pl.add("];\n")
|
||||
line(p, cpsStmts, pl)
|
||||
pl.add("]")
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(extract(pl))
|
||||
else:
|
||||
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
|
||||
pl.add(addrLoc(p.config, tmp))
|
||||
pl.add("];\n")
|
||||
line(p, cpsStmts, pl)
|
||||
pl.add("]")
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(extract(pl))
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
else:
|
||||
pl.add("]")
|
||||
if d.k == locNone: d = getTemp(p, typ.returnType)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc = initLoc(locCall, ri, OnUnknown)
|
||||
list.snippet = pl
|
||||
list.snippet = extract(pl)
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
pl.add("];\n")
|
||||
line(p, cpsStmts, pl)
|
||||
pl.add("]")
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(extract(pl))
|
||||
|
||||
proc notYetAlive(n: PNode): bool {.inline.} =
|
||||
let r = getRoot(n)
|
||||
|
||||
@@ -289,16 +289,16 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Builder) =
|
||||
#echo "New code produced for ", v.name.s, " ", p.config $ value.info
|
||||
genBracedInit(p, value, isConst = false, v.typ, result)
|
||||
|
||||
proc genCppParamsForCtor(p: BProc; call: PNode; didGenTemp: var bool): string =
|
||||
result = ""
|
||||
var argsCounter = 0
|
||||
proc genCppParamsForCtor(p: BProc; call: PNode; didGenTemp: var bool): Snippet =
|
||||
var res = newBuilder("")
|
||||
var argBuilder = default(CallBuilder) # not init, only building params
|
||||
let typ = skipTypes(call[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
for i in 1..<call.len:
|
||||
#if it's a type we can just generate here another initializer as we are in an initializer context
|
||||
if call[i].kind == nkCall and call[i][0].kind == nkSym and call[i][0].sym.kind == skType:
|
||||
if argsCounter > 0: result.add ","
|
||||
result.add genCppInitializer(p.module, p, call[i][0].sym.typ, didGenTemp)
|
||||
res.addArgument(argBuilder):
|
||||
res.add genCppInitializer(p.module, p, call[i][0].sym.typ, didGenTemp)
|
||||
else:
|
||||
#We need to test for temp in globals, see: #23657
|
||||
let param =
|
||||
@@ -311,7 +311,8 @@ proc genCppParamsForCtor(p: BProc; call: PNode; didGenTemp: var bool): string =
|
||||
tyVarargs, tySequence, tyString, tyCstring, tyTuple}:
|
||||
let tempLoc = initLocExprSingleUse(p, param)
|
||||
didGenTemp = didGenTemp or tempLoc.k == locTemp
|
||||
genOtherArg(p, call, i, typ, result, argsCounter)
|
||||
genOtherArg(p, call, i, typ, res, argBuilder)
|
||||
result = extract(res)
|
||||
|
||||
proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope, didGenTemp: var bool) =
|
||||
let params = genCppParamsForCtor(p, call, didGenTemp)
|
||||
|
||||
@@ -362,7 +362,7 @@ proc rdLoc(a: TLoc): Rope =
|
||||
else:
|
||||
result = a.snippet
|
||||
|
||||
proc addRdLoc(a: TLoc; result: var Rope) =
|
||||
proc addRdLoc(a: TLoc; result: var Builder) =
|
||||
if lfIndirect in a.flags:
|
||||
result.add cDeref(a.snippet)
|
||||
else:
|
||||
@@ -411,7 +411,7 @@ template mapTypeChooser(n: PNode): TSymKind =
|
||||
|
||||
template mapTypeChooser(a: TLoc): TSymKind = mapTypeChooser(a.lode)
|
||||
|
||||
proc addAddrLoc(conf: ConfigRef; a: TLoc; result: var Rope) =
|
||||
proc addAddrLoc(conf: ConfigRef; a: TLoc; result: var Builder) =
|
||||
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != ctArray:
|
||||
result.add wrapPar(cAddr(a.snippet))
|
||||
else:
|
||||
@@ -782,7 +782,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc)
|
||||
|
||||
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
|
||||
proc genLiteral(p: BProc, n: PNode; result: var Builder)
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int)
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder; argBuilder: var CallBuilder)
|
||||
proc raiseExit(p: BProc)
|
||||
proc raiseExitCleanup(p: BProc, destroy: string)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user