From 1e167eb8ffac56f1299dfbec2851ae7870425580 Mon Sep 17 00:00:00 2001 From: zerbina <100542850+zerbina@users.noreply.github.com> Date: Sat, 8 Jul 2023 20:20:15 +0000 Subject: [PATCH 1/8] cgen: decouple `TLoc` from `TSym` Store all locs associated with symbols in lookup tables, with `TSym.loc` only being queried (but never written) for the external name or user- provided flags. In order to efficiently associate a `TSym` with a code-generator `TLoc`, each `TSym` stores a one-based index (`locId`) into one of the code generator's lookup tables. A table-based approach would have too, but it's slightly slower (~1.4% when building the compiler itselfs). In general, `cgen` becomes more strict with locs, now requiring globals, constants, and parameters to have their loc set-up once at definition processing time. Procedures, fields, and locals still need to support ad-hoc loc setup. Other changes: - writing the mangled names to NDI files is temporarily disabled - in symbol definitions contexts, `loc.t` is replaced with the querying the symbol's type directly (both are equivalent) - locs for constants now store a symbol node in their `lode` field --- compiler/ast/ast.nim | 3 +- compiler/ast/ast_types.nim | 3 +- compiler/backend/ccgcalls.nim | 2 +- compiler/backend/ccgexprs.nim | 96 ++++++++++------------- compiler/backend/ccgreset.nim | 12 ++- compiler/backend/ccgstmts.nim | 24 +++--- compiler/backend/ccgthreadvars.nim | 8 +- compiler/backend/ccgtypes.nim | 120 ++++++++++++++--------------- compiler/backend/cgen.nim | 101 +++++++++++++----------- compiler/backend/cgendata.nim | 68 ++++++++++++++++ compiler/utils/containers.nim | 5 ++ 11 files changed, 253 insertions(+), 189 deletions(-) diff --git a/compiler/ast/ast.nim b/compiler/ast/ast.nim index ff90b61364d..72f7215f66a 100644 --- a/compiler/ast/ast.nim +++ b/compiler/ast/ast.nim @@ -510,7 +510,8 @@ template transitionSymKindCommon*(k: TSymKind) = s[] = TSym(kind: k, itemId: obj.itemId, magic: obj.magic, typ: obj.typ, name: obj.name, info: obj.info, owner: obj.owner, flags: obj.flags, ast: obj.ast, options: obj.options, position: obj.position, offset: obj.offset, - loc: obj.loc, annex: obj.annex, constraint: obj.constraint) + loc: obj.loc, locId: obj.locId, + annex: obj.annex, constraint: obj.constraint) when defined(nimsuggest): s.allUsages = obj.allUsages diff --git a/compiler/ast/ast_types.nim b/compiler/ast/ast_types.nim index e3a5704a94b..d7136e464bb 100644 --- a/compiler/ast/ast_types.nim +++ b/compiler/ast/ast_types.nim @@ -1714,6 +1714,8 @@ type ## for variables a slot index for the evaluator offset*: int ## offset of record field loc*: TLoc + locId*: uint32 ## associates the symbol with a loc in the C code + ## generator. 0 means unset. annex*: PLib ## additional fields (seldom used, so we use a ## reference to another object to save space) constraint*: PNode ## additional constraints like 'lit|result'; also @@ -1759,7 +1761,6 @@ type align*: int16 ## the type's alignment requirements paddingAtEnd*: int16 ## lockLevel*: TLockLevel ## lock level as required for deadlock checking - loc*: TLoc typeInst*: PType ## for generic instantiations the tyGenericInst that led to this ## type; for tyError the previous type if avaiable uniqueId*: ItemId ## due to a design mistake, we need to keep the real ID here as it diff --git a/compiler/backend/ccgcalls.nim b/compiler/backend/ccgcalls.nim index 3df75cf23c5..dca43038aa3 100644 --- a/compiler/backend/ccgcalls.nim +++ b/compiler/backend/ccgcalls.nim @@ -467,7 +467,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = proc notYetAlive(n: PNode): bool {.inline.} = let r = getRoot(n) - result = r != nil and r.loc.lode == nil + result = r != nil and r.locId == 0 proc isInactiveDestructorCall(p: BProc, e: PNode): bool = #[ Consider this example. diff --git a/compiler/backend/ccgexprs.nim b/compiler/backend/ccgexprs.nim index 887a73c9b51..426972274c3 100644 --- a/compiler/backend/ccgexprs.nim +++ b/compiler/backend/ccgexprs.nim @@ -602,9 +602,8 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) = else: var rtyp: PType let field = lookupFieldAgain(p, ty, f, r, addr rtyp) - if field.loc.r == "" and rtyp != nil: fillObjectFields(p.module, rtyp) - if field.loc.r == "": internalError(p.config, e.info, "genRecordField 3 " & typeToString(ty)) - r.addf(".$1", [field.loc.r]) + ensureObjectFields(p.module, field, rtyp) + r.addf(".$1", [p.fieldLoc(field).r]) putIntoDest(p, d, e, r, a.storage) proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) @@ -624,7 +623,7 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) = initLoc(v, locExpr, disc, OnUnknown) v.r = obj v.r.add(".") - v.r.add(disc.sym.loc.r) + v.r.add(p.fieldLoc(disc.sym).r) genInExprAux(p, it, u, v, test) var msg = "" if optDeclaredLocs in p.config.globalOptions: @@ -686,11 +685,10 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = var r = rdLoc(a) let f = e[0][1].sym let field = lookupFieldAgain(p, ty, f, r) - if field.loc.r == "": fillObjectFields(p.module, ty) - if field.loc.r == "": - internalError(p.config, e.info, "genCheckedRecordField") # generate the checks: + ensureObjectFields(p.module, field, ty) + # generate the checks: genFieldCheck(p, e, r, field) - r.add(ropecg(p.module, ".$1", [field.loc.r])) + r.add(ropecg(p.module, ".$1", [p.fieldLoc(field).r])) putIntoDest(p, d, e[0], r, a.storage) else: genRecordField(p, e[0], d) @@ -1040,10 +1038,8 @@ proc specializeInitObjectN(p: BProc, accessor: Rope, n: PNode, typ: PType) = p.config.internalAssert(n[0].kind == nkSym, n.info, "specializeInitObjectN") let disc = n[0].sym - if disc.loc.r == "": fillObjectFields(p.module, typ) - p.config.internalAssert(disc.loc.t != nil, n.info, - "specializeInitObjectN()") - lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r]) + ensureObjectFields(p.module, disc, typ) + lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, p.fieldLoc(disc).r]) for i in 1.." & sym.loc.r) + let loc {.cursor.} = p.module.globals[sym] + putIntoDest(p, d, loc.lode, "NimTV_->" & loc.r) else: - putLocIntoDest(p, d, sym.loc) + 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, sym.loc) + putLocIntoDest(p, d, p.locals[sym]) of skTemp: - when false: - # this is more harmful than helpful. - if sym.loc.r == "": - # we now support undeclared 'skTemp' variables for easier - # transformations in other parts of the compiler: - assignLocalVar(p, n) - if sym.loc.r == "" or sym.loc.t == nil: - #echo "FAILED FOR PRCO ", p.prc.name.s - #echo renderTree(p.prc.ast, {renderIds}) - internalError(p.config, n.info, "expr: temp not init " & sym.name.s & "_" & $sym.id) - putLocIntoDest(p, d, sym.loc) + putLocIntoDest(p, d, p.locals[sym]) of skParam: - if sym.loc.r == "" or sym.loc.t == nil: - # echo "FAILED FOR PRCO ", p.prc.name.s - # debug p.prc.typ.n - # echo renderTree(p.prc.ast, {renderIds}) - internalError(p.config, n.info, "expr: param not init " & sym.name.s & "_" & $sym.id) - putLocIntoDest(p, d, sym.loc) + 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]) else: internalError(p.config, n.info, "expr(" & $sym.kind & "); unknown symbol") of nkNilLit: if not isEmptyType(n.typ): diff --git a/compiler/backend/ccgreset.nim b/compiler/backend/ccgreset.nim index 9c1575603da..c5dc98757c4 100644 --- a/compiler/backend/ccgreset.nim +++ b/compiler/backend/ccgreset.nim @@ -30,9 +30,8 @@ proc specializeResetN(p: BProc, accessor: Rope, n: PNode; of nkRecCase: p.config.internalAssert(n[0].kind == nkSym, n.info, "specializeResetN") let disc = n[0].sym - if disc.loc.r == "": fillObjectFields(p.module, typ) - p.config.internalAssert(disc.loc.t != nil, n.info, "specializeResetN()") - lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r]) + ensureObjectFields(p.module, disc, typ) + lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, p.fieldLoc(disc).r]) for i in 1..