From cd292568d775d55d9abb51e962882ecda12c03a9 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 12 Apr 2011 01:13:42 +0200 Subject: big repo cleanup --- compiler/passes.nim | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100755 compiler/passes.nim (limited to 'compiler/passes.nim') diff --git a/compiler/passes.nim b/compiler/passes.nim new file mode 100755 index 000000000..b380cd66f --- /dev/null +++ b/compiler/passes.nim @@ -0,0 +1,155 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2011 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# This module implements the passes functionality. A pass must implement the +# `TPass` interface. + +import + strutils, lists, options, ast, astalgo, llstream, msgs, platform, os, + condsyms, idents, rnimsyn, types, extccomp, math, magicsys, nversion, nimsets, + syntaxes, times, rodread + +type + TPassContext* = object of TObject # the pass's context + PPassContext* = ref TPassContext + TPass* = tuple[ + open: proc (module: PSym, filename: string): PPassContext, + openCached: proc (module: PSym, filename: string, + rd: PRodReader): PPassContext, + close: proc (p: PPassContext, n: PNode): PNode, + process: proc (p: PPassContext, topLevelStmt: PNode): PNode] + +# a pass is a tuple of procedure vars ``TPass.close`` may produce additional +# nodes. These are passed to the other close procedures. +# This mechanism used to be used for the instantiation of generics. + +proc registerPass*(p: TPass) +proc initPass*(p: var TPass) + # This implements a memory preserving scheme: Top level statements are + # processed in a pipeline. The compiler never looks at a whole module + # any longer. However, this is simple to change, as new passes may perform + # whole program optimizations. For now, we avoid it to save a lot of memory. +proc processModule*(module: PSym, filename: string, stream: PLLStream, + rd: PRodReader) + +# the semantic checker needs these: +var + gImportModule*: proc (filename: string): PSym + gIncludeFile*: proc (filename: string): PNode + +# implementation + +proc skipCodegen*(n: PNode): bool {.inline.} = + # can be used by codegen passes to determine whether they should do + # something with `n`. Currently, this ignores `n` and uses the global + # error count instead. + result = msgs.gErrorCounter > 0 + +proc astNeeded*(s: PSym): bool = + # The ``rodwrite`` module uses this to determine if the body of a proc + # needs to be stored. The passes manager frees s.sons[codePos] when + # appropriate to free the procedure body's memory. This is important + # to keep memory usage down. + if (s.kind in {skMethod, skProc}) and + ({sfCompilerProc, sfCompileTime} * s.flags == {}) and + (s.typ.callConv != ccInline) and + (s.ast.sons[genericParamsPos].kind == nkEmpty): + result = false + else: + result = true + +const + maxPasses = 10 + +type + TPassContextArray = array[0..maxPasses - 1, PPassContext] + +var + gPasses: array[0..maxPasses - 1, TPass] + gPassesLen: int + +proc registerPass(p: TPass) = + gPasses[gPassesLen] = p + inc(gPassesLen) + +proc openPasses(a: var TPassContextArray, module: PSym, filename: string) = + for i in countup(0, gPassesLen - 1): + if not isNil(gPasses[i].open): a[i] = gPasses[i].open(module, filename) + else: a[i] = nil + +proc openPassesCached(a: var TPassContextArray, module: PSym, filename: string, + rd: PRodReader) = + for i in countup(0, gPassesLen - 1): + if not isNil(gPasses[i].openCached): + a[i] = gPasses[i].openCached(module, filename, rd) + else: + a[i] = nil + +proc closePasses(a: var TPassContextArray) = + var m: PNode = nil + for i in countup(0, gPassesLen - 1): + if not isNil(gPasses[i].close): m = gPasses[i].close(a[i], m) + a[i] = nil # free the memory here + +proc processTopLevelStmt(n: PNode, a: var TPassContextArray) = + # this implements the code transformation pipeline + var m = n + for i in countup(0, gPassesLen - 1): + if not isNil(gPasses[i].process): m = gPasses[i].process(a[i], m) + +proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) = + # this implements the code transformation pipeline + var m = n + for i in countup(0, gPassesLen - 1): + if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m) + +proc closePassesCached(a: var TPassContextArray) = + var m = ast.emptyNode + for i in countup(0, gPassesLen - 1): + if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close): + m = gPasses[i].close(a[i], m) + a[i] = nil # free the memory here + +proc processModule(module: PSym, filename: string, stream: PLLStream, + rd: PRodReader) = + var + p: TParsers + a: TPassContextArray + s: PLLStream + if rd == nil: + openPasses(a, module, filename) + if stream == nil: + s = LLStreamOpen(filename, fmRead) + if s == nil: + rawMessage(errCannotOpenFile, filename) + return + else: + s = stream + while true: + openParsers(p, filename, s) + while true: + var n = parseTopLevelStmt(p) + if n.kind == nkEmpty: break + processTopLevelStmt(n, a) + closeParsers(p) + if s.kind != llsStdIn: break + closePasses(a) + # id synchronization point for more consistent code generation: + IDsynchronizationPoint(1000) + else: + openPassesCached(a, module, filename, rd) + var n = loadInitSection(rd) #MessageOut('init section' + renderTree(n)); + for i in countup(0, sonsLen(n) - 1): processTopLevelStmtCached(n.sons[i], a) + closePassesCached(a) + +proc initPass(p: var TPass) = + p.open = nil + p.openCached = nil + p.close = nil + p.process = nil -- cgit 1.4.1-2-gfad0