From 96ebe3da9fc26fd57b0ef67b6c57087abe4b9642 Mon Sep 17 00:00:00 2001 From: zerbina <100542850+zerbina@users.noreply.github.com> Date: Fri, 2 Jun 2023 00:41:56 +0200 Subject: [PATCH] generate method dispatchers prior to code-gen (#734) ## Summary Move the method dispatcher generation out of the code generators (`cgen` and `jsgen`) and into the orchestrators. This is another step towards unifying the backend processing. Methods are now also subject to dead-code elimination, meaning that if none of the methods attached to an object hierarchy are called, no code will be generated for them. ## Details The dispatchers do not appear in calls prior to `transf`, so the DCE implementation used by IC backend cannot analyze them. For this reason, `cgen` continues to special-case methods. In addition, remove the unused `objHasKidsValid` enum value. ### Future Direction Given that all backends need to generate method dispatchers, this step (lowering methods into procedures) should happen through some common facility in the future. --- compiler/backend/cbackend.nim | 3 +++ compiler/backend/ccgexprs.nim | 6 ++---- compiler/backend/cgen.nim | 9 ++++++--- compiler/backend/cgendata.nim | 1 - compiler/backend/cgmeth.nim | 19 +++++++++++++------ compiler/backend/jsbackend.nim | 3 +++ compiler/backend/jsgen.nim | 15 --------------- 7 files changed, 27 insertions(+), 29 deletions(-) diff --git a/compiler/backend/cbackend.nim b/compiler/backend/cbackend.nim index be33788c6f6..f7bb8592f47 100644 --- a/compiler/backend/cbackend.nim +++ b/compiler/backend/cbackend.nim @@ -12,6 +12,7 @@ import compiler/backend/[ cgen, cgendata, + cgmeth, extccomp ], compiler/front/[ @@ -36,6 +37,8 @@ proc generateCode*(graph: ModuleGraph, mlist: sink ModuleList) = let config = graph.config + generateMethodDispatchers(graph) + var g = newModuleList(graph) # first create a module list entry for each input module. This has to happen diff --git a/compiler/backend/ccgexprs.nim b/compiler/backend/ccgexprs.nim index 1f2717820c0..50d7a8e3d01 100644 --- a/compiler/backend/ccgexprs.nim +++ b/compiler/backend/ccgexprs.nim @@ -2268,8 +2268,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = var sym = n.sym case sym.kind of skMethod: - if useAliveDataFromDce in p.module.flags or {sfDispatcher, sfForward} * sym.flags != {}: - # we cannot produce code for the dispatcher yet: + if useAliveDataFromDce in p.module.flags or {sfForward} * sym.flags != {}: fillProcLoc(p.module, n) genProcPrototype(p.module, sym) else: @@ -2471,8 +2470,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = genProc(p.module, prc) elif prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags: if ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or - (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or - (prc.kind == skMethod): + (sfExportc in prc.flags and lfExportLib in prc.loc.flags): # due to a bug/limitation in the lambda lifting, unused inner procs # are not transformed correctly. We work around this issue (#411) here # by ensuring it's no inner proc (owner is a module). diff --git a/compiler/backend/cgen.nim b/compiler/backend/cgen.nim index 4c4b052a409..616a72dc3cf 100644 --- a/compiler/backend/cgen.nim +++ b/compiler/backend/cgen.nim @@ -1747,9 +1747,12 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone: discard cgsym(m, "initThreadVarsEmulation") - incl m.flags, objHasKidsValid - let disp = generateMethodDispatchers(graph) - for x in disp: genProcAux(m, x.sym) + if useAliveDataFromDce in m.flags: + # methods need to be special-cased for IC, as whether a dispatcher is + # alive is only know after ``transf`` (phase-ordering problem) + generateMethodDispatchers(graph) + for disp in dispatchers(graph): + genProcAux(m, disp) # for compatibility, the code generator still manages its own "closed order" # list, but this should be phased out eventually diff --git a/compiler/backend/cgendata.nim b/compiler/backend/cgendata.nim index 83b5cc70170..578f9ccd3dd 100644 --- a/compiler/backend/cgendata.nim +++ b/compiler/backend/cgendata.nim @@ -124,7 +124,6 @@ type ## a frame var twice in an init proc isHeaderFile, ## C source file is the header file includesStringh, ## C source file already includes ```` - objHasKidsValid ## whether we can rely on tfObjHasKids useAliveDataFromDce ## use the `alive: IntSet` field instead of ## computing alive data on our own. diff --git a/compiler/backend/cgmeth.nim b/compiler/backend/cgmeth.nim index 709dbf79a95..130f84079be 100644 --- a/compiler/backend/cgmeth.nim +++ b/compiler/backend/cgmeth.nim @@ -258,9 +258,10 @@ proc sortBucket(a: var seq[PSym], relevantCols: IntSet) = a[j] = v if h == 1: break -proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PSym = +proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet) = var base = methods[0].ast[dispatcherPos].sym - result = base + # XXX: `base` is not the method marked with ``.base``, but rather the + # *dispatcher* var paramLen = base.typ.len var nilchecks = newNodeI(nkStmtList, base.info) var disp = newNodeI(nkIfStmt, base.info) @@ -315,10 +316,12 @@ proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PS disp = ret nilchecks.add disp nilchecks.flags.incl nfTransf # should not be further transformed - result.ast[bodyPos] = nilchecks + base.ast[bodyPos] = nilchecks -proc generateMethodDispatchers*(g: ModuleGraph): PNode = - result = newNode(nkStmtList) +proc generateMethodDispatchers*(g: ModuleGraph) = + ## For each method dispatcher, generates the body and updates the definition. + ## This procedure must only be called once, and only *after* all methods were + ## registered. for bucket in 0.. 0: let n = newNode(nkStmtList) @@ -2692,8 +2680,5 @@ proc finalCodegenActions*(graph: ModuleGraph; globals: PGlobals, m: BModule) = genTopLevelStmt(globals, m, n) - if sfMainModule in m.module.flags: - finishMainModule(graph, globals, m) - proc wholeCode*(globals: PGlobals): Rope = result = globals.typeInfo & globals.constants & globals.code \ No newline at end of file