diff options
Diffstat (limited to 'compiler/cgen.nim')
-rw-r--r-- | compiler/cgen.nim | 167 |
1 files changed, 73 insertions, 94 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 3040f98da..3545edc88 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -14,11 +14,14 @@ import nversion, nimsets, msgs, std / sha1, bitsets, idents, types, ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth, condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, - lowerings, semparallel, tables, sets, ndi, lineinfos, pathutils + lowerings, tables, sets, ndi, lineinfos, pathutils, transf + +when not defined(leanCompiler): + import semparallel import strutils except `%` # collides with ropes.`%` -from modulegraphs import ModuleGraph +from modulegraphs import ModuleGraph, PPassContext from lineinfos import warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated, errCannotOpenFile import dynlib @@ -42,8 +45,7 @@ when options.hasTinyCBackend: # implementation proc addForwardedProc(m: BModule, prc: PSym) = - m.forwardedProcs.add(prc) - inc(m.g.forwardedProcsCounter) + m.g.forwardedProcs.add(prc) proc findPendingModule(m: BModule, s: PSym): BModule = var ms = getModule(s) @@ -292,10 +294,10 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, type TAssignmentFlag = enum - needToCopy, afDestIsNil, afDestIsNotNil, afSrcIsNil, afSrcIsNotNil + needToCopy TAssignmentFlags = set[TAssignmentFlag] -proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) +proc genRefAssign(p: BProc, dest, src: TLoc) proc isComplexValueType(t: PType): bool {.inline.} = let t = t.skipTypes(abstractInst + tyUserTypeClasses) @@ -311,7 +313,7 @@ proc resetLoc(p: BProc, loc: var TLoc) = var nilLoc: TLoc initLoc(nilLoc, locTemp, loc.lode, OnStack) nilLoc.r = rope("NIM_NIL") - genRefAssign(p, loc, nilLoc, {afSrcIsNil}) + genRefAssign(p, loc, nilLoc) else: linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc)) else: @@ -444,20 +446,21 @@ proc assignGlobalVar(p: BProc, n: PNode) = return useHeader(p.module, s) if lfNoDecl in s.loc.flags: return - if sfThread in s.flags: - declareThreadVar(p.module, s, sfImportc in s.flags) - else: - var decl: Rope = nil - var td = getTypeDesc(p.module, s.loc.t) - if s.constraint.isNil: - if sfImportc in s.flags: add(decl, "extern ") - add(decl, td) - if sfRegister in s.flags: add(decl, " register") - if sfVolatile in s.flags: add(decl, " volatile") - addf(decl, " $1;$n", [s.loc.r]) + if not containsOrIncl(p.module.declaredThings, s.id): + if sfThread in s.flags: + declareThreadVar(p.module, s, sfImportc in s.flags) else: - decl = (s.cgDeclFrmt & ";$n") % [td, s.loc.r] - add(p.module.s[cfsVars], decl) + var decl: Rope = nil + var td = getTypeDesc(p.module, s.loc.t) + if s.constraint.isNil: + if sfImportc in s.flags: add(decl, "extern ") + add(decl, td) + if sfRegister in s.flags: add(decl, " register") + if sfVolatile in s.flags: add(decl, " volatile") + addf(decl, " $1;$n", [s.loc.r]) + else: + decl = (s.cgDeclFrmt & ";$n") % [td, s.loc.r] + add(p.module.s[cfsVars], decl) if p.withinLoop > 0: # fixes tests/run/tzeroarray: resetLoc(p, s.loc) @@ -567,7 +570,12 @@ proc loadDynamicLib(m: BModule, lib: PLib) = var p = newProc(nil, m) p.options = p.options - {optStackTrace, optEndb} var dest: TLoc - initLocExpr(p, lib.path, dest) + initLoc(dest, locTemp, lib.path, OnStack) + dest.r = getTempName(m) + appcg(m, m.s[cfsDynLibInit],"$1 $2;$n", + [getTypeDesc(m, lib.path.typ), rdLoc(dest)]) + expr(p, lib.path, dest) + add(m.s[cfsVars], p.s(cpsLocals)) add(m.s[cfsDynLibInit], p.s(cpsInit)) add(m.s[cfsDynLibInit], p.s(cpsStmts)) @@ -697,8 +705,12 @@ proc closureSetup(p: BProc, prc: PSym) = #echo "created environment: ", env.id, " for ", prc.name.s assignLocalVar(p, ls) # generate cast assignment: - linefmt(p, cpsStmts, "$1 = ($2) ClE_0;$n", - rdLoc(env.loc), getTypeDesc(p.module, env.typ)) + if p.config.selectedGC == gcGo: + linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, ($2) ClE_0);$n", + addrLoc(p.config, env.loc), getTypeDesc(p.module, env.typ)) + else: + linefmt(p, cpsStmts, "$1 = ($2) ClE_0;$n", + rdLoc(env.loc), getTypeDesc(p.module, env.typ)) proc containsResult(n: PNode): bool = if n.kind == nkSym and n.sym.kind == skResult: @@ -766,7 +778,13 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum = result = InitRequired of nkReturnStmt: if n.len > 0: - result = allPathsAsgnResult(n[0]) + if n[0].kind == nkEmpty and result != InitSkippable: + # This is a bare `return` statement, if `result` was not initialized + # anywhere else (or if we're not sure about this) let's require it to be + # initialized. This avoids cases like #9286 where this heuristic lead to + # wrong code being generated. + result = InitRequired + else: result = allPathsAsgnResult(n[0]) of nkIfStmt, nkIfExpr: var exhaustive = false result = InitSkippable @@ -830,6 +848,8 @@ proc genProcAux(m: BModule, prc: PSym) = var header = genProcHeader(m, prc) var returnStmt: Rope = nil assert(prc.ast != nil) + let procBody = transformBody(m.g.graph, prc, cache = false) + if sfPure notin prc.flags and prc.typ.sons[0] != nil: if resultPos >= prc.ast.len: internalError(m.config, prc.info, "proc has no result symbol") @@ -837,7 +857,7 @@ proc genProcAux(m: BModule, prc: PSym) = let res = resNode.sym # get result symbol if not isInvalidReturnType(m.config, prc.typ.sons[0]): if sfNoInit in prc.flags: incl(res.flags, sfNoInit) - if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(prc.getBody); val != nil): + if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil): var decl = localVarDecl(p, resNode) var a: TLoc initLocExprSingleUse(p, val, a) @@ -858,7 +878,7 @@ proc genProcAux(m: BModule, prc: PSym) = # global is either 'nil' or points to valid memory and so the RC operation # succeeds without touching not-initialized memory. if sfNoInit in prc.flags: discard - elif allPathsAsgnResult(prc.getBody) == InitSkippable: discard + elif allPathsAsgnResult(procBody) == InitSkippable: discard else: resetLoc(p, res.loc) if skipTypes(res.typ, abstractInst).kind == tyArray: @@ -870,7 +890,7 @@ proc genProcAux(m: BModule, prc: PSym) = if param.typ.isCompileTimeOnly: continue assignParam(p, param) closureSetup(p, prc) - genStmts(p, prc.getBody) # modifies p.locals, p.init, etc. + genStmts(p, procBody) # modifies p.locals, p.init, etc. var generatedProc: Rope if sfNoReturn in prc.flags: if hasDeclspec in extccomp.CC[p.config.cCompiler].props: @@ -1019,7 +1039,7 @@ proc genVarPrototype(m: BModule, n: PNode) = let sym = n.sym useHeader(m, sym) fillLoc(sym.loc, locGlobalVar, n, mangleName(m, sym), OnHeap) - if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id): + if (lfNoDecl in sym.loc.flags) or contains(m.declaredThings, sym.id): return if sym.owner.id != m.module.id: # else we already have the symbol generated! @@ -1038,7 +1058,7 @@ proc addIntTypes(result: var Rope; conf: ConfigRef) {.inline.} = addf(result, "#define NIM_NEW_MANGLING_RULES\L" & "#define NIM_INTBITS $1\L", [ platform.CPU[conf.target.targetCPU].intSize.rope]) - if conf.cppCustomNamespace.len > 0: + if conf.cppCustomNamespace.len > 0: result.add("#define USE_NIM_NAMESPACE ") result.add(conf.cppCustomNamespace) result.add("\L") @@ -1373,7 +1393,6 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule result.preInitProc = newPreInitProc(result) initNodeTable(result.dataCache) result.typeStack = @[] - result.forwardedProcs = @[] result.typeNodesName = getTempName(result) result.nimTypesName = getTempName(result) # no line tracing for the init sections of the system module so that we @@ -1389,49 +1408,6 @@ proc nullify[T](arr: var T) = for i in low(arr)..high(arr): arr[i] = Rope(nil) -proc resetModule*(m: BModule) = - # between two compilations in CAAS mode, we can throw - # away all the data that was written to disk - m.headerFiles = @[] - m.declaredProtos = initIntSet() - m.forwTypeCache = initTable[SigHash, Rope]() - m.initProc = newProc(nil, m) - m.initProc.options = initProcOptions(m) - m.preInitProc = newPreInitProc(m) - initNodeTable(m.dataCache) - m.typeStack = @[] - m.forwardedProcs = @[] - m.typeNodesName = getTempName(m) - m.nimTypesName = getTempName(m) - if sfSystemModule in m.module.flags: - incl m.flags, preventStackTrace - else: - excl m.flags, preventStackTrace - nullify m.s - m.typeNodes = 0 - m.nimTypes = 0 - nullify m.extensionLoaders - - # indicate that this is now cached module - # the cache will be invalidated by nullifying gModules - #m.fromCache = true - m.g = nil - - # we keep only the "merge info" information for the module - # and the properties that can't change: - # m.filename - # m.cfilename - # m.isHeaderFile - # m.module ? - # m.typeCache - # m.declaredThings - # m.typeInfoMarker - # m.labels - # m.FrameDeclared - -proc resetCgenModules*(g: BModuleList) = - for m in cgenModules(g): resetModule(m) - proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule = result = rawNewModule(g, module, AbsoluteFile toFullPath(conf, module.position.FileIndex)) @@ -1507,27 +1483,14 @@ proc myProcess(b: PPassContext, n: PNode): PNode = m.initProc.options = initProcOptions(m) #softRnl = if optLineDir in m.config.options: noRnl else: rnl # XXX replicate this logic! - genStmts(m.initProc, n) - -proc finishModule(m: BModule) = - var i = 0 - while i <= high(m.forwardedProcs): - # Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use - # a ``for`` loop here - var prc = m.forwardedProcs[i] - if sfForward in prc.flags: - internalError(m.config, prc.info, "still forwarded: " & prc.name.s) - genProcNoForward(m, prc) - inc(i) - assert(m.g.forwardedProcsCounter >= i) - dec(m.g.forwardedProcsCounter, i) - setLen(m.forwardedProcs, 0) + let tranformed_n = transformStmt(m.g.graph, m.module, n) + genStmts(m.initProc, tranformed_n) proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool = result = true if optForceFullMake notin m.config.globalOptions: if not equalsFile(code, cfile.cname): - if isDefined(m.config, "nimdiff"): + if m.config.symbolFiles == readOnlySf: #isDefined(m.config, "nimdiff"): if fileExists(cfile.cname): copyFile(cfile.cname.string, cfile.cname.string & ".backup") echo "diff ", cfile.cname.string, ".backup ", cfile.cname.string @@ -1618,22 +1581,38 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = registerModuleToMain(m.g, m.module) if sfMainModule in m.module.flags: - if m.g.forwardedProcsCounter == 0: + if m.g.forwardedProcs.len == 0: incl m.flags, objHasKidsValid let disp = generateMethodDispatchers(graph) for x in disp: genProcAux(m, x.sym) genMainProc(m) +proc genForwardedProcs(g: BModuleList) = + # Forward declared proc:s lack bodies when first encountered, so they're given + # a second pass here + # Note: ``genProcNoForward`` may add to ``forwardedProcs`` + while g.forwardedProcs.len > 0: + let + prc = g.forwardedProcs.pop() + ms = getModule(prc) + m = g.modules[ms.position] + if sfForward in prc.flags: + internalError(m.config, prc.info, "still forwarded: " & prc.name.s) + + genProcNoForward(m, prc) + proc cgenWriteModules*(backend: RootRef, config: ConfigRef) = let g = BModuleList(backend) # we need to process the transitive closure because recursive module # deps are allowed (and the system module is processed in the wrong # order anyway) g.config = config - if g.generatedHeader != nil: finishModule(g.generatedHeader) - while g.forwardedProcsCounter > 0: - for m in cgenModules(g): - finishModule(m) + let (outDir, _, _) = splitFile(config.outfile) + if not outDir.isEmpty: + createDir(outDir) + + genForwardedProcs(g) + for m in cgenModules(g): m.writeModule(pending=true) writeMapping(config, g.mapping) |