diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2008-12-12 14:02:27 +0100 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2008-12-12 14:02:27 +0100 |
commit | ddaedab835fa7ea3457f21a772d636921defdc46 (patch) | |
tree | 8f96b5a3a6700704e0a64bdcdedee1d2caf68517 /nim/passes.pas | |
parent | 2cd136cf7a0210e3cfde7a6f8ba32c9f09560047 (diff) | |
download | Nim-ddaedab835fa7ea3457f21a772d636921defdc46.tar.gz |
version 0.7.2
Diffstat (limited to 'nim/passes.pas')
-rw-r--r-- | nim/passes.pas | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/nim/passes.pas b/nim/passes.pas new file mode 100644 index 000000000..028cfc2a2 --- /dev/null +++ b/nim/passes.pas @@ -0,0 +1,216 @@ +// +// +// The Nimrod Compiler +// (c) Copyright 2008 Andreas Rumpf +// +// See the file "copying.txt", included in this +// distribution, for details about the copyright. +// +unit passes; + +// This module implements the passes functionality. A pass must implement the +// `TPass` interface. + +interface + +{$include 'config.inc'} + +uses + nsystem, charsets, strutils, + lists, options, ast, astalgo, llstream, + msgs, platform, nos, condsyms, idents, rnimsyn, types, + extccomp, nmath, magicsys, nversion, nimsets, pnimsyn, ntime, rodread; + +type + TPassContext = object(NObject) // the pass's context + end; + PPassContext = ^TPassContext; + + TPass = record {@tuple} // a pass is a tuple of procedure vars + open: function (module: PSym; const filename: string): PPassContext; + openCached: function (module: PSym; const filename: string; + rd: PRodReader): PPassContext; + close: function (p: PPassContext; n: PNode): PNode; + process: function (p: PPassContext; topLevelStmt: PNode): PNode; + end; + +// ``TPass.close`` may produce additional nodes. These are passed to the other +// close procedures. This mechanism is needed for the instantiation of +// generics. + +procedure registerPass(const p: TPass); + +procedure initPass(var p: 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. + +procedure processModule(module: PSym; const filename: string; + stream: PLLStream; rd: PRodReader); + + +function 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. + +// some passes (the semantic checker) need these: +var + gImportModule: function (const filename: string): PSym; + gIncludeFile: function (const filename: string): PNode; + gIncludeTmplFile: function (const filename: string): PNode; + +implementation + +function astNeeded(s: PSym): bool; +begin + if (s.kind = skProc) + and ([sfCompilerProc, sfCompileTime] * s.flags = []) + and (s.typ.callConv <> ccInline) + and (s.ast.sons[genericParamsPos] = nil) then + result := false + else + result := true +end; + +const + maxPasses = 10; + +type + TPassContextArray = array [0..maxPasses-1] of PPassContext; +var + gPasses: array [0..maxPasses-1] of TPass; + gPassesLen: int; + +procedure registerPass(const p: TPass); +begin + gPasses[gPassesLen] := p; + inc(gPassesLen); +end; + +procedure openPasses(var a: TPassContextArray; module: PSym; + const filename: string); +var + i: int; +begin + for i := 0 to gPassesLen-1 do + if assigned(gPasses[i].open) then + a[i] := gPasses[i].open(module, filename) + else + a[i] := nil +end; + +procedure openPassesCached(var a: TPassContextArray; module: PSym; + const filename: string; rd: PRodReader); +var + i: int; +begin + for i := 0 to gPassesLen-1 do + if assigned(gPasses[i].openCached) then + a[i] := gPasses[i].openCached(module, filename, rd) + else + a[i] := nil +end; + +procedure closePasses(var a: TPassContextArray); +var + i: int; + m: PNode; +begin + m := nil; + for i := 0 to gPassesLen-1 do begin + if assigned(gPasses[i].close) then m := gPasses[i].close(a[i], m); + a[i] := nil; // free the memory here + end +end; + +procedure processTopLevelStmt(n: PNode; var a: TPassContextArray); +var + i: int; + m: PNode; +begin + // this implements the code transformation pipeline + m := n; + for i := 0 to gPassesLen-1 do + if assigned(gPasses[i].process) then m := gPasses[i].process(a[i], m); +end; + +procedure processTopLevelStmtCached(n: PNode; var a: TPassContextArray); +var + i: int; + m: PNode; +begin + // this implements the code transformation pipeline + m := n; + for i := 0 to gPassesLen-1 do + if assigned(gPasses[i].openCached) then m := gPasses[i].process(a[i], m); +end; + +procedure closePassesCached(var a: TPassContextArray); +var + i: int; + m: PNode; +begin + m := nil; + for i := 0 to gPassesLen-1 do begin + if assigned(gPasses[i].openCached) and assigned(gPasses[i].close) then + m := gPasses[i].close(a[i], m); + a[i] := nil; // free the memory here + end +end; + +procedure processModule(module: PSym; const filename: string; + stream: PLLStream; rd: PRodReader); +var + p: TParser; + n: PNode; + a: TPassContextArray; + s: PLLStream; + i: int; +begin + if rd = nil then begin + openPasses(a, module, filename); + if stream = nil then begin + s := LLStreamOpen(filename, fmRead); + if s = nil then begin + rawMessage(errCannotOpenFile, filename); + exit + end; + end + else + s := stream; + while true do begin + openParser(p, filename, s); + while true do begin + n := parseTopLevelStmt(p); + if n = nil then break; + processTopLevelStmt(n, a) + end; + closeParser(p); + if s.kind <> llsStdIn then break; + end; + closePasses(a); + // id synchronization point for more consistent code generation: + IDsynchronizationPoint(1000); + end + else begin + openPassesCached(a, module, filename, rd); + n := loadInitSection(rd); + //MessageOut('init section' + renderTree(n)); + for i := 0 to sonsLen(n)-1 do processTopLevelStmtCached(n.sons[i], a); + closePassesCached(a); + end; +end; + +procedure initPass(var p: TPass); +begin + p.open := nil; + p.openCached := nil; + p.close := nil; + p.process := nil; +end; + +end. |