Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

codegen: don't use PSym for locals #914

Merged
merged 16 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions compiler/backend/cbackend.nim
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,12 @@ func hash(x: PSym): int = hash(x.id)

proc writeMangledLocals(p: BProc) =
## Writes the mangled names of `p`'s locals to the module's NDI file.
for it in p.locals.items:
# writing out mangled names for compiler-inserted variables (temporaries)
# is not necessary (lode is guaranteed to be a symbol)
if it.lode.sym.kind != skTemp:
writeMangledName(p.module.ndi, it.lode.sym, it.r, p.config)
for i, it in p.locals.pairs:
# only write a mapping for locals that have both a user-provided
# and mangled name (compile-time-only parameters don't have one)
if p.body[i].name != nil and it.r.len > 0:
writeMangledName(p.module.ndi, it.lode.info, p.body[i].name, it.r,
p.config)

func registerInline(g: var InliningData, prc: PSym): uint32 =
## If not already registered, registers the inline procedure `prc` with
Expand Down Expand Up @@ -228,7 +229,7 @@ proc processEvent(g: BModuleList, inl: var InliningData, discovery: var Discover

let body = generateIR(g.graph, bmod.idgen, evt.sym, evt.body)
# emit into the procedure:
genStmts(p, merge(p.body, body))
genPartial(p, merge(p.body, body))

processLate(bmod, discovery, inl, evt.module, inlineId)
of bekProcedure:
Expand Down Expand Up @@ -416,10 +417,6 @@ proc generateCode*(graph: ModuleGraph, g: BModuleList, mlist: sink ModuleList) =
s = it.sym
m = g.modules[moduleId(s)]
writeMangledName(m.ndi, s, it.name, g.config)
# parameters:
for p in it.params.items:
if p.k != locNone: # not all parameters have locs
writeMangledName(m.ndi, s, p.r, g.config)

template write(loc: TLoc) =
let s = loc.lode.sym
Expand Down
23 changes: 12 additions & 11 deletions compiler/backend/ccgcalls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ proc reportObservableStore(p: BProc; le, ri: CgNode) =
# do NOT follow ``cnkDerefView`` here!
case n.kind
of cnkSym:
# we don't own the location so it escapes:
if n.sym.owner != p.prc:
return true
elif inTryStmt and sfUsedInFinallyOrExcept in n.sym.flags:
# this must be a global -> the mutation escapes
return true
of cnkLocal:
if inTryStmt and sfUsedInFinallyOrExcept in p.body[n.local].flags:
zerbina marked this conversation as resolved.
Show resolved Hide resolved
# it is also an observable store if the location is used
# in 'except' or 'finally'
return true
# we don't own the location so it escapes
return false
of cnkFieldAccess, cnkBracketAccess, cnkCheckedFieldAccess:
n = n[0]
Expand Down Expand Up @@ -134,11 +135,11 @@ proc fixupCall(p: BProc, le, ri: CgNode, d: var TLoc,

proc genBoundsCheck(p: BProc; arr, a, b: TLoc)

proc reifiedOpenArray(n: CgNode): bool {.inline.} =
proc reifiedOpenArray(p: BProc, n: CgNode): bool {.inline.} =
var x = n
while x.kind in {cnkAddr, cnkHiddenAddr, cnkHiddenConv, cnkDerefView}:
x = x.operand
if x.kind == cnkSym and x.sym.kind == skParam:
if x.kind == cnkLocal and p.locals[x.local].k == locParam:
result = false
else:
result = true
Expand All @@ -165,7 +166,7 @@ proc genOpenArraySlice(p: BProc; q: CgNode; formalType, destType: PType): (Rope,
[rdLoc(a), rdLoc(b), intLiteral(first), dest],
lengthExpr)
of tyOpenArray, tyVarargs:
if reifiedOpenArray(q[1]):
if reifiedOpenArray(p, q[1]):
result = ("($3*)($1.Field0)+($2)" % [rdLoc(a), rdLoc(b), dest],
lengthExpr)
else:
Expand Down Expand Up @@ -208,7 +209,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: CgNode): Rope =
initLocExpr(p, if n.kind == cnkHiddenConv: n.operand else: n, a)
case skipTypes(a.t, abstractVar+{tyStatic}).kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(n):
if reifiedOpenArray(p, n):
result = "$1.Field0, $1.Field1" % [rdLoc(a)]
else:
result = "$1, $1Len_0" % [rdLoc(a)]
Expand Down Expand Up @@ -368,9 +369,9 @@ proc genClosureCall(p: BProc, le, ri: CgNode, d: var TLoc) =
genCallPattern()
exitCall(p, ri[0], canRaise)

proc notYetAlive(n: CgNode): bool {.inline.} =
proc notYetAlive(p: BProc, n: CgNode): bool {.inline.} =
let r = getRoot(n)
result = r != nil and r.locId == 0
result = r != nil and r.kind == cnkLocal and p.locals[r.local].k == locNone

proc isInactiveDestructorCall(p: BProc, e: CgNode): bool =
#[ Consider this example.
Expand All @@ -390,7 +391,7 @@ proc isInactiveDestructorCall(p: BProc, e: CgNode): bool =
the 'let args = ...' statement. We exploit this to generate better
code for 'return'. ]#
result = e.len == 2 and e[0].kind == cnkSym and
e[0].sym.name.s == "=destroy" and notYetAlive(e[1].operand)
e[0].sym.name.s == "=destroy" and notYetAlive(p, e[1].operand)

