mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-01 19:33:42 +00:00
IC: migrate expr and the emitters — cgen generates from a cursor
`genProcBody` is handed `BNode(bodyBuf.rootCursor)` under `-d:newIcBackend`, so
`expr` and the ~160 procs under it read the routine body through a cursor rather
than a tree. This had to land as one change: `expr` dispatches to all of them, so
they move together or the dispatch converts at every node.
The evidence that it works is not that it compiles. Cursor-driven and
`PNode`-driven builds emit BYTE-IDENTICAL `.c` (50/50 on an 89k-line target,
12/12 on the grind target), the built program runs and prints the right thing,
and — the part that makes the first number mean something — sabotaging
`bnode.intVal` changes all 12 files. The generator is genuinely reading through
the cursor, not quietly falling back.
Four kinds of site could not simply take `AnyNode`, and each is marked where it
sits rather than left for the next person to rediscover:
* THE GENERATOR REWRITES. `mAppendSeqElem`, `mNewSeq`, `genSetLengthSeq`,
`genWasMoved` and `genArrToSeq` replace a child or a type IN PLACE, and
`genEnumToStr`/`mAsgn`/`spawn` build fresh trees. Those run on `origin(n)` —
the very node the buffer was encoded from — so the mutation lands exactly
where it always did. Where the mutation is then READ (`genArrToSeq` retypes a
bracket, `genArg` replaces a `var` param's type), generation continues on the
origin too, because the buffer does not see the write and a cursor would keep
reading the slot as encoded.
* NILABLE NODES stay `PNode`: a cursor has no standalone nil. That is the
assignment DESTINATION throughout the call family (`genCall` passes nil), the
`check` of an object-constructor field, `exvar`, `stepNode`, the `fin` of a
try statement.
* `PNode`-KEYED TABLES AND ANALYSES take `origin`: `dataCache`, `isPartOf`,
`lhsDoesAlias`, `potentialAlias`, the type-record walkers.
* SHARED PREDICATES in `ast.nim` cannot see `BNode`, so `skipHiddenAddr`,
`isInfixAs` and `getStr` join `canRaise`/`getInt` as templates instantiated
for both. `skipPragmaExpr` is a deliberate exception: it sits above the point
in `ast.nim` where `firstSon` for a `PNode` exists, so `bnode` carries a
one-line spelling with a pointer back.
Two Nim details worth recording. Repeated occurrences of a type class in one
signature share ONE implicit generic, so any proc whose two node parameters can
differ in representation needs explicit params — `genSingleVar`,
`genFieldObjConstr`, `callGlobalVarCppCtor`. And a `{.dirty.}` template inside a
generic resolves its identifiers at instantiation, so `genClosureCall`'s local
`rawProc` had to be bound before the template that uses it or it lost to the
module-level proc of the same name.
Verified: grind clean (1431 bodies, 260_431 nodes, 0 disagreements, origins
exact); the default path is byte-identical to HEAD; all four build
configurations compile.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEF7FJvUkGKvG9LSGuEaNR
This commit is contained in:
@@ -714,6 +714,10 @@ proc extractPragma*(s: PSym): PNode =
|
||||
proc skipPragmaExpr*(n: PNode): PNode =
|
||||
## if pragma expr, give the node the pragmas are applied to,
|
||||
## otherwise give node itself
|
||||
##
|
||||
## `bnode` carries the `BNode` spelling. It is a separate one-liner rather
|
||||
## than a shared template because this sits above the point in this module
|
||||
## where `firstSon` for a `PNode` exists.
|
||||
if n.kind == nkPragmaExpr:
|
||||
result = n[0]
|
||||
else:
|
||||
@@ -1505,14 +1509,21 @@ proc getFloat*(a: PNode): BiggestFloat =
|
||||
#internalError(a.info, "getFloat")
|
||||
#result = 0.0
|
||||
|
||||
proc getStr*(a: PNode): string =
|
||||
case a.kind
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal
|
||||
of nkNilLit:
|
||||
# let's hope this fixes more problems than it creates:
|
||||
result = ""
|
||||
else:
|
||||
raiseRecoverableError("cannot extract string from invalid AST node")
|
||||
template getStrImpl*(aArg: typed): string =
|
||||
## Body shared with `bnode`'s `BNode` spelling — see `canRaiseImpl`.
|
||||
block:
|
||||
let gs = aArg
|
||||
var res = ""
|
||||
case gs.kind
|
||||
of nkStrLit..nkTripleStrLit: res = gs.strVal
|
||||
of nkNilLit:
|
||||
# let's hope this fixes more problems than it creates:
|
||||
res = ""
|
||||
else:
|
||||
raiseRecoverableError("cannot extract string from invalid AST node")
|
||||
res
|
||||
|
||||
proc getStr*(a: PNode): string = getStrImpl(a)
|
||||
#doAssert false, "getStr"
|
||||
#internalError(a.info, "getStr")
|
||||
#result = ""
|
||||
@@ -1655,8 +1666,14 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
|
||||
let base = t.skipTypes({tyAlias, tyPtr, tyDistinct, tyGenericInst})
|
||||
result = base.sym != nil and {sfCompileToCpp, sfImportc} * base.sym.flags != {}
|
||||
|
||||
proc isInfixAs*(n: PNode): bool =
|
||||
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.id == ord(wAs)
|
||||
template isInfixAsImpl*(nArg: typed): bool =
|
||||
## Body shared with `bnode`'s `BNode` spelling — see `canRaiseImpl`.
|
||||
block:
|
||||
let ia = nArg
|
||||
ia.kind == nkInfix and ia.firstSon.kind == nkIdent and
|
||||
ia.firstSon.ident.id == ord(wAs)
|
||||
|
||||
proc isInfixAs*(n: PNode): bool = isInfixAsImpl(n)
|
||||
|
||||
proc skipColon*(n: PNode): PNode =
|
||||
result = n
|
||||
@@ -1851,8 +1868,13 @@ proc toHumanStr*(kind: TTypeKind): string =
|
||||
## strips leading `tk`
|
||||
result = toHumanStrImpl(kind, 2)
|
||||
|
||||
proc skipHiddenAddr*(n: PNode): PNode {.inline.} =
|
||||
(if n.kind == nkHiddenAddr: n[0] else: n)
|
||||
template skipHiddenAddrImpl*(nArg: typed): untyped =
|
||||
## Body shared with `bnode`'s `BNode` spelling — see `canRaiseImpl`.
|
||||
block:
|
||||
let sha = nArg
|
||||
(if sha.kind == nkHiddenAddr: sha.firstSon else: sha)
|
||||
|
||||
proc skipHiddenAddr*(n: PNode): PNode {.inline.} = skipHiddenAddrImpl(n)
|
||||
|
||||
proc isNewStyleConcept*(n: PNode): bool {.inline.} =
|
||||
assert n.kind == nkTypeClassTy
|
||||
|
||||
@@ -740,7 +740,7 @@ proc listSymbolNames*(symbols: openArray[PSym]): string =
|
||||
result.add ", "
|
||||
result.add sym.name.s
|
||||
|
||||
proc isDiscriminantField*(n: PNode): bool =
|
||||
if n.kind == nkCheckedFieldExpr: sfDiscriminant in n[0][1].sym.flags
|
||||
elif n.kind == nkDotExpr: sfDiscriminant in n[1].sym.flags
|
||||
proc isDiscriminantField*(n: AnyNode): bool =
|
||||
if n.kind == nkCheckedFieldExpr: sfDiscriminant in n.firstSon.secondSon.sym.flags
|
||||
elif n.kind == nkDotExpr: sfDiscriminant in n.secondSon.sym.flags
|
||||
else: false
|
||||
|
||||
@@ -699,6 +699,16 @@ when defined(newIcBackend):
|
||||
|
||||
proc getInt*(n: BNode): Int128 = getIntImpl(n)
|
||||
|
||||
proc skipHiddenAddr*(n: BNode): BNode {.inline.} = skipHiddenAddrImpl(n)
|
||||
|
||||
proc isInfixAs*(n: BNode): bool = isInfixAsImpl(n)
|
||||
|
||||
proc getStr*(n: BNode): string = getStrImpl(n)
|
||||
|
||||
proc skipPragmaExpr*(n: BNode): BNode {.inline.} =
|
||||
## The `BNode` spelling of `ast.skipPragmaExpr`.
|
||||
(if n.kind == nkPragmaExpr: n.firstSon else: n)
|
||||
|
||||
proc canRaiseConservative*(fn: BNode): bool = canRaiseConservativeImpl(fn)
|
||||
|
||||
proc canRaise*(fn: BNode): bool = canRaiseImpl(fn)
|
||||
|
||||
@@ -37,14 +37,12 @@ proc canRaiseDisp(p: BProc; n: AnyNode): bool =
|
||||
if n.kind == nkSym:
|
||||
logCanRaise(n.sym, result)
|
||||
|
||||
proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
|
||||
## STAYS on `PNode`, and the reason is a capability the seam does not have
|
||||
## rather than an accessor it is missing: the `warnObservableStores` message
|
||||
## interpolates `$le`, i.e. it RENDERS the node. Rendering is `renderer.nim`
|
||||
## reconstructing source text, which is a different job from reading a node's
|
||||
## kind/sym/type, and nothing needs it until a diagnostic does. The alias
|
||||
## analysis this calls (`isPartOf`) is already `AnyNode`, so only the message
|
||||
## is in the way.
|
||||
proc preventNrvo(p: BProc; dest, le: PNode; ri: AnyNode): bool =
|
||||
## `dest` and `le` stay `PNode`s: they are DESTINATIONS, which the whole call
|
||||
## family keeps as `PNode`s so they can be nil and so they can be handed to
|
||||
## the alias analysis, and it is also what keeps the `warnObservableStores`
|
||||
## message able to RENDER `le` — rendering being a capability the cursor seam
|
||||
## does not have at all. `ri`, the call being generated, is a cursor.
|
||||
proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool =
|
||||
result = false
|
||||
var n = le
|
||||
@@ -70,18 +68,20 @@ proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
|
||||
return true
|
||||
|
||||
result = false
|
||||
if le != nil:
|
||||
if not le.isNilNode:
|
||||
for r in sonsFrom(ri, 1):
|
||||
if isPartOf(le, r, {pfStructural}) != arNo: return true
|
||||
# `isPartOf` compares field symbols by identity and so has not moved to
|
||||
# the seam; `origin` hands it the same nodes it always compared.
|
||||
if isPartOf(le, origin(r), {pfStructural}) != arNo: return true
|
||||
# we use the weaker 'canRaise' here in order to prevent too many
|
||||
# annoying warnings, see #14514
|
||||
if canRaise(ri.firstSon) and
|
||||
locationEscapes(p, le, p.nestedTryStmts.len > 0):
|
||||
message(p.config, le.info, warnObservableStores, $le)
|
||||
# bug #19613 prevent dangerous aliasing too:
|
||||
if dest != nil and dest != le:
|
||||
if not dest.isNilNode and dest != le:
|
||||
for r in sonsFrom(ri, 1):
|
||||
if isPartOf(dest, r, {pfStructural}) != arNo: return true
|
||||
if isPartOf(dest, origin(r), {pfStructural}) != arNo: return true
|
||||
|
||||
proc hasNoInit(call: AnyNode): bool {.inline.} =
|
||||
result = call.firstSon.kind == nkSym and sfNoInit in call.firstSon.sym.flags
|
||||
@@ -115,7 +115,11 @@ proc cleanupTemp(p: BProc; returnType: PType, tmp: TLoc): bool =
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
# `le` — the assignment DESTINATION — stays a `PNode` throughout this family.
|
||||
# It is nilable (`genCall` passes nil, and a cursor has no standalone nil), and
|
||||
# it is what `preventNrvo` and `isPartOf` are handed, both of which are still
|
||||
# `PNode`-typed. `ri`, the expression being generated, is the part that moves.
|
||||
proc fixupCall(p: BProc, le: PNode, ri: AnyNode, d: var TLoc,
|
||||
result: var Builder, call: var CallBuilder) =
|
||||
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri.firstSon)
|
||||
genLineDir(p, ri)
|
||||
@@ -214,7 +218,7 @@ proc reifiedOpenArray(n: AnyNode): bool {.inline.} =
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareForMutation = false): (Rope, Rope) =
|
||||
proc genOpenArraySlice(p: BProc; q: AnyNode; formalType, destType: PType; prepareForMutation = false): (Rope, Rope) =
|
||||
var a = initLocExpr(p, q.secondSon)
|
||||
var b = initLocExpr(p, son(q, 2))
|
||||
var c = initLocExpr(p, son(q, 3))
|
||||
@@ -277,7 +281,7 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
|
||||
result = ("", "")
|
||||
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
|
||||
|
||||
proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Builder) =
|
||||
proc openArrayLoc(p: BProc, formalType: PType, n: AnyNode; result: var Builder) =
|
||||
var q = skipConv(n)
|
||||
var skipped = false
|
||||
while q.kind == nkStmtListExpr and q.hasSons:
|
||||
@@ -387,13 +391,13 @@ proc expressionsNeedsTmp(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 Builder; needsTmp: bool) {.inline.} =
|
||||
proc genArgStringToCString(p: BProc, n: AnyNode; result: var Builder; needsTmp: bool) {.inline.} =
|
||||
var a = initLocExpr(p, n.firstSon)
|
||||
let tmp = withTmpIfNeeded(p, a, needsTmp)
|
||||
let ra = if p.config.usesSso(): byRefLoc(p, tmp) else: tmp.rdLoc
|
||||
result.addCall(cgsymValue(p.module, "nimToCStringConv"), ra)
|
||||
|
||||
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Builder; needsTmp = false) =
|
||||
proc genArg(p: BProc, n: AnyNode, param: PSym; call: AnyNode; result: var Builder; needsTmp = false) =
|
||||
var a: TLoc
|
||||
if n.kind == nkStringToCString:
|
||||
genArgStringToCString(p, n, result, needsTmp)
|
||||
@@ -413,10 +417,16 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Builder; n
|
||||
# will be a reference in C++ and we cannot create a temporary reference
|
||||
# variable. Thus, we create a temporary pointer variable instead.
|
||||
let needsIndirect = mapType(p.config, n.firstSon.typ, mapTypeChooser(n.firstSon) == skParam) != ctArray
|
||||
# A REWRITE, and one that has to be followed. The node's type is replaced in
|
||||
# place, and a cursor would keep reading the type slot as it was ENCODED —
|
||||
# the buffer does not see the mutation. So from here this site works on the
|
||||
# origin, which is the node being mutated and therefore the one that has the
|
||||
# new type.
|
||||
let nn = origin(n)
|
||||
if needsIndirect:
|
||||
n.typ = copyType(n.typ, p.module.idgen, n.typ.owner)
|
||||
n.typ.incl tfVarIsPtr
|
||||
a = initLocExprSingleUse(p, n)
|
||||
nn.typ = copyType(nn.typ, p.module.idgen, nn.typ.owner)
|
||||
nn.typ.incl tfVarIsPtr
|
||||
a = initLocExprSingleUse(p, nn)
|
||||
a = withTmpIfNeeded(p, a, needsTmp)
|
||||
if needsIndirect: a.flags.incl lfIndirect
|
||||
# if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
|
||||
@@ -438,7 +448,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Builder; n
|
||||
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
|
||||
#assert result != nil
|
||||
|
||||
proc genArgNoParam(p: BProc, n: PNode; result: var Builder; needsTmp = false) =
|
||||
proc genArgNoParam(p: BProc, n: AnyNode; result: var Builder; needsTmp = false) =
|
||||
var a: TLoc
|
||||
if n.kind == nkStringToCString:
|
||||
genArgStringToCString(p, n, result, needsTmp)
|
||||
@@ -448,7 +458,7 @@ proc genArgNoParam(p: BProc, n: PNode; result: var Builder; needsTmp = false) =
|
||||
|
||||
import aliasanalysis
|
||||
|
||||
proc potentialAlias(n: PNode, potentialWrites: seq[PNode]): bool =
|
||||
proc potentialAlias(n: AnyNode, potentialWrites: seq[PNode]): bool =
|
||||
result = false
|
||||
for p in potentialWrites:
|
||||
if p.aliases(n) != no or n.aliases(p) != no:
|
||||
@@ -467,23 +477,30 @@ proc skipTrivialIndirections[T: AnyNode](n: T): T =
|
||||
result = result.secondSon
|
||||
else: break
|
||||
|
||||
proc getPotentialReads(n: PNode; result: var seq[PNode]) =
|
||||
proc getPotentialReads(n: AnyNode; result: var seq[PNode]) =
|
||||
case n.kind:
|
||||
of nkLiterals, nkIdent, nkFormalParams: discard
|
||||
of nkSym: result.add n
|
||||
else:
|
||||
for s in n:
|
||||
for s in sons(n):
|
||||
getPotentialReads(s, result)
|
||||
|
||||
proc genParams(p: BProc, ri: PNode, typ: PType; result: var Builder, argBuilder: var CallBuilder) =
|
||||
proc genParams(p: BProc, ri: AnyNode, typ: PType; result: var Builder, argBuilder: var CallBuilder) =
|
||||
# We must generate temporaries in cases like #14396
|
||||
# to keep the strict Left-To-Right evaluation
|
||||
# The arguments are walked BACKWARDS below, which a `Cursor` cannot do and
|
||||
# which costs a re-walk per step even on a `PNode`. Materialize them in one
|
||||
# forward pass and index that; `needTmp` already allocates per call, so this
|
||||
# is the same order of work.
|
||||
#
|
||||
# The arguments are materialized as `PNode`s, not cursors, because the alias
|
||||
# analysis below (`potentialAlias`, `getPotentialReads`) carries a
|
||||
# `seq[PNode]` beside the node and has not moved to the seam — see the
|
||||
# mixed-representation blocker in `bnode`'s module doc. `origin` gives the
|
||||
# same objects the tree-driven build used, so this is the argument list it
|
||||
# always was; when that analysis moves, this becomes `seq[AnyNode]`.
|
||||
var args: seq[PNode] = @[]
|
||||
for it in sonsFrom(ri, 1): args.add it
|
||||
for it in sonsFrom(ri, 1): args.add origin(it)
|
||||
var needTmp = newSeq[bool](args.len)
|
||||
var potentialWrites: seq[PNode] = @[]
|
||||
for i in countdown(args.high, 0):
|
||||
@@ -525,7 +542,7 @@ proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
|
||||
(sym.typ.callConv == ccInline or sym.owner.id == module.id):
|
||||
res = res & "_actual".rope
|
||||
|
||||
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
proc genPrefixCall(p: BProc, le: PNode, ri: AnyNode, d: var TLoc) =
|
||||
# this is a hotspot in the compiler
|
||||
var op = initLocExpr(p, ri.firstSon)
|
||||
# getUniqueType() is too expensive here:
|
||||
@@ -541,7 +558,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
genParams(p, ri, typ, res, call)
|
||||
fixupCall(p, le, ri, d, res, call)
|
||||
|
||||
proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
proc genClosureCall(p: BProc, le: PNode, ri: AnyNode, d: var TLoc) =
|
||||
|
||||
template callProc(rp, params, pTyp: Snippet): Snippet =
|
||||
let e = dotField(rp, "ClE_0")
|
||||
@@ -576,6 +593,12 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var argBuilder = default(CallBuilder) # not initCallBuilder, we just want the params
|
||||
genParams(p, ri, typ, params, argBuilder)
|
||||
|
||||
# `rawProc` is bound BEFORE the `{.dirty.}` template that uses it. Inside a
|
||||
# generic proc a dirty template's identifiers resolve at instantiation, and a
|
||||
# local declared after the template loses to the module-level `rawProc` proc
|
||||
# — which type-checks as a completely different thing.
|
||||
let rawProc = getClosureType(p.module, typ, clHalf)
|
||||
|
||||
template genCallPattern {.dirty.} =
|
||||
let rp = rdLoc(op)
|
||||
let pars = extract(params)
|
||||
@@ -584,8 +607,6 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
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.firstSon)
|
||||
if typ.returnType != nil:
|
||||
if isInvalidReturnType(p.config, typ):
|
||||
@@ -637,7 +658,7 @@ 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 Builder;
|
||||
proc genOtherArg(p: BProc; ri: AnyNode; 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
|
||||
@@ -714,7 +735,7 @@ proc skipAddrDeref[T: AnyNode](node: T): T =
|
||||
else:
|
||||
result = node
|
||||
|
||||
proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder) =
|
||||
proc genThisArg(p: BProc; ri: AnyNode; 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.
|
||||
@@ -749,7 +770,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder) =
|
||||
genArgNoParam(p, ri, result) #, son(typ.n, i).sym)
|
||||
result.add(".")
|
||||
|
||||
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Builder) =
|
||||
proc genPatternCall(p: BProc; ri: AnyNode; pat: string; typ: PType; result: var Builder) =
|
||||
var i = 0
|
||||
var j = 1
|
||||
while i < pat.len:
|
||||
@@ -803,7 +824,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Bu
|
||||
if i - 1 >= start:
|
||||
result.add(substr(pat, start, i - 1))
|
||||
|
||||
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
proc genInfixCall(p: BProc, le: PNode, ri: AnyNode, d: var TLoc) =
|
||||
var op = initLocExpr(p, ri.firstSon)
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri.firstSon.typ, abstractInst)
|
||||
@@ -844,7 +865,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
genOtherArg(p, ri, i, typ, res, call)
|
||||
fixupCall(p, le, ri, d, res, call)
|
||||
|
||||
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
proc genNamedParamCall(p: BProc, ri: AnyNode, d: var TLoc) =
|
||||
# generates a crappy ObjC call
|
||||
var op = initLocExpr(p, ri.firstSon)
|
||||
var pl = newBuilder("[")
|
||||
@@ -935,7 +956,7 @@ proc isInactiveDestructorCall(p: BProc, e: AnyNode): bool =
|
||||
result = e.safeLen == 2 and e.firstSon.kind == nkSym and
|
||||
e.firstSon.sym.name.s == "=destroy" and notYetAlive(e.secondSon.skipAddr)
|
||||
|
||||
proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
proc genAsgnCall(p: BProc, le: PNode, ri: AnyNode, d: var TLoc) =
|
||||
if p.withinBlockLeaveActions > 0 and isInactiveDestructorCall(p, ri):
|
||||
return
|
||||
when defined(icDbgHash):
|
||||
@@ -957,4 +978,4 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
else:
|
||||
genPrefixCall(p, le, ri, d)
|
||||
|
||||
proc genCall(p: BProc, e: PNode, d: var TLoc) = genAsgnCall(p, nil, e, d)
|
||||
proc genCall(p: BProc, e: AnyNode, d: var TLoc) = genAsgnCall(p, nil, e, d)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -53,11 +53,11 @@ proc genStringLiteralDataOnlyV1(m: BModule, s: string; result: var Rope) =
|
||||
res.add(makeCString(s))
|
||||
m.s[cfsStrData].add(extract(res))
|
||||
|
||||
proc genStringLiteralV1(m: BModule; n: PNode; result: var Builder) =
|
||||
proc genStringLiteralV1(m: BModule; n: AnyNode; result: var Builder) =
|
||||
if s.isNil:
|
||||
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), NimNil))
|
||||
else:
|
||||
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
|
||||
let id = nodeTableTestOrSet(m.dataCache, origin(n), m.labels)
|
||||
var name: string = ""
|
||||
if id == m.labels:
|
||||
# string literal not found in the cache:
|
||||
@@ -85,8 +85,8 @@ proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bo
|
||||
res.add(makeCString(s))
|
||||
m.s[cfsStrData].add(extract(res))
|
||||
|
||||
proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Builder) =
|
||||
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
|
||||
proc genStringLiteralV2(m: BModule; n: AnyNode; isConst: bool; result: var Builder) =
|
||||
let id = nodeTableTestOrSet(m.dataCache, origin(n), m.labels)
|
||||
var litName: string
|
||||
if id == m.labels:
|
||||
cgsym(m, "NimStrPayload")
|
||||
@@ -111,8 +111,8 @@ proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Builder
|
||||
res.add(cCast(ptrType("NimStrPayload"), cAddr(litName)))
|
||||
m.s[cfsStrData].add(extract(res))
|
||||
|
||||
proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Builder) =
|
||||
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
|
||||
proc genStringLiteralV2Const(m: BModule; n: AnyNode; isConst: bool; result: var Builder) =
|
||||
let id = nodeTableTestOrSet(m.dataCache, origin(n), m.labels)
|
||||
var pureLit: Rope
|
||||
if id == m.labels:
|
||||
pureLit = getTempName(m)
|
||||
@@ -164,7 +164,7 @@ proc ssoMoreLit(m: BModule; s: string): string =
|
||||
val = val or (ch shl (uint(ptrSize - 1 - i) * 8))
|
||||
result = cCast(ptrType("LongString"), "(uintptr_t)" & $val)
|
||||
|
||||
proc genStringLiteralV3Const(m: BModule; n: PNode; isConst: bool; result: var Builder) =
|
||||
proc genStringLiteralV3Const(m: BModule; n: AnyNode; isConst: bool; result: var Builder) =
|
||||
# Inline SmallString struct initializer for use inside const aggregate types.
|
||||
# Layout: {bytes: NimUint, more: ptr LongString}
|
||||
# bytes = slen (low byte) | char[0]<<8 | char[1]<<16 | ... | char[6]<<56
|
||||
@@ -220,7 +220,7 @@ proc genStringLiteralV3Const(m: BModule; n: PNode; isConst: bool; result: var Bu
|
||||
|
||||
# ------ Version 3: SmallString (SSO) strings --------------------------------
|
||||
|
||||
proc genStringLiteralV3(m: BModule; n: PNode; isConst: bool; result: var Builder) =
|
||||
proc genStringLiteralV3(m: BModule; n: AnyNode; isConst: bool; result: var Builder) =
|
||||
# SmallString literal. Always generate a fresh SmallString variable (like v2
|
||||
# always generates a fresh outer NimStringV2). For long strings, cache the
|
||||
# LongString payload to avoid duplicates within a module.
|
||||
@@ -259,7 +259,7 @@ proc genStringLiteralV3(m: BModule; n: PNode; isConst: bool; result: var Builder
|
||||
else:
|
||||
# Long: cache the LongString block to emit it only once per module per string.
|
||||
# Always generate a fresh SmallString pointing at the (possibly cached) block.
|
||||
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
|
||||
let id = nodeTableTestOrSet(m.dataCache, origin(n), m.labels)
|
||||
var dataName: string
|
||||
if id == m.labels:
|
||||
dataName = getTempName(m)
|
||||
@@ -301,7 +301,7 @@ proc genStringLiteralV3(m: BModule; n: PNode; isConst: bool; result: var Builder
|
||||
proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Builder) =
|
||||
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), NimNil))
|
||||
|
||||
proc genStringLiteral(m: BModule; n: PNode; result: var Builder) =
|
||||
proc genStringLiteral(m: BModule; n: AnyNode; result: var Builder) =
|
||||
case detectStrVersion(m)
|
||||
of 0, 1: genStringLiteralV1(m, n, result)
|
||||
of 2: genStringLiteralV2(m, n, isConst = true, result)
|
||||
|
||||
@@ -94,13 +94,13 @@ template endBlockWith(p: BProc, body: typed) =
|
||||
body
|
||||
endBlockOutside(p, label)
|
||||
|
||||
proc genVarTuple(p: BProc, n: PNode) =
|
||||
proc genVarTuple(p: BProc, n: AnyNode) =
|
||||
if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
|
||||
|
||||
# if we have a something that's been captured, use the lowering instead:
|
||||
for it in sonsButLast(n, 2):
|
||||
if it.kind != nkSym:
|
||||
genStmts(p, lowerTupleUnpacking(p.module.g.graph, n, p.module.idgen, p.prc))
|
||||
genStmts(p, lowerTupleUnpacking(p.module.g.graph, origin(n), p.module.idgen, p.prc))
|
||||
return
|
||||
|
||||
# check only the first son
|
||||
@@ -172,7 +172,9 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
cCast(ptrType(CPointer), cAddr(curr.loc.snippet))))
|
||||
|
||||
|
||||
proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
|
||||
proc loadInto(p: BProc, le: PNode, ri: AnyNode, a: var TLoc) {.inline.} =
|
||||
## `le` is the DESTINATION and stays a `PNode` — it only ever reaches
|
||||
## `genAsgnCall`, which keeps it a `PNode` for the alias analysis.
|
||||
if ri.kind in nkCallKinds and (ri.firstSon.kind != nkSym or
|
||||
ri.firstSon.sym.magic == mNone):
|
||||
genAsgnCall(p, le, ri, a)
|
||||
@@ -199,13 +201,13 @@ proc endSimpleBlock(p: BProc, scope: var ScopeBuilder) {.inline.} =
|
||||
endBlockWith(p):
|
||||
finishScope(p.s(cpsStmts), scope)
|
||||
|
||||
proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
|
||||
proc genSimpleBlock(p: BProc, stmts: AnyNode) {.inline.} =
|
||||
var scope: ScopeBuilder
|
||||
startSimpleBlock(p, scope)
|
||||
genStmts(p, stmts)
|
||||
endSimpleBlock(p, scope)
|
||||
|
||||
proc exprBlock(p: BProc, n: PNode, d: var TLoc) =
|
||||
proc exprBlock(p: BProc, n: AnyNode, d: var TLoc) =
|
||||
var scope: ScopeBuilder
|
||||
startSimpleBlock(p, scope)
|
||||
expr(p, n, d)
|
||||
@@ -216,7 +218,7 @@ template preserveBreakIdx(body: untyped): untyped =
|
||||
body
|
||||
p.breakIdx = oldBreakIdx
|
||||
|
||||
proc genState(p: BProc, n: PNode) =
|
||||
proc genState(p: BProc, n: AnyNode) =
|
||||
internalAssert p.config, n.len == 1
|
||||
let n0 = n.firstSon
|
||||
if n0.kind == nkIntLit:
|
||||
@@ -261,7 +263,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int, isReturnStmt
|
||||
for i in countdown(howManyExcepts-1, 0):
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popCurrentException"))
|
||||
|
||||
proc genGotoState(p: BProc, n: PNode) =
|
||||
proc genGotoState(p: BProc, n: AnyNode) =
|
||||
# we resist the temptation to translate it into duff's device as it later
|
||||
# will be translated into computed gotos anyway for GCC at least:
|
||||
# switch (x.state) {
|
||||
@@ -285,7 +287,7 @@ proc genGotoState(p: BProc, n: PNode) =
|
||||
p.s(cpsStmts).addSingleSwitchCase(cIntValue(i)):
|
||||
p.s(cpsStmts).addGoto(prefix & $i)
|
||||
|
||||
proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
|
||||
proc genBreakState(p: BProc, n: AnyNode, d: var TLoc) =
|
||||
var a: TLoc
|
||||
d = initLoc(locExpr, n, OnUnknown)
|
||||
|
||||
@@ -307,23 +309,23 @@ proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
|
||||
cIntValue(1)),
|
||||
cIntValue(0))
|
||||
|
||||
proc genGotoVar(p: BProc; value: PNode) =
|
||||
proc genGotoVar(p: BProc; value: AnyNode) =
|
||||
if value.kind notin {nkCharLit..nkUInt64Lit}:
|
||||
localError(p.config, value.info, "'goto' target must be a literal value")
|
||||
else:
|
||||
p.s(cpsStmts).addGoto("NIMSTATE_" & $value.intVal)
|
||||
|
||||
proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; result: var Builder)
|
||||
proc genBracedInit(p: BProc, n: AnyNode; isConst: bool; optionalType: PType; result: var Builder)
|
||||
|
||||
proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Builder) =
|
||||
proc potentialValueInit(p: BProc; v: PSym; value: AnyNode; result: var Builder) =
|
||||
if lfDynamicLib in v.loc.flags or sfThread in v.flags or p.hcrOn:
|
||||
discard "nothing to do"
|
||||
elif sfGlobal in v.flags and value != nil and isDeepConstExpr(value, p.module.compileToCpp) and
|
||||
elif sfGlobal in v.flags and not value.isNilNode and isDeepConstExpr(value, p.module.compileToCpp) and
|
||||
p.withinLoop == 0 and not containsGarbageCollectedRef(v.typ):
|
||||
#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): Snippet =
|
||||
proc genCppParamsForCtor(p: BProc; call: AnyNode; didGenTemp: var bool): Snippet =
|
||||
var res = newBuilder("")
|
||||
var argBuilder = default(CallBuilder) # not init, only building params
|
||||
let typ = skipTypes(call.firstSon.typ, abstractInst)
|
||||
@@ -348,7 +350,11 @@ proc genCppParamsForCtor(p: BProc; call: PNode; didGenTemp: var bool): Snippet =
|
||||
genOtherArg(p, call, i, typ, res, argBuilder)
|
||||
result = extract(res)
|
||||
|
||||
proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
proc genSingleVar[V: AnyNode; W: AnyNode](p: BProc, v: PSym; vn: V; value: W) =
|
||||
## `vn` and `value` are SEPARATE type parameters, not one shared: the
|
||||
## definition site is a body node while the value can come from the symbol's
|
||||
## own AST (`astdef`), so the two are not necessarily the same
|
||||
## representation.
|
||||
if sfGoto in v.flags:
|
||||
# translate 'var state {.goto.} = X' into 'goto LX':
|
||||
genGotoVar(p, value)
|
||||
@@ -462,13 +468,13 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
genLineDir(targetProc, vn)
|
||||
if not isCppCtorCall:
|
||||
backendEnsureMutable v
|
||||
loadInto(targetProc, vn, value, v.locImpl)
|
||||
loadInto(targetProc, origin(vn), value, v.locImpl)
|
||||
if forHcr:
|
||||
endBlockWith(targetProc):
|
||||
finishBranch(p.s(cpsStmts), hcrInit)
|
||||
finishIfStmt(p.s(cpsStmts), hcrInit)
|
||||
|
||||
proc genSingleVar(p: BProc, a: PNode) =
|
||||
proc genSingleVar(p: BProc, a: AnyNode) =
|
||||
let v = a.firstSon.sym
|
||||
if sfCompileTime in v.flags:
|
||||
# fix issue #12640
|
||||
@@ -479,17 +485,17 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||
return
|
||||
genSingleVar(p, v, a.firstSon, son(a, 2))
|
||||
|
||||
proc genClosureVar(p: BProc, a: PNode) =
|
||||
proc genClosureVar(p: BProc, a: AnyNode) =
|
||||
var immediateAsgn = son(a, 2).kind != nkEmpty
|
||||
var v: TLoc = initLocExpr(p, a.firstSon)
|
||||
genLineDir(p, a)
|
||||
if immediateAsgn:
|
||||
loadInto(p, a.firstSon, son(a, 2), v)
|
||||
loadInto(p, origin(a.firstSon), son(a, 2), v)
|
||||
elif sfNoInit notin a.firstSon.secondSon.sym.flags:
|
||||
constructLoc(p, v)
|
||||
|
||||
proc genVarStmt(p: BProc, n: PNode) =
|
||||
for it in n:
|
||||
proc genVarStmt(p: BProc, n: AnyNode) =
|
||||
for it in sons(n):
|
||||
case it.kind
|
||||
of nkCommentStmt: discard
|
||||
of nkIdentDefs:
|
||||
@@ -503,7 +509,7 @@ proc genVarStmt(p: BProc, n: PNode) =
|
||||
else:
|
||||
genVarTuple(p, it)
|
||||
|
||||
proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
proc genIf(p: BProc, n: AnyNode, d: var TLoc) =
|
||||
#
|
||||
# { if (!expr1) goto L1;
|
||||
# thenPart }
|
||||
@@ -552,7 +558,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
else: internalError(p.config, n.info, "genIf()")
|
||||
if n.len > 1: fixLabel(p, lend)
|
||||
|
||||
proc genReturnStmt(p: BProc, t: PNode) =
|
||||
proc genReturnStmt(p: BProc, t: AnyNode) =
|
||||
if nfPreventCg in t.flags: return
|
||||
p.flags.incl beforeRetNeeded
|
||||
genLineDir(p, t)
|
||||
@@ -572,7 +578,7 @@ proc genReturnStmt(p: BProc, t: PNode) =
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popCurrentException"))
|
||||
p.s(cpsStmts).addGoto("BeforeRet_")
|
||||
|
||||
proc genGotoForCase(p: BProc; caseStmt: PNode) =
|
||||
proc genGotoForCase(p: BProc; caseStmt: AnyNode) =
|
||||
for child in sonsFrom(caseStmt, 1):
|
||||
var scope: ScopeBuilder
|
||||
startSimpleBlock(p, scope)
|
||||
@@ -589,18 +595,20 @@ proc genGotoForCase(p: BProc; caseStmt: PNode) =
|
||||
|
||||
iterator fieldValuePairs(n: PNode): tuple[memberSym, valueSym: PNode] =
|
||||
assert(n.kind in {nkLetSection, nkVarSection})
|
||||
for identDefs in n:
|
||||
for identDefs in sons(n):
|
||||
if identDefs.kind == nkIdentDefs:
|
||||
let valueSym = identDefs.lastSon
|
||||
for memberSym in sonsButLast(identDefs, 2):
|
||||
yield((memberSym: memberSym, valueSym: valueSym))
|
||||
|
||||
proc genComputedGoto(p: BProc; n: PNode) =
|
||||
proc genComputedGoto(p: BProc; n: AnyNode) =
|
||||
# first pass: Generate array of computed labels:
|
||||
|
||||
# flatten the loop body because otherwise let and var sections
|
||||
# wrapped inside stmt lists by inject destructors won't be recognised
|
||||
let n = n.flattenStmts()
|
||||
# REBUILDS the statement list, so from here this proc works on
|
||||
# a fresh `PNode` tree — there is nothing in the buffer corresponding to it.
|
||||
let n = origin(n).flattenStmts()
|
||||
var casePos = -1
|
||||
var arraySize: int = 0
|
||||
for i, it in isons(n):
|
||||
@@ -688,7 +696,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
genStmts(p, it)
|
||||
|
||||
|
||||
proc genWhileStmt(p: BProc, t: PNode) =
|
||||
proc genWhileStmt(p: BProc, t: AnyNode) =
|
||||
# we don't generate labels here as for example GCC would produce
|
||||
# significantly worse code
|
||||
var
|
||||
@@ -727,7 +735,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
|
||||
|
||||
dec(p.withinLoop)
|
||||
|
||||
proc genBlock(p: BProc, n: PNode, d: var TLoc) =
|
||||
proc genBlock(p: BProc, n: AnyNode, d: var TLoc) =
|
||||
if not isEmptyType(n.typ):
|
||||
# bug #4505: allocate the temp in the outer scope
|
||||
# so that it can escape the generated {}:
|
||||
@@ -748,7 +756,7 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
|
||||
expr(p, n.secondSon, d)
|
||||
endSimpleBlock(p, scope)
|
||||
|
||||
proc genParForStmt(p: BProc, t: PNode) =
|
||||
proc genParForStmt(p: BProc, t: AnyNode) =
|
||||
assert(t.len == 3)
|
||||
inc(p.withinLoop)
|
||||
genLineDir(p, t)
|
||||
@@ -765,13 +773,13 @@ proc genParForStmt(p: BProc, t: PNode) =
|
||||
|
||||
var stepNode: PNode = nil
|
||||
# $n at the beginning because of #9710
|
||||
if call.len == 4: # procName(a, b, annotation)
|
||||
if call.safeLen == 4: # procName(a, b, annotation)
|
||||
if call.firstSon.sym.name.s == "||": # `||`(a, b, annotation)
|
||||
p.s(cpsStmts).addCPragma("omp " & son(call, 3).getStr)
|
||||
else:
|
||||
p.s(cpsStmts).addCPragma(son(call, 3).getStr)
|
||||
else: # `||`(a, b, step, annotation)
|
||||
stepNode = son(call, 3)
|
||||
stepNode = origin(son(call, 3))
|
||||
p.s(cpsStmts).addCPragma("omp " & son(call, 4).getStr)
|
||||
|
||||
p.breakIdx = startBlockWith(p):
|
||||
@@ -787,7 +795,7 @@ proc genParForStmt(p: BProc, t: PNode) =
|
||||
|
||||
dec(p.withinLoop)
|
||||
|
||||
proc genBreakStmt(p: BProc, t: PNode) =
|
||||
proc genBreakStmt(p: BProc, t: AnyNode) =
|
||||
var idx = p.breakIdx
|
||||
if t.firstSon.kind != nkEmpty:
|
||||
# named break?
|
||||
@@ -868,7 +876,7 @@ proc raiseInstr(p: BProc; result: var Builder) =
|
||||
result.addGoto("LA" & $p.nestedTryStmts[L-1].label & "_")
|
||||
# + ord(p.nestedTryStmts[L-1].inExcept)])
|
||||
|
||||
proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
proc genRaiseStmt(p: BProc, t: AnyNode) =
|
||||
if t.firstSon.kind != nkEmpty:
|
||||
var a: TLoc = initLocExprSingleUse(p, t.firstSon)
|
||||
finallyActions(p)
|
||||
@@ -905,7 +913,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "reraiseException"))
|
||||
raiseInstr(p, p.s(cpsStmts))
|
||||
|
||||
template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
template genCaseGenericBranch(p: BProc, b: AnyNode, e: TLoc, labl: TLabel,
|
||||
rangeFormat, eqFormat: untyped) =
|
||||
var x, y: TLoc
|
||||
for it in sonsButLast(b):
|
||||
@@ -923,7 +931,7 @@ template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
let rb {.inject.} = rdCharLoc(x)
|
||||
eqFormat
|
||||
|
||||
proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
|
||||
proc genCaseSecondPass(p: BProc, t: AnyNode, d: var TLoc,
|
||||
labId, until: int): TLabel =
|
||||
var lend = getLabel(p)
|
||||
for i, branch in isons(t, 1):
|
||||
@@ -938,7 +946,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
|
||||
exprBlock(p, branch.firstSon, d)
|
||||
result = lend
|
||||
|
||||
template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
|
||||
template genIfForCaseUntil(p: BProc, t: AnyNode, d: var TLoc,
|
||||
until: int, a: TLoc,
|
||||
rangeFormat, eqFormat: untyped): TLabel =
|
||||
# generate a C-if statement for a Nim case statement
|
||||
@@ -962,13 +970,13 @@ template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
|
||||
res = genCaseSecondPass(p, t, d, labId, until)
|
||||
res
|
||||
|
||||
template genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
|
||||
template genCaseGeneric(p: BProc, t: AnyNode, d: var TLoc,
|
||||
rangeFormat, eqFormat: untyped) =
|
||||
var a: TLoc = initLocExpr(p, t.firstSon)
|
||||
var lend = genIfForCaseUntil(p, t, d, t.len-1, a, rangeFormat, eqFormat)
|
||||
var lend = genIfForCaseUntil(p, t, d, t.safeLen-1, a, rangeFormat, eqFormat)
|
||||
fixLabel(p, lend)
|
||||
|
||||
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
proc genCaseStringBranch(p: BProc, b: AnyNode, e: TLoc, labl: TLabel,
|
||||
stringKind: TTypeKind,
|
||||
branches: var openArray[Builder]) =
|
||||
var x: TLoc
|
||||
@@ -990,7 +998,7 @@ proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
do:
|
||||
branches[j].addGoto(labl)
|
||||
|
||||
proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
|
||||
proc genStringCase(p: BProc, t: AnyNode, stringKind: TTypeKind, d: var TLoc) =
|
||||
# count how many constant strings there are in the case:
|
||||
var strings = 0
|
||||
for it in sonsFrom(t, 1):
|
||||
@@ -1057,7 +1065,7 @@ proc ifSwitchSplitPoint(p: BProc, n: AnyNode): int =
|
||||
if branch.kind == nkOfBranch and branchHasTooBigRange(branch):
|
||||
result = i
|
||||
|
||||
proc genCaseRange(p: BProc, branch: PNode, info: var SwitchCaseBuilder) =
|
||||
proc genCaseRange(p: BProc, branch: AnyNode, info: var SwitchCaseBuilder) =
|
||||
for it in sonsButLast(branch):
|
||||
if it.kind == nkRange:
|
||||
if hasSwitchRange in CC[p.config.cCompiler].props:
|
||||
@@ -1067,7 +1075,9 @@ proc genCaseRange(p: BProc, branch: PNode, info: var SwitchCaseBuilder) =
|
||||
genLiteral(p, it.secondSon, litB)
|
||||
p.s(cpsStmts).addCaseRange(info, extract(litA), extract(litB))
|
||||
else:
|
||||
var v = copyNode(it.firstSon)
|
||||
# A working COPY is mutated in the loop below, so it is a `PNode`
|
||||
# built from the origin — there is nothing to mutate on a cursor.
|
||||
var v = copyNode(origin(it.firstSon))
|
||||
while v.intVal <= it.secondSon.intVal:
|
||||
var litA = newBuilder("")
|
||||
genLiteral(p, v, litA)
|
||||
@@ -1078,7 +1088,7 @@ proc genCaseRange(p: BProc, branch: PNode, info: var SwitchCaseBuilder) =
|
||||
genLiteral(p, it, litA)
|
||||
p.s(cpsStmts).addCase(info, extract(litA))
|
||||
|
||||
proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
|
||||
proc genOrdinalCase(p: BProc, n: AnyNode, d: var TLoc) =
|
||||
# analyse 'case' statement:
|
||||
var splitPoint = ifSwitchSplitPoint(p, n)
|
||||
|
||||
@@ -1124,7 +1134,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
|
||||
p.s(cpsStmts).addCallStmt("__assume", cIntValue(0))
|
||||
if lend != "": fixLabel(p, lend)
|
||||
|
||||
proc genCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
proc genCase(p: BProc, t: AnyNode, d: var TLoc) =
|
||||
genLineDir(p, t)
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
d = getTemp(p, t.typ)
|
||||
@@ -1160,7 +1170,7 @@ proc genRestoreFrameAfterException(p: BProc) =
|
||||
p.procSec(cpsInit).addCall(cgsymValue(p.module, "getFrame"))
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "setFrame"), "_nimCurFrame")
|
||||
|
||||
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
proc genTryCpp(p: BProc, t: AnyNode, d: var TLoc) =
|
||||
#[ code to generate:
|
||||
|
||||
std::exception_ptr error;
|
||||
@@ -1196,7 +1206,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
#init on locals, fixes #23306
|
||||
lineCg(p, cpsLocals, "std::exception_ptr T$1_;$n", [etmp])
|
||||
|
||||
let fin = if t.lastSon.kind == nkFinally: t.lastSon else: nil
|
||||
let fin = if t.lastSon.kind == nkFinally: origin(t.lastSon) else: nil
|
||||
p.nestedTryStmts.add((fin, false, t.kind == nkHiddenTryStmt, 0.Natural))
|
||||
|
||||
if t.kind == nkHiddenTryStmt:
|
||||
@@ -1251,7 +1261,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
var typeNode = label
|
||||
if label.isInfixAs():
|
||||
typeNode = label.secondSon
|
||||
exvar = son(label, 2) # ex1 in `except ExceptType as ex1:`
|
||||
exvar = origin(son(label, 2)) # ex1 in `except ExceptType as ex1:`
|
||||
assert(typeNode.kind == nkType)
|
||||
if isImportedException(typeNode.typ, p.config):
|
||||
hasImportedCppExceptions = true
|
||||
@@ -1292,7 +1302,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
linefmt(p, cpsStmts, "}$n", [])
|
||||
|
||||
# Second pass: handle C++ based exceptions:
|
||||
template genExceptBranchBody(body: PNode) {.dirty.} =
|
||||
template genExceptBranchBody(body: AnyNode) {.dirty.} =
|
||||
genRestoreFrameAfterException(p)
|
||||
#linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp])
|
||||
expr(p, body, d)
|
||||
@@ -1320,7 +1330,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
if label.isInfixAs():
|
||||
typeNode = label.secondSon
|
||||
if isImportedException(typeNode.typ, p.config):
|
||||
let exvar = son(label, 2) # ex1 in `except ExceptType as ex1:`
|
||||
let exvar = origin(son(label, 2)) # ex1 in `except ExceptType as ex1:`
|
||||
fillLocalName(p, exvar.sym)
|
||||
backendEnsureMutable exvar.sym
|
||||
fillLoc(exvar.sym.locImpl, locTemp, exvar, OnStack)
|
||||
@@ -1372,8 +1382,8 @@ proc bodyCanRaise(p: BProc; n: AnyNode): bool =
|
||||
for it in sons(n):
|
||||
if bodyCanRaise(p, it): return true
|
||||
|
||||
proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
let fin = if t.lastSon.kind == nkFinally: t.lastSon else: nil
|
||||
proc genTryGoto(p: BProc; t: AnyNode; d: var TLoc) =
|
||||
let fin = if t.lastSon.kind == nkFinally: origin(t.lastSon) else: nil
|
||||
inc p.labels
|
||||
let lab = p.labels
|
||||
let hasExcept = t.secondSon.kind == nkExceptBranch
|
||||
@@ -1506,7 +1516,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
raiseExit(p)
|
||||
if hasExcept: inc p.withinTryWithExcept
|
||||
|
||||
proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
proc genTrySetjmp(p: BProc, t: AnyNode, d: var TLoc) =
|
||||
# code to generate:
|
||||
#
|
||||
# XXX: There should be a standard dispatch algorithm
|
||||
@@ -1585,7 +1595,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
nonQuirkyIf = initIfStmt(p.s(cpsStmts))
|
||||
initElifBranch(p.s(cpsStmts), nonQuirkyIf, removeSinglePar(
|
||||
cOp(Equal, dotField(safePoint, "status"), cIntValue(0))))
|
||||
let fin = if t.lastSon.kind == nkFinally: t.lastSon else: nil
|
||||
let fin = if t.lastSon.kind == nkFinally: origin(t.lastSon) else: nil
|
||||
p.nestedTryStmts.add((fin, quirkyExceptions, t.kind == nkHiddenTryStmt, 0.Natural))
|
||||
expr(p, t.firstSon, d)
|
||||
var quirkyIf = default(IfBuilder)
|
||||
@@ -1708,7 +1718,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
cIntValue(0))):
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "reraiseException"))
|
||||
|
||||
proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
|
||||
proc genAsmOrEmitStmt(p: BProc, t: AnyNode, isAsmStmt=false; result: var Rope) =
|
||||
var res = ""
|
||||
let offset =
|
||||
if isAsmStmt: 1 # first son is pragmas
|
||||
@@ -1754,14 +1764,14 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
|
||||
res.add("\L")
|
||||
result.add res.rope
|
||||
|
||||
proc genAsmStmt(p: BProc, t: PNode) =
|
||||
proc genAsmStmt(p: BProc, t: AnyNode) =
|
||||
assert(t.kind == nkAsmStmt)
|
||||
genLineDir(p, t)
|
||||
var s = newRopeAppender()
|
||||
|
||||
var asmSyntax = ""
|
||||
if (let p = t.firstSon; p.kind == nkPragma):
|
||||
for i in p:
|
||||
for i in sons(p):
|
||||
if whichPragma(i) == wAsmSyntax:
|
||||
asmSyntax = i.secondSon.strVal
|
||||
|
||||
@@ -1784,7 +1794,7 @@ proc genAsmStmt(p: BProc, t: PNode) =
|
||||
addIndent p, p.s(cpsStmts)
|
||||
p.s(cpsStmts).add runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s])
|
||||
|
||||
proc determineSection(n: PNode): TCFileSection =
|
||||
proc determineSection(n: AnyNode): TCFileSection =
|
||||
result = cfsProcHeaders
|
||||
if n.len >= 1 and n.firstSon.kind in {nkStrLit..nkTripleStrLit}:
|
||||
let sec = n.firstSon.strVal
|
||||
@@ -1792,7 +1802,7 @@ proc determineSection(n: PNode): TCFileSection =
|
||||
elif sec.startsWith("/*VARSECTION*/"): result = cfsVars
|
||||
elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders
|
||||
|
||||
proc genEmit(p: BProc, t: PNode) =
|
||||
proc genEmit(p: BProc, t: AnyNode) =
|
||||
var s = newRopeAppender()
|
||||
genAsmOrEmitStmt(p, t.secondSon, false, s)
|
||||
if p.prc == nil:
|
||||
@@ -1804,12 +1814,12 @@ proc genEmit(p: BProc, t: PNode) =
|
||||
genLineDir(p, t)
|
||||
line(p, cpsStmts, s)
|
||||
|
||||
proc genPragma(p: BProc, n: PNode) =
|
||||
proc genPragma(p: BProc, n: AnyNode) =
|
||||
for i, it in isons(n):
|
||||
case whichPragma(it)
|
||||
of wEmit: genEmit(p, it)
|
||||
of wPush:
|
||||
processPushBackendOption(p.config, p.optionsStack, p.options, n, i+1)
|
||||
processPushBackendOption(p.config, p.optionsStack, p.options, origin(n), i+1)
|
||||
of wPop:
|
||||
processPopBackendOption(p.config, p.optionsStack, p.options)
|
||||
else: discard
|
||||
@@ -1835,7 +1845,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
|
||||
if p.config.exc == excGoto:
|
||||
raiseExit(p)
|
||||
|
||||
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||
proc asgnFieldDiscriminant(p: BProc, e: AnyNode) =
|
||||
var dotExpr = e.firstSon
|
||||
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr.firstSon
|
||||
var a = initLocExpr(p, e.firstSon)
|
||||
@@ -1847,7 +1857,7 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||
message(p.config, e.info, warnCaseTransition)
|
||||
genAssignment(p, a, tmp, {})
|
||||
|
||||
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
proc genAsgn(p: BProc, e: AnyNode, fastAsgn: bool) =
|
||||
if e.firstSon.kind == nkSym and sfGoto in e.firstSon.sym.flags:
|
||||
genLineDir(p, e)
|
||||
genGotoVar(p, e.secondSon)
|
||||
@@ -1876,9 +1886,9 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
if fastAsgn: incl(a.flags, lfNoDeepCopy)
|
||||
assert(a.t != nil)
|
||||
genLineDir(p, ri)
|
||||
loadInto(p, le, ri, a)
|
||||
loadInto(p, origin(le), ri, a)
|
||||
|
||||
proc genStmts(p: BProc, t: PNode) =
|
||||
proc genStmts(p: BProc, t: AnyNode) =
|
||||
var a: TLoc = default(TLoc)
|
||||
|
||||
let isPush = p.config.hasHint(hintExtendedContext)
|
||||
|
||||
@@ -18,7 +18,7 @@ type
|
||||
|
||||
|
||||
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType)
|
||||
proc genCaseRange(p: BProc, branch: PNode, info: var SwitchCaseBuilder)
|
||||
proc genCaseRange(p: BProc, branch: AnyNode, info: var SwitchCaseBuilder)
|
||||
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc
|
||||
|
||||
proc visit(p: BProc, data, visitor: Snippet) =
|
||||
|
||||
@@ -747,7 +747,7 @@ proc hasCppCtor(m: BModule; typ: PType): bool =
|
||||
if sfConstructor in prc.flags:
|
||||
return true
|
||||
|
||||
proc genCppParamsForCtor(p: BProc; call: PNode; didGenTemp: var bool): string
|
||||
proc genCppParamsForCtor(p: BProc; call: AnyNode; didGenTemp: var bool): string
|
||||
|
||||
proc genCppInitializer(m: BModule, prc: BProc; typ: PType; didGenTemp: var bool): string =
|
||||
#To avoid creating a BProc per test when called inside a struct nil BProc is allowed
|
||||
|
||||
@@ -135,11 +135,11 @@ proc signatureHasMetaType*(t: PType; depth: int = 0): bool =
|
||||
# `HashList[T, N]`, …) is carried as a `tyStatic` node inside the otherwise
|
||||
# fully-concrete `tyGenericInst`, but it is NOT meta: the routine is a normal
|
||||
# runtime routine the owner must emit. Only an UNRESOLVED `static T` parameter
|
||||
# (no bound value, `t.n == nil`) is meta. Without this, every routine whose
|
||||
# (no bound value, `t.n.isNilNode`) is meta. Without this, every routine whose
|
||||
# signature touches a `static`-parameterized generic instance (the bulk of
|
||||
# the SSZ/`MDigest` API) is dropped from the owned-routine seeding and ends up
|
||||
# an undefined reference at link (mirrors the tyGenericBody case above).
|
||||
return t.n == nil
|
||||
return t.n.isNilNode
|
||||
if t.kind in {tyTyped, tyUntyped, tyTypeDesc, tyGenericParam,
|
||||
tyAnything, tyFromExpr, tyError}:
|
||||
return true
|
||||
@@ -512,7 +512,7 @@ proc genCLineDir(r: var Builder, p: BProc, info: TLineInfo; conf: ConfigRef) =
|
||||
if freshLineInfo(p, info):
|
||||
genCLineDir(r, info.fileIndex, info.safeLineNm, p, info, lastFileIndex)
|
||||
|
||||
proc genLineDir(p: BProc, t: PNode) =
|
||||
proc genLineDir(p: BProc; t: AnyNode) =
|
||||
if p == p.module.preInitProc: return
|
||||
let line = t.info.safeLineNm
|
||||
|
||||
@@ -595,7 +595,7 @@ include ccgtypes
|
||||
|
||||
# ------------------------------ Manager of temporaries ------------------
|
||||
|
||||
template mapTypeChooser(n: PNode): TSymKind =
|
||||
template mapTypeChooser(n: AnyNode): TSymKind =
|
||||
(if n.kind == nkSym: n.sym.kind else: skVar)
|
||||
|
||||
template mapTypeChooser(a: TLoc): TSymKind = mapTypeChooser(a.lode)
|
||||
@@ -632,8 +632,8 @@ type
|
||||
needAssignCall
|
||||
TAssignmentFlags = set[TAssignmentFlag]
|
||||
|
||||
proc genObjConstr(p: BProc, e: PNode, d: var TLoc)
|
||||
proc rawConstExpr(p: BProc, n: PNode; d: var TLoc)
|
||||
proc genObjConstr(p: BProc; e: AnyNode, d: var TLoc)
|
||||
proc rawConstExpr(p: BProc; n: AnyNode; d: var TLoc)
|
||||
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
|
||||
|
||||
type
|
||||
@@ -852,7 +852,7 @@ proc getIntTemp(p: BProc): TLoc =
|
||||
flags: {})
|
||||
p.s(cpsLocals).addVar(kind = Local, name = result.snippet, typ = NimInt)
|
||||
|
||||
proc localVarDecl(res: var Builder, p: BProc; n: PNode,
|
||||
proc localVarDecl(res: var Builder, p: BProc; n: AnyNode,
|
||||
initializer: Snippet = "",
|
||||
initializerKind: VarInitializerKind = Assignment) =
|
||||
let s = n.sym
|
||||
@@ -870,7 +870,7 @@ proc localVarDecl(res: var Builder, p: BProc; n: PNode,
|
||||
initializer = initializer,
|
||||
initializerKind = initializerKind)
|
||||
|
||||
proc assignLocalVar(p: BProc, n: PNode) =
|
||||
proc assignLocalVar(p: BProc; n: AnyNode) =
|
||||
#assert(s.loc.k == locNone) # not yet assigned
|
||||
# this need not be fulfilled for inline procs; they are regenerated
|
||||
# for each module that uses them!
|
||||
@@ -894,7 +894,7 @@ proc treatGlobalDifferentlyForHCR(m: BModule, s: PSym): bool =
|
||||
# and s.owner.kind == skModule # owner isn't always a module (global pragma on local var)
|
||||
# and s.loc.k == locGlobalVar # loc isn't always initialized when this proc is used
|
||||
|
||||
proc genGlobalVarDecl(res: var Builder, p: BProc, n: PNode; td: Snippet;
|
||||
proc genGlobalVarDecl(res: var Builder, p: BProc; n: AnyNode; td: Snippet;
|
||||
initializer: Snippet = "",
|
||||
initializerKind: VarInitializerKind = Assignment,
|
||||
allowConst = true) =
|
||||
@@ -935,7 +935,7 @@ proc genGlobalVarDecl(res: var Builder, p: BProc, n: PNode; td: Snippet;
|
||||
initializer = initializer,
|
||||
initializerKind = initializerKind)
|
||||
|
||||
proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
|
||||
proc assignGlobalVar(p: BProc; n: AnyNode; value: Rope) =
|
||||
let s = n.sym
|
||||
if s.loc.k == locNone:
|
||||
fillBackendName(p.module, s)
|
||||
@@ -999,7 +999,7 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
|
||||
backendEnsureMutable s
|
||||
resetLoc(p, s.locImpl)
|
||||
|
||||
proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode; didGenTemp: var bool) =
|
||||
proc callGlobalVarCppCtor[V: AnyNode; W: AnyNode](p: BProc; v: PSym; vn: V; value: W; didGenTemp: var bool) =
|
||||
let s = vn.sym
|
||||
fillBackendName(p.module, s)
|
||||
backendEnsureMutable s
|
||||
@@ -1018,7 +1018,7 @@ proc assignParam(p: BProc, s: PSym, retType: PType) =
|
||||
assert(s.loc.snippet != "")
|
||||
scopeMangledParam(p, s)
|
||||
|
||||
proc fillProcLoc(m: BModule; n: PNode) =
|
||||
proc fillProcLoc(m: BModule; n: AnyNode) =
|
||||
let sym = n.sym
|
||||
if sym.loc.k == locNone:
|
||||
fillBackendName(m, sym)
|
||||
@@ -1032,22 +1032,22 @@ proc getLabel(p: BProc): TLabel =
|
||||
proc fixLabel(p: BProc, labl: TLabel) =
|
||||
p.s(cpsStmts).addLabel(labl)
|
||||
|
||||
proc genVarPrototype(m: BModule, n: PNode)
|
||||
proc genVarPrototype(m: BModule, n: AnyNode)
|
||||
proc requestConstImpl(p: BProc, sym: PSym)
|
||||
proc genStmts(p: BProc, t: PNode)
|
||||
proc expr(p: BProc, n: PNode, d: var TLoc)
|
||||
proc genStmts(p: BProc, t: AnyNode)
|
||||
proc expr(p: BProc, n: AnyNode, 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 Builder; argBuilder: var CallBuilder)
|
||||
proc genLiteral(p: BProc; n: AnyNode; result: var Builder)
|
||||
proc genOtherArg(p: BProc; ri: AnyNode; i: int; typ: PType; result: var Builder; argBuilder: var CallBuilder)
|
||||
proc raiseExit(p: BProc)
|
||||
proc raiseExitCleanup(p: BProc, destroy: string)
|
||||
|
||||
proc initLocExpr(p: BProc, e: PNode, flags: TLocFlags = {}): TLoc =
|
||||
proc initLocExpr(p: BProc; e: AnyNode, flags: TLocFlags = {}): TLoc =
|
||||
result = initLoc(locNone, e, OnUnknown, flags)
|
||||
expr(p, e, result)
|
||||
|
||||
proc initLocExprSingleUse(p: BProc, e: PNode): TLoc =
|
||||
proc initLocExprSingleUse(p: BProc; e: AnyNode): TLoc =
|
||||
result = initLoc(locNone, e, OnUnknown)
|
||||
if e.kind in nkCallKinds and (e.firstSon.kind != nkSym or e.firstSon.sym.magic == mNone):
|
||||
# We cannot check for tfNoSideEffect here because of mutable parameters.
|
||||
@@ -1748,7 +1748,7 @@ when defined(newIcBackend):
|
||||
# `(ht . <sym>)` type difference. Only a subtree that clean is handed to
|
||||
# `grindPredicates` — see the descent below for why.
|
||||
result = true
|
||||
if a == nil:
|
||||
if a.isNilNode:
|
||||
if not c.isNilNode: bail("nil-ness", "not-nil", "nil")
|
||||
return
|
||||
if c.isNilNode: bail("nil-ness", "nil", "not-nil")
|
||||
@@ -1891,7 +1891,7 @@ when defined(newIcBackend):
|
||||
## disagreement with the original, so both directions are checked by the one
|
||||
## oracle rather than by a hand-written comparator that could agree with the
|
||||
## bug.
|
||||
if bnodeGrind == 0 or body == nil: return
|
||||
if bnodeGrind == 0 or body.isNilNode: return
|
||||
let htBefore = tolHtNil
|
||||
let fieldBefore = tolFieldSym
|
||||
|
||||
@@ -1908,7 +1908,7 @@ when defined(newIcBackend):
|
||||
# Asserted rather than assumed, with `==` on the reference: an equal copy
|
||||
# would not do.
|
||||
proc grindOrigins(enc: var BridgeBuf; c: BNode; a: PNode; path: string) =
|
||||
if a == nil: return
|
||||
if a.isNilNode: return
|
||||
# Through the AMBIENT accessor (`bnode.origin`, via `currentNav`), which
|
||||
# is the one a migrated generator proc will call from inside `initLoc` —
|
||||
# not the direct `originOf`, which would test a path nothing uses.
|
||||
@@ -1988,7 +1988,7 @@ when defined(newIcBackend):
|
||||
let ast = prc.ast
|
||||
if ast == nil or ast.safeLen <= bodyPos: return
|
||||
let body = son(ast, bodyPos)
|
||||
if body == nil: return
|
||||
if body.isNilNode: return
|
||||
var scope = default(BodyScope)
|
||||
var viaCursor = default(BNode)
|
||||
if not lazyBodyBNode(body, scope, viaCursor): return
|
||||
@@ -2028,7 +2028,7 @@ proc getProcTypeCast(m: BModule, prc: PSym): Rope =
|
||||
let params = extract(desc)
|
||||
result = procPtrTypeUnnamed(rettype = rettype, params = params)
|
||||
|
||||
proc genProcBody(p: BProc; procBody: PNode) =
|
||||
proc genProcBody(p: BProc; procBody: AnyNode) =
|
||||
genStmts(p, procBody) # modifies p.locals, p.init, etc.
|
||||
if {nimErrorFlagAccessed, nimErrorFlagDeclared, nimErrorFlagDisabled} * p.flags == {nimErrorFlagAccessed}:
|
||||
p.flags.incl nimErrorFlagDeclared
|
||||
@@ -2194,7 +2194,14 @@ proc genProcLvl3*(m: BModule, prc: PSym) =
|
||||
continue
|
||||
assignParam(p, param, prc.typ.returnType)
|
||||
closureSetup(p, prc)
|
||||
genProcBody(p, procBody)
|
||||
# THE FLIP: under `-d:newIcBackend` the generator is driven off the cursor
|
||||
# into the handed-off buffer, not the tree. Both spellings must produce the
|
||||
# same C, which is what the cursor-vs-`PNode` `.c` comparison checks.
|
||||
when defined(newIcBackend):
|
||||
withBridge(bodyBuf.tables):
|
||||
genProcBody(p, BNode(bodyBuf.rootCursor))
|
||||
else:
|
||||
genProcBody(p, procBody)
|
||||
|
||||
# IC: spurious write, seems fine for now:
|
||||
prc.infoImpl = tmpInfo
|
||||
@@ -2482,7 +2489,7 @@ proc requestProcDef*(m: BModule, prc: PSym) =
|
||||
## code had referenced it.
|
||||
genProc(m, prc)
|
||||
|
||||
proc genVarPrototype(m: BModule, n: PNode) =
|
||||
proc genVarPrototype(m: BModule, n: AnyNode) =
|
||||
#assert(sfGlobal in sym.flags)
|
||||
let sym = n.sym
|
||||
useHeader(m, sym)
|
||||
@@ -3373,9 +3380,9 @@ when false:
|
||||
readMergeInfo(getCFile(m), m)
|
||||
result = m
|
||||
|
||||
proc addHcrInitGuards(p: BProc, n: PNode, inInitGuard: var bool, init: var IfBuilder) =
|
||||
proc addHcrInitGuards(p: BProc; n: AnyNode, inInitGuard: var bool, init: var IfBuilder) =
|
||||
if n.kind == nkStmtList:
|
||||
for child in n:
|
||||
for child in sons(n):
|
||||
addHcrInitGuards(p, child, inInitGuard, init)
|
||||
else:
|
||||
let stmtShouldExecute = n.kind in {nkVarSection, nkLetSection} or
|
||||
@@ -3412,7 +3419,7 @@ proc handleProcGlobals(m: BModule) =
|
||||
handleProcGlobals(m)
|
||||
m.preInitProc.s(cpsStmts).add stmts.extract()
|
||||
|
||||
proc genTopLevelStmt*(m: BModule; n: PNode) =
|
||||
proc genTopLevelStmt*(m: BModule; n: AnyNode) =
|
||||
## Also called from `ic/cbackend.nim`.
|
||||
if pipelineutils.skipCodegen(m.config, n): return
|
||||
m.initProc.options = initProcOptions(m)
|
||||
@@ -3507,7 +3514,7 @@ proc writeModule(m: BModule) =
|
||||
code = stripCnifMarks(code)
|
||||
registerModuleCode(m, cf, code)
|
||||
|
||||
proc generateLibraryDestroyGlobals(graph: ModuleGraph; m: BModule; body: PNode; isDynlib: bool): PSym =
|
||||
proc generateLibraryDestroyGlobals(graph: ModuleGraph; m: BModule; body: AnyNode; isDynlib: bool): PSym =
|
||||
let prefixedName = m.config.nimMainPrefix & "NimDestroyGlobals"
|
||||
let procname = getIdent(graph.cache, prefixedName)
|
||||
result = newSym(skProc, procname, m.idgen, m.module.owner, m.module.info)
|
||||
@@ -3561,7 +3568,7 @@ proc genIcModuleDestroyGlobals*(graph: ModuleGraph; m: BModule): string =
|
||||
dtor.ast = theProc
|
||||
genProcLvl3(m, dtor)
|
||||
|
||||
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
|
||||
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: AnyNode) =
|
||||
## Also called from IC.
|
||||
if sfMainModule in m.module.flags:
|
||||
# phase ordering problem here: We need to announce this
|
||||
@@ -3584,7 +3591,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
|
||||
# if the module is cached, we don't regenerate the main proc
|
||||
# nor the dispatchers? But if the dispatchers changed?
|
||||
# XXX emit the dispatchers into its own .c file?
|
||||
if n != nil:
|
||||
if not n.isNilNode:
|
||||
m.initProc.options = initProcOptions(m)
|
||||
genProcBody(m.initProc, n)
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ proc getMagic*(op: AnyNode): TMagic =
|
||||
else: result = mNone
|
||||
else: result = mNone
|
||||
|
||||
proc isConstExpr*(n: PNode): bool =
|
||||
proc isConstExpr*(n: AnyNode): bool =
|
||||
const atomKinds = {nkCharLit..nkNilLit} # Char, Int, UInt, Str, Float and Nil literals
|
||||
n.kind in atomKinds or nfAllConst in n.flags
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
ast, astalgo, trees, msgs, platform, renderer, options,
|
||||
lineinfos, int128, modulegraphs, astmsgs
|
||||
lineinfos, int128, modulegraphs, astmsgs, bnode
|
||||
|
||||
import std/[intsets, strutils]
|
||||
|
||||
@@ -102,7 +102,7 @@ proc isPureObject*(typ: PType): bool =
|
||||
proc isUnsigned*(t: PType): bool =
|
||||
t.skipTypes(abstractInst).kind in {tyChar, tyUInt..tyUInt64}
|
||||
|
||||
proc getOrdValueAux*(n: PNode, err: var bool): Int128 =
|
||||
proc getOrdValueAux*(n: AnyNode, err: var bool): Int128 =
|
||||
var k = n.kind
|
||||
if n.typ != nil and n.typ.skipTypes(abstractInst).kind in {tyChar, tyUInt..tyUInt64}:
|
||||
k = nkUIntLit
|
||||
@@ -119,17 +119,17 @@ proc getOrdValueAux*(n: PNode, err: var bool): Int128 =
|
||||
of nkNilLit:
|
||||
int128.Zero
|
||||
of nkHiddenStdConv:
|
||||
getOrdValueAux(n[1], err)
|
||||
getOrdValueAux(n.secondSon, err)
|
||||
else:
|
||||
err = true
|
||||
int128.Zero
|
||||
|
||||
proc getOrdValue*(n: PNode): Int128 =
|
||||
proc getOrdValue*(n: AnyNode): Int128 =
|
||||
var err: bool = false
|
||||
result = getOrdValueAux(n, err)
|
||||
#assert err == false
|
||||
|
||||
proc getOrdValue*(n: PNode, onError: Int128): Int128 =
|
||||
proc getOrdValue*(n: AnyNode, onError: Int128): Int128 =
|
||||
var err = false
|
||||
result = getOrdValueAux(n, err)
|
||||
if err:
|
||||
@@ -1392,17 +1392,17 @@ proc classify*(t: PType): OrdinalType =
|
||||
result = IntLike
|
||||
else: result = NoneLike
|
||||
|
||||
proc skipConv*(n: PNode): PNode =
|
||||
proc skipConv*[T: AnyNode](n: T): T =
|
||||
result = n
|
||||
case n.kind
|
||||
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
|
||||
# only skip the conversion if it doesn't lose too important information
|
||||
# (see bug #1334)
|
||||
if n[0].typ.classify == n.typ.classify:
|
||||
result = n[0]
|
||||
if n.firstSon.typ.classify == n.typ.classify:
|
||||
result = n.firstSon
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
if n[1].typ.classify == n.typ.classify:
|
||||
result = n[1]
|
||||
if n.secondSon.typ.classify == n.typ.classify:
|
||||
result = n.secondSon
|
||||
else: discard
|
||||
|
||||
proc skipHidden*(n: PNode): PNode =
|
||||
|
||||
Reference in New Issue
Block a user