refactoring: C codegen with fewer global variables

This commit is contained in:
Araq 2016-12-05 12:14:24 +01:00
commit ba38b83dd5
6 changed files with 79 additions and 78 deletions

View file

@ -206,8 +206,8 @@ proc genSingleVar(p: BProc, a: PNode) =
genObjectInit(p.module.preInitProc, cpsInit, v.typ, v.loc, true) genObjectInit(p.module.preInitProc, cpsInit, v.typ, v.loc, true)
# Alternative construction using default constructor (which may zeromem): # Alternative construction using default constructor (which may zeromem):
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc) # if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
if sfExportc in v.flags and generatedHeader != nil: if sfExportc in v.flags and p.module.g.generatedHeader != nil:
genVarPrototypeAux(generatedHeader, v) genVarPrototypeAux(p.module.g.generatedHeader, v)
registerGcRoot(p, v) registerGcRoot(p, v)
else: else:
let value = a.sons[2] let value = a.sons[2]
@ -1024,10 +1024,6 @@ proc genEmit(p: BProc, t: PNode) =
genLineDir(p, t) genLineDir(p, t)
line(p, cpsStmts, s) line(p, cpsStmts, s)
var
breakPointId: int = 0
gBreakpoints: Rope # later the breakpoints are inserted into the main proc
proc genBreakPoint(p: BProc, t: PNode) = proc genBreakPoint(p: BProc, t: PNode) =
var name: string var name: string
if optEndb in p.options: if optEndb in p.options:
@ -1035,10 +1031,10 @@ proc genBreakPoint(p: BProc, t: PNode) =
assert(t.sons[1].kind in {nkStrLit..nkTripleStrLit}) assert(t.sons[1].kind in {nkStrLit..nkTripleStrLit})
name = normalize(t.sons[1].strVal) name = normalize(t.sons[1].strVal)
else: else:
inc(breakPointId) inc(p.module.g.breakPointId)
name = "bp" & $breakPointId name = "bp" & $p.module.g.breakPointId
genLineDir(p, t) # BUGFIX genLineDir(p, t) # BUGFIX
appcg(p.module, gBreakpoints, appcg(p.module, p.module.g.breakpoints,
"#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [ "#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [
rope(toLinenumber(t.info)), makeCString(toFilename(t.info)), rope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
makeCString(name)]) makeCString(name)])

View file

@ -1084,7 +1084,7 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
let owner = t.skipTypes(typedescPtrs).owner.getModule let owner = t.skipTypes(typedescPtrs).owner.getModule
if owner != m.module: if owner != m.module:
# make sure the type info is created in the owner module # make sure the type info is created in the owner module
discard genTypeInfo(owner.bmod, origType) discard genTypeInfo(m.g.modules[owner.position], origType)
# reference the type info as extern here # reference the type info as extern here
discard cgsym(m, "TNimType") discard cgsym(m, "TNimType")
discard cgsym(m, "TNimNode") discard cgsym(m, "TNimNode")

View file