proc genAsgnCall(p: BProc, le, ri: CgNode, d: var TLoc) =
if p.withinBlockLeaveActions > 0 and isInactiveDestructorCall(p, ri):
Expand Down
43 changes: 14 additions & 29 deletions compiler/backend/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =

case a.t.skipTypes(abstractVar).kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(a.lode):
if reifiedOpenArray(p, a.lode):
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), a.rdLoc])
else:
Expand Down Expand Up @@ -177,7 +177,7 @@ proc genAssignment(p: BProc, dest, src: TLoc) =
# HACK: ``cgirgen`` elides to-openArray-conversion operations, so we
# need to reconstruct that information here. Remove this case
# once ``cgirgen`` no longer elides the operations
if reifiedOpenArray(dest.lode):
if reifiedOpenArray(p, dest.lode):
genOpenArrayConv(p, dest, src)
else:
linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
Expand Down Expand Up @@ -486,7 +486,7 @@ proc unaryArith(p: BProc, e: CgNode, d: var TLoc, op: TMagic) =
proc genDeref(p: BProc, e: CgNode, d: var TLoc) =
let
src = e.operand
mt = mapType(p.config, src.typ, mapTypeChooser(src))
mt = mapType(p.config, src.typ, mapTypeChooser(p, src))
if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags:
# XXX the amount of hacks for C's arrays is incredible, maybe we should
# simply wrap them in a struct? --> Losing auto vectorization then?
Expand Down Expand Up @@ -528,7 +528,7 @@ proc genDeref(p: BProc, e: CgNode, d: var TLoc) =
putIntoDest(p, d, e, "(*$1)" % [rdLoc(a)], a.storage)

proc genAddr(p: BProc, e: CgNode, mutate: bool, d: var TLoc) =
if mapType(p.config, e.operand.typ, mapTypeChooser(e.operand)) == ctArray:
if mapType(p.config, e.operand.typ, mapTypeChooser(p, e.operand)) == ctArray:
expr(p, e.operand, d)
else:
var a: TLoc
Expand Down Expand Up @@ -736,7 +736,7 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
let ty = skipTypes(arr.t, abstractVarRange)
case ty.kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(arr.lode):
if reifiedOpenArray(p, arr.lode):
linefmt(p, cpsStmts,
"if ($2-$1 != -1 && " &
"((NU)($1) >= (NU)($3.Field1) || (NU)($2) >= (NU)($3.Field1))){ #raiseIndexError(); $4}$n",
Expand All @@ -763,7 +763,7 @@ proc genOpenArrayElem(p: BProc, n, x, y: CgNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, x, a)
initLocExpr(p, y, b)
if not reifiedOpenArray(x):
if not reifiedOpenArray(p, x):
# emit range check:
if optBoundsCheck in p.options:
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)){ #raiseIndexError2($1,$2Len_0-1); $3}$n",
Expand Down Expand Up @@ -1326,7 +1326,7 @@ proc genArrayLen(p: BProc, e: CgNode, d: var TLoc, op: TMagic) =
else:
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)+1", [rdLoc(b), rdLoc(c)]))
else:
if not reifiedOpenArray(a):
if not reifiedOpenArray(p, a):
if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")
else: unaryExpr(p, e, d, "$1Len_0")
else:
Expand Down Expand Up @@ -1687,7 +1687,7 @@ proc skipAddr(n: CgNode): CgNode =
proc genWasMoved(p: BProc; n: CgNode) =
var a: TLoc
let n1 = n[1].skipAddr
if p.withinBlockLeaveActions > 0 and notYetAlive(n1):
if p.withinBlockLeaveActions > 0 and notYetAlive(p, n1):
discard
else:
initLocExpr(p, n1, a)
Expand Down Expand Up @@ -2107,8 +2107,8 @@ proc expr(p: BProc, n: CgNode, d: var TLoc) =
useConst(p.module, sym)
putLocIntoDest(p, d, p.module.consts[sym])
of skVar, skForVar, skLet:
if {sfGlobal, sfThread} * sym.flags != {}:
genVarPrototype(p.module, n)
assert sfGlobal in sym.flags
genVarPrototype(p.module, n)

if sfThread in sym.flags:
accessThreadLocalVar(p, sym)
Expand All @@ -2117,26 +2117,11 @@ proc expr(p: BProc, n: CgNode, d: var TLoc) =
putIntoDest(p, d, loc.lode, "NimTV_->" & loc.r)
else:
putLocIntoDest(p, d, p.module.globals[sym])
elif sfGlobal in sym.flags:
putLocIntoDest(p, d, p.module.globals[sym])
else: # must be a local then
putLocIntoDest(p, d, p.locals[sym])
of skResult:
# the 'result' location is either a parameter or local
if p.params[0].k != locNone:
putLocIntoDest(p, d, p.params[0])
else:
putLocIntoDest(p, d, p.locals[sym])
of skTemp:
putLocIntoDest(p, d, p.locals[sym])
of skParam:
if sym.position + 1 < p.params.len:
putLocIntoDest(p, d, p.params[sym.position + 1])
else:
# must be the hidden environment parameter (which is treated as a
# local)
putLocIntoDest(p, d, p.locals[sym])
putLocIntoDest(p, d, p.module.globals[sym])
else: internalError(p.config, n.info, "expr(" & $sym.kind & "); unknown symbol")
of cnkLocal:
putLocIntoDest(p, d, p.locals[n.local])
of cnkStrLit:
putDataIntoDest(p, d, n, genLiteral(p, n))
of cnkIntLit, cnkUIntLit, cnkFloatLit, cnkNilLit:
Expand Down Expand Up @@ -2202,7 +2187,7 @@ proc expr(p: BProc, n: CgNode, d: var TLoc) =
of cnkClosureConstr: genClosure(p, n, d)
of cnkEmpty: discard
of cnkRepeatStmt: genRepeatStmt(p, n)
of cnkDef: genDef(p, n)
of cnkDef: genSingleVar(p, n[0], n[1])
of cnkCaseStmt: genCase(p, n)
of cnkReturnStmt: genReturnStmt(p, n)
of cnkBreakStmt: genBreakStmt(p, n)
Expand Down
31 changes: 13 additions & 18 deletions compiler/backend/ccgstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -155,31 +155,22 @@ proc genGotoVar(p: BProc; value: CgNode) =

proc genBracedInit(p: BProc, n: CgNode; isConst: bool; optionalType: PType): Rope

proc genSingleVar(p: BProc, v: PSym; vn, value: CgNode) =
if sfGoto in v.flags:
proc genSingleVar(p: BProc, vn, value: CgNode) =
## Generates and emits the C code for the definition statement of a local.
let v = vn.local

if sfGoto in p.body[v].flags:
# translate 'var state {.goto.} = X' into 'goto LX':
genGotoVar(p, value)
return

assert {sfGlobal, sfThread} * v.flags == {}
let imm = isAssignedImmediately(p.config, value)
assignLocalVar(p, vn)
initLocalVar(p, v, imm)

if value.kind != cnkEmpty:
genLineDir(p, vn)
# we have a parameter aliasing issue here: passing `p.locals[v]`
# as the parameter directly would be an aliasing rule violation.
# Since the initializer expression cannot reference `v` itself,
# it's safe to temporarily move the loc out of ``p.locals``
var loc = move p.locals[v]
loadInto(p, vn, value, loc)
p.locals.assign(v, loc) # put it back

proc genDef(p: BProc, a: CgNode) =
assert a.kind == cnkDef
let v = a[0].sym
genSingleVar(p, v, a[0], a[1])
loadInto(p, vn, value, p.locals[v])

proc genIf(p: BProc, n: CgNode) =
# if (expr1)
Expand Down Expand Up @@ -595,7 +586,7 @@ proc genCase(p: BProc, t: CgNode) =
genCaseGeneric(p, t, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
"if ($1 == $2) goto $3;$n")
else:
if t[0].kind == cnkSym and sfGoto in t[0].sym.flags:
if t[0].kind == cnkLocal and sfGoto in p.body[t[0].local].flags:
genGotoForCase(p, t)
else:
genOrdinalCase(p, t)
Expand Down Expand Up @@ -725,7 +716,7 @@ proc genAsmOrEmitStmt(p: BProc, t: CgNode, isAsmStmt=false): Rope =
var a: TLoc
initLocExpr(p, it, a)
res.add(rdLoc(a))
of skVar, skLet, skForVar, skParam, skResult, skTemp:
of skVar, skLet, skForVar:
# make sure the C type description is available:
discard getTypeDesc(p.module, skipTypes(sym.typ, abstractPtrs))
var a: TLoc
Expand All @@ -741,6 +732,10 @@ proc genAsmOrEmitStmt(p: BProc, t: CgNode, isAsmStmt=false): Rope =
res.add(p.fieldName(sym))
else:
unreachable(sym.kind)
of cnkLocal:
# make sure the C type description is available:
discard getTypeDesc(p.module, skipTypes(it.typ, abstractPtrs))
res.add(rdLoc(p.locals[it.local]))
of cnkType:
res.add(getTypeDesc(p.module, it.typ))
else:
Expand Down Expand Up @@ -825,7 +820,7 @@ proc asgnFieldDiscriminant(p: BProc, e: CgNode) =
genAssignment(p, a, tmp)

proc genAsgn(p: BProc, e: CgNode) =
if e[0].kind == cnkSym and sfGoto in e[0].sym.flags:
if e[0].kind == cnkLocal and sfGoto in p.body[e[0].local].flags:
genLineDir(p, e)
genGotoVar(p, e[1])
elif optFieldCheck in p.options and isDiscriminantField(e[0]):
Expand Down
29 changes: 14 additions & 15 deletions compiler/backend/ccgtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -53,27 +53,26 @@ proc mangleParamName(c: ConfigRef; s: PSym): Rope =

result = res.rope

proc mangleLocalName(p: BProc; s: PSym): Rope =
assert s.kind in skLocalVars+{skTemp}
#assert sfGlobal notin s.flags
if true:
var key: string
shallowCopy(key, s.name.s.mangle)
proc mangleLocalName(p: BProc; name: PIdent, id: LocalId): Rope =
if name.isNil:
# use the ID prefixed by an underscore, which is guaranteed to be a unique
# name within the procedure
result = "_" & $id.int
else:
# mangle the user-defiend name, also accounting for shadowed names
var key = name.s.mangle
let counter = p.sigConflicts.getOrDefault(key)
result = key.rope
if s.kind == skTemp:
# speed up conflict search for temps (these are quite common):
if counter != 0: result.add "_" & rope(counter+1)
elif counter != 0 or isKeyword(s.name) or p.module.g.config.cppDefines.contains(key):
result = key
if counter != 0 or isKeyword(name) or p.module.g.config.cppDefines.contains(key):
result.add "_" & rope(counter+1)
p.sigConflicts.inc(key)

proc scopeMangledParam(p: BProc; param: PSym) =
proc scopeMangledParam(p: BProc; name: PIdent) =
## parameter generation doesn't have access to a ``BProc``, so we have to
## remember these parameter names are already in scope to be able to
## generate unique identifiers reliably (consider that ``var a = a`` is
## even an idiom in Nim).
var key = param.name.s.mangle
var key = name.s.mangle
p.sigConflicts.inc(key)

const
Expand Down Expand Up @@ -205,7 +204,7 @@ proc addAbiCheck(m: BModule, t: PType, name: Rope) =

proc initResultParamLoc(conf: ConfigRef; param: CgNode): TLoc =
result = initLoc(locParam, param, "Result", OnStack)
let t = param.sym.typ
let t = param.typ
if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, t):
incl(result.flags, lfIndirect)
result.storage = OnUnknown
Expand Down Expand Up @@ -369,7 +368,7 @@ proc prepareParameters(m: BModule, t: PType): seq[TLoc] =
else:
OnStack

result[i] = initLoc(locParam, toSymNode(params[i]),
result[i] = initLoc(locParam, newLocalRef(LocalId(i), param.info, param.typ),
mangleParamName(m.config, param), storage)

if ccgIntroducedPtr(m.config, param, t[0]):
Expand Down
Loading
Loading