From b64eeeb4303953f9fe1135cb9c3c61e23ec55afa Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 8 Sep 2012 15:43:21 +0200 Subject: term rewriting improvements --- compiler/hlo.nim | 91 ++++++++++++++++++++++++++++++++++++++++++++++ compiler/parampatterns.nim | 59 ++++++++++++++++++++++++++++-- compiler/patterns.nim | 84 +++++++++++++++++++++++++++++------------- compiler/sem.nim | 51 +------------------------- compiler/semexprs.nim | 45 +---------------------- compiler/seminst.nim | 1 + compiler/semstmts.nim | 8 ++-- compiler/semtempl.nim | 22 ++++++++--- compiler/semtypes.nim | 13 ++++--- 9 files changed, 238 insertions(+), 136 deletions(-) create mode 100644 compiler/hlo.nim (limited to 'compiler') diff --git a/compiler/hlo.nim b/compiler/hlo.nim new file mode 100644 index 000000000..152fd4414 --- /dev/null +++ b/compiler/hlo.nim @@ -0,0 +1,91 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# This include implements the high level optimization pass. + +proc hlo(c: PContext, n: PNode): PNode + +proc evalPattern(c: PContext, n, orig: PNode): PNode = + InternalAssert n.kind == nkCall and n.sons[0].kind == nkSym + # we need to ensure that the resulting AST is semchecked. However, it's + # aweful to semcheck before macro invocation, so we don't and treat + # templates and macros as immediate in this context. + var rule: string + if optHints in gOptions and hintPattern in gNotes: + rule = renderTree(n, {renderNoComments}) + let s = n.sons[0].sym + case s.kind + of skMacro: + result = semMacroExpr(c, n, orig, s) + of skTemplate: + result = semTemplateExpr(c, n, s) + else: + result = semDirectOp(c, n, {}) + if optHints in gOptions and hintPattern in gNotes: + Message(orig.info, hintPattern, rule & " --> '" & + renderTree(result, {renderNoComments}) & "'") + # check the resulting AST for optimization rules again: + result = hlo(c, result) + +proc applyPatterns(c: PContext, n: PNode): PNode = + result = n + # we apply the last pattern first, so that pattern overriding is possible; + # however the resulting AST would better not trigger the old rule then + # anymore ;-) + for i in countdown( 100: + GlobalError(n.info, errTemplateInstantiationTooNested) + # deactivate this pattern: + c.patterns[i] = nil + if x.kind == nkStmtList: + assert x.len == 3 + x.sons[1] = evalPattern(c, x.sons[1], result) + result = flattenStmts(x) + else: + result = evalPattern(c, x, result) + dec(evalTemplateCounter) + # activate this pattern again: + c.patterns[i] = pattern + +proc hlo(c: PContext, n: PNode): PNode = + case n.kind + of nkMacroDef, nkTemplateDef, procDefs: + # already processed (special cases in semstmts.nim) + result = n + else: + result = applyPatterns(c, n) + if result == n: + # no optimization applied, try subtrees: + for i in 0 .. < safeLen(result): + let a = result.sons[i] + let h = hlo(c, a) + if h != a: result.sons[i] = h + else: + # perform type checking, so that the replacement still fits: + if n.typ == nil and (result.typ == nil or + result.typ.kind in {tyStmt, tyEmpty}): + nil + else: + result = fitNode(c, n.typ, result) + +proc hloBody(c: PContext, n: PNode): PNode = + # fast exit: + if c.patterns.len == 0 or optPatterns notin gOptions: return n + result = hlo(c, n) + +proc hloStmt(c: PContext, n: PNode): PNode = + # fast exit: + if c.patterns.len == 0 or optPatterns notin gOptions: return n + result = hlo(c, n) diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 44e41f7a0..ee1f69818 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -18,7 +18,7 @@ import strutils, ast, astalgo, types, msgs, idents, renderer, wordrecg type TAliasRequest* = enum # first byte of the bytecode determines alias checking aqNone = 1, # no alias analysis requested - aqShouldAlias, # with what? + aqShouldAlias, # with some other param aqNoAlias # request noalias TOpcode = enum ppEof = 1, # end of compiled pattern @@ -32,6 +32,8 @@ type ppCall, ppSymKind, ppNodeKind, + ppLValue, + ppLocal, ppSideEffect, ppNoSideEffect TPatternCode = string @@ -87,6 +89,8 @@ proc compileConstraints(p: PNode, result: var TPatternCode) = of "call": result.add(ppCall) of "alias": result[0] = chr(aqShouldAlias.ord) of "noalias": result[0] = chr(aqNoAlias.ord) + of "lvalue": result.add(ppLValue) + of "local": result.add(ppLocal) of "sideeffect": result.add(ppSideEffect) of "nosideeffect": result.add(ppNoSideEffect) else: @@ -144,8 +148,8 @@ proc checkForSideEffects(n: PNode): TSideEffectAnalysis = # indirect call without side effects: result = seNoSideEffect else: - # indirect call: we don't know - result = seUnknown + # indirect call: assume side effect: + return seSideEffect # we need to check n[0] too: (FwithSideEffectButReturnsProcWithout)(args) for i in 0 ..