@ -26,20 +26,13 @@ when options.hasTinyCBackend:
# implementation # implementation
var
generatedHeader: BModule
proc addForwardedProc(m: BModule, prc: PSym) = proc addForwardedProc(m: BModule, prc: PSym) =
m.forwardedProcs.add(prc) m.forwardedProcs.add(prc)
inc(gForwardedProcsCounter) inc(m.g.forwardedProcsCounter)
proc getCgenModule(s: PSym): BModule =
result = if s.position >= 0 and s.position < gModules.len: gModules[s.position]
else: nil
proc findPendingModule(m: BModule, s: PSym): BModule = proc findPendingModule(m: BModule, s: PSym): BModule =
var ms = getModule(s) var ms = getModule(s)
result = gModules[ms.position] result = m.g.modules[ms.position]
proc emitLazily(s: PSym): bool {.inline.} = proc emitLazily(s: PSym): bool {.inline.} =
result = optDeadCodeElim in gGlobalOptions or result = optDeadCodeElim in gGlobalOptions or
@ -772,8 +765,8 @@ proc requestConstImpl(p: BProc, sym: PSym) =
let headerDecl = "extern NIM_CONST $1 $2;$n" % let headerDecl = "extern NIM_CONST $1 $2;$n" %
[getTypeDesc(m, sym.loc.t), sym.loc.r] [getTypeDesc(m, sym.loc.t), sym.loc.r]
add(m.s[cfsData], headerDecl) add(m.s[cfsData], headerDecl)
if sfExportc in sym.flags and generatedHeader != nil: if sfExportc in sym.flags and p.module.g.generatedHeader != nil:
add(generatedHeader.s[cfsData], headerDecl) add(p.module.g.generatedHeader.s[cfsData], headerDecl)
proc isActivated(prc: PSym): bool = prc.typ != nil proc isActivated(prc: PSym): bool = prc.typ != nil
@ -784,11 +777,11 @@ proc genProc(m: BModule, prc: PSym) =
else: else:
genProcNoForward(m, prc) genProcNoForward(m, prc)
if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
generatedHeader != nil and lfNoDecl notin prc.loc.flags: m.g.generatedHeader != nil and lfNoDecl notin prc.loc.flags:
genProcPrototype(generatedHeader, prc) genProcPrototype(m.g.generatedHeader, prc)
if prc.typ.callConv == ccInline: if prc.typ.callConv == ccInline:
if not containsOrIncl(generatedHeader.declaredThings, prc.id): if not containsOrIncl(m.g.generatedHeader.declaredThings, prc.id):
genProcAux(generatedHeader, prc) genProcAux(m.g.generatedHeader, prc)
proc genVarPrototypeAux(m: BModule, sym: PSym) = proc genVarPrototypeAux(m: BModule, sym: PSym) =
#assert(sfGlobal in sym.flags) #assert(sfGlobal in sym.flags)
@ -946,23 +939,24 @@ proc genMainProc(m: BModule) =
else: else:
nimMain = PosixNimMain nimMain = PosixNimMain
otherMain = PosixCMain otherMain = PosixCMain
if gBreakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint") if m.g.breakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
if optEndb in gOptions: if optEndb in gOptions:
gBreakpoints.add(m.genFilenames) m.g.breakpoints.add(m.genFilenames)
let initStackBottomCall = let initStackBottomCall =
if platform.targetOS == osStandalone or gSelectedGC == gcNone: "".rope if platform.targetOS == osStandalone or gSelectedGC == gcNone: "".rope
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N") else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
inc(m.labels) inc(m.labels)
appcg(m, m.s[cfsProcs], PreMainBody, [ appcg(m, m.s[cfsProcs], PreMainBody, [
mainDatInit, gBreakpoints, otherModsInit, m.g.mainDatInit, m.g.breakpoints, m.g.otherModsInit,
if emulatedThreadVars() and platform.targetOS != osStandalone: if emulatedThreadVars() and platform.targetOS != osStandalone:
ropecg(m, "\t#initThreadVarsEmulation();$N") ropecg(m, "\t#initThreadVarsEmulation();$N")
else: else:
"".rope, "".rope,
initStackBottomCall]) initStackBottomCall])
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, initStackBottomCall, rope(m.labels)]) appcg(m, m.s[cfsProcs], nimMain,
[m.g.mainModInit, initStackBottomCall, rope(m.labels)])
if optNoMain notin gGlobalOptions: if optNoMain notin gGlobalOptions:
appcg(m, m.s[cfsProcs], otherMain, []) appcg(m, m.s[cfsProcs], otherMain, [])
@ -984,19 +978,19 @@ proc getInitName(m: PSym): Rope =
proc getDatInitName(m: PSym): Rope = getSomeInitName(m, "DatInit000") proc getDatInitName(m: PSym): Rope = getSomeInitName(m, "DatInit000")
proc registerModuleToMain(m: PSym) = proc registerModuleToMain(g: BModuleList; m: PSym) =
var var
init = m.getInitName init = m.getInitName
datInit = m.getDatInitName datInit = m.getDatInitName
addf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init]) addf(g.mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init])
addf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit]) addf(g.mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit])
if sfSystemModule notin m.flags: if sfSystemModule notin m.flags:
addf(mainDatInit, "\t$1();$N", [datInit]) addf(g.mainDatInit, "\t$1();$N", [datInit])
let initCall = "\t$1();$N" % [init] let initCall = "\t$1();$N" % [init]
if sfMainModule in m.flags: if sfMainModule in m.flags:
add(mainModInit, initCall) add(g.mainModInit, initCall)
else: else:
add(otherModsInit, initCall) add(g.otherModsInit, initCall)
proc genInitCode(m: BModule) = proc genInitCode(m: BModule) =
var initname = getInitName(m.module) var initname = getInitName(m.module)
@ -1087,7 +1081,7 @@ proc newPostInitProc(m: BModule): BProc =
proc initProcOptions(m: BModule): TOptions = proc initProcOptions(m: BModule): TOptions =
if sfSystemModule in m.module.flags: gOptions-{optStackTrace} else: gOptions if sfSystemModule in m.module.flags: gOptions-{optStackTrace} else: gOptions
proc rawNewModule(module: PSym, filename: string): BModule = proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
new(result) new(result)
result.tmpBase = rope("T" & $hashOwner(module) & "_") result.tmpBase = rope("T" & $hashOwner(module) & "_")
initLinkedList(result.headerFiles) initLinkedList(result.headerFiles)
@ -1109,6 +1103,7 @@ proc rawNewModule(module: PSym, filename: string): BModule =
result.forwardedProcs = @[] result.forwardedProcs = @[]
result.typeNodesName = getTempName(result) result.typeNodesName = getTempName(result)
result.nimTypesName = getTempName(result) result.nimTypesName = getTempName(result)
result.g = g
# no line tracing for the init sections of the system module so that we # no line tracing for the init sections of the system module so that we
# don't generate a TFrame which can confuse the stack botton initialization: # don't generate a TFrame which can confuse the stack botton initialization:
if sfSystemModule in module.flags: if sfSystemModule in module.flags:
@ -1147,6 +1142,7 @@ proc resetModule*(m: BModule) =
# indicate that this is now cached module # indicate that this is now cached module
# the cache will be invalidated by nullifying gModules # the cache will be invalidated by nullifying gModules
m.fromCache = true m.fromCache = true
m.g = nil
# we keep only the "merge info" information for the module # we keep only the "merge info" information for the module
# and the properties that can't change: # and the properties that can't change:
@ -1160,31 +1156,35 @@ proc resetModule*(m: BModule) =
# m.labels # m.labels
# m.FrameDeclared # m.FrameDeclared
proc resetCgenModules* = proc resetCgenModules*(g: BModuleList) =
for m in cgenModules(): resetModule(m) for m in cgenModules(g): resetModule(m)
proc rawNewModule(module: PSym): BModule = proc rawNewModule(g: BModuleList; module: PSym): BModule =
result = rawNewModule(module, module.position.int32.toFullPath) result = rawNewModule(g, module, module.position.int32.toFullPath)
proc newModule(module: PSym): BModule = proc newModule(g: BModuleList; module: PSym): BModule =
# we should create only one cgen module for each module sym # we should create only one cgen module for each module sym
internalAssert getCgenModule(module) == nil result = rawNewModule(g, module)
growCache g.modules, module.position
result = rawNewModule(module) g.modules[module.position] = result
growCache gModules, module.position
gModules[module.position] = result
if (optDeadCodeElim in gGlobalOptions): if (optDeadCodeElim in gGlobalOptions):
if (sfDeadCodeElim in module.flags): if (sfDeadCodeElim in module.flags):
internalError("added pending module twice: " & module.filename) internalError("added pending module twice: " & module.filename)
template injectG() {.dirty.} =
if graph.backend == nil:
graph.backend = newModuleList()
let g = BModuleList(graph.backend)
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
result = newModule(module) injectG()
if optGenIndex in gGlobalOptions and generatedHeader == nil: result = newModule(g, module)
if optGenIndex in gGlobalOptions and g.generatedHeader == nil:
let f = if headerFile.len > 0: headerFile else: gProjectFull let f = if headerFile.len > 0: headerFile else: gProjectFull
generatedHeader = rawNewModule(module, g.generatedHeader = rawNewModule(g, module,
changeFileExt(completeCFilePath(f), hExt)) changeFileExt(completeCFilePath(f), hExt))
incl generatedHeader.flags, isHeaderFile incl g.generatedHeader.flags, isHeaderFile
proc writeHeader(m: BModule) = proc writeHeader(m: BModule) =
var result = getCopyright(m.filename) var result = getCopyright(m.filename)
@ -1214,8 +1214,9 @@ proc getCFile(m: BModule): string =
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext) result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext)
proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext = proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
injectG()
assert optSymbolFiles in gGlobalOptions assert optSymbolFiles in gGlobalOptions
var m = newModule(module) var m = newModule(g, module)
readMergeInfo(getCFile(m), m) readMergeInfo(getCFile(m), m)
result = m result = m
@ -1236,8 +1237,8 @@ proc finishModule(m: BModule) =
internalError(prc.info, "still forwarded: " & prc.name.s) internalError(prc.info, "still forwarded: " & prc.name.s)
genProcNoForward(m, prc) genProcNoForward(m, prc)
inc(i) inc(i)
assert(gForwardedProcsCounter >= i) assert(m.g.forwardedProcsCounter >= i)
dec(gForwardedProcsCounter, i) dec(m.g.forwardedProcsCounter, i)
setLen(m.forwardedProcs, 0) setLen(m.forwardedProcs, 0)
proc shouldRecompile(code: Rope, cfile: string): bool = proc shouldRecompile(code: Rope, cfile: string): bool =
@ -1265,7 +1266,7 @@ proc writeModule(m: BModule, pending: bool) =
finishTypeDescriptions(m) finishTypeDescriptions(m)
if sfMainModule in m.module.flags: if sfMainModule in m.module.flags:
# generate main file: # generate main file:
add(m.s[cfsProcHeaders], mainModProcs) add(m.s[cfsProcHeaders], m.g.mainModProcs)
generateThreadVarsSize(m) generateThreadVarsSize(m)
var code = genModule(m, cfile) var code = genModule(m, cfile)
@ -1313,7 +1314,7 @@ proc myClose(b: PPassContext, n: PNode): PNode =
m.initProc.options = initProcOptions(m) m.initProc.options = initProcOptions(m)
genStmts(m.initProc, n) genStmts(m.initProc, n)
# cached modules need to registered too: # cached modules need to registered too:
registerModuleToMain(m.module) registerModuleToMain(m.g, m.module)
if sfMainModule in m.module.flags: if sfMainModule in m.module.flags:
incl m.flags, objHasKidsValid incl m.flags, objHasKidsValid
@ -1321,21 +1322,22 @@ proc myClose(b: PPassContext, n: PNode): PNode =
for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym) for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)
genMainProc(m) genMainProc(m)
proc cgenWriteModules* = proc cgenWriteModules*(backend: RootRef) =
let g = BModuleList(backend)
# we need to process the transitive closure because recursive module # we need to process the transitive closure because recursive module
# deps are allowed (and the system module is processed in the wrong # deps are allowed (and the system module is processed in the wrong
# order anyway) # order anyway)
if generatedHeader != nil: finishModule(generatedHeader) if g.generatedHeader != nil: finishModule(g.generatedHeader)
while gForwardedProcsCounter > 0: while g.forwardedProcsCounter > 0:
for m in cgenModules(): for m in cgenModules(g):
if not m.fromCache: if not m.fromCache:
finishModule(m) finishModule(m)
for m in cgenModules(): for m in cgenModules(g):
if m.fromCache: if m.fromCache:
m.updateCachedModule m.updateCachedModule
else: else:
m.writeModule(pending=true) m.writeModule(pending=true)
writeMapping(gMapping) writeMapping(g.mapping)
if generatedHeader != nil: writeHeader(generatedHeader) if g.generatedHeader != nil: writeHeader(g.generatedHeader)
const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose) const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)

View file

@ -104,6 +104,17 @@ type
isHeaderFile, # C source file is the header file isHeaderFile, # C source file is the header file
includesStringh, # C source file already includes ``<string.h>`` includesStringh, # C source file already includes ``<string.h>``
objHasKidsValid # whether we can rely on tfObjHasKids objHasKidsValid # whether we can rely on tfObjHasKids
BModuleList* = ref object of RootObj
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
mapping*: Rope # the generated mapping file (if requested)
modules*: seq[BModule] # list of all compiled modules
forwardedProcsCounter*: int
generatedHeader*: BModule
breakPointId*: int
breakpoints*: Rope # later the breakpoints are inserted into the main proc
TCGen = object of TPassContext # represents a C source file TCGen = object of TPassContext # represents a C source file
s*: TCFileSections # sections of the C file s*: TCFileSections # sections of the C file
flags*: set[Codegenflag] flags*: set[Codegenflag]
@ -131,13 +142,7 @@ type
# OpenGL wrapper # OpenGL wrapper
injectStmt*: Rope injectStmt*: Rope
sigConflicts*: CountTable[SigHash] sigConflicts*: CountTable[SigHash]
g*: BModuleList
var
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
# varuious parts of the main module
gMapping*: Rope # the generated mapping file (if requested)
gModules*: seq[BModule] = @[] # list of all compiled modules
gForwardedProcsCounter*: int = 0
proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} = proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
# section in the current block # section in the current block
@ -147,10 +152,6 @@ proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
# top level proc sections # top level proc sections
result = p.blocks[0].sections[s] result = p.blocks[0].sections[s]
proc bmod*(module: PSym): BModule =
# obtains the BModule for a given module PSym
result = gModules[module.position]
proc newProc*(prc: PSym, module: BModule): BProc = proc newProc*(prc: PSym, module: BModule): BProc =
new(result) new(result)
result.prc = prc result.prc = prc
@ -161,10 +162,11 @@ proc newProc*(prc: PSym, module: BModule): BProc =
result.nestedTryStmts = @[] result.nestedTryStmts = @[]
result.finallySafePoints = @[] result.finallySafePoints = @[]
iterator cgenModules*: BModule = proc newModuleList*(): BModuleList = BModuleList(modules: @[])
for i in 0..high(gModules):
iterator cgenModules*(g: BModuleList): BModule =
for i in 0..high(g.modules):
# ultimately, we are iterating over the file ids here. # ultimately, we are iterating over the file ids here.
# some "files" won't have an associated cgen module (like stdin) # some "files" won't have an associated cgen module (like stdin)
# and we must skip over them. # and we must skip over them.
if gModules[i] != nil: yield gModules[i] if g.modules[i] != nil: yield g.modules[i]

View file

@ -64,7 +64,7 @@ proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
#registerPass(cleanupPass()) #registerPass(cleanupPass())
compileProject(graph, cache) compileProject(graph, cache)
cgenWriteModules() cgenWriteModules(graph.backend)
if gCmd != cmdRun: if gCmd != cmdRun:
extccomp.callCCompiler(changeFileExt(gProjectFull, "")) extccomp.callCCompiler(changeFileExt(gProjectFull, ""))

View file

@ -38,6 +38,7 @@ type
# first module that included it # first module that included it
importStack*: seq[int32] # The current import stack. Used for detecting recursive importStack*: seq[int32] # The current import stack. Used for detecting recursive
# module dependencies. # module dependencies.
backend*: RootRef # minor hack so that a backend can extend this easily
{.this: g.} {.this: g.}