summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2015-02-06 21:26:40 +0100
committerAraq <rumpf_a@web.de>2015-02-07 10:48:07 +0100
commite84834db79854c6ccc89263ec20d3749b8a87a05 (patch)
tree4232d1e7638c232eded8c6a1f3d82120f272d586 /compiler
parentd020ad097c7f1e8155c6b6e7bafbf7731caaafe8 (diff)
downloadNim-e84834db79854c6ccc89263ec20d3749b8a87a05.tar.gz
lots of C++ codegen improvements
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ccgcalls.nim24
-rw-r--r--compiler/ccgexprs.nim4
-rw-r--r--compiler/ccgstmts.nim23
-rw-r--r--compiler/ccgtypes.nim5
-rw-r--r--compiler/cgen.nim100
-rw-r--r--compiler/cgendata.nim3
-rw-r--r--compiler/transf.nim1
7 files changed, 50 insertions, 110 deletions
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index ad9d18257..5e8bbc335 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -124,8 +124,8 @@ proc genArgStringToCString(p: BProc, n: PNode): PRope {.inline.} =
   var a: TLoc
   initLocExpr(p, n.sons[0], a)
   result = ropef("$1->data", [a.rdLoc])
-  
-proc genArg(p: BProc, n: PNode, param: PSym): PRope =
+
+proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): PRope =
   var a: TLoc
   if n.kind == nkStringToCString:
     result = genArgStringToCString(p, n)
@@ -138,7 +138,15 @@ proc genArg(p: BProc, n: PNode, param: PSym): PRope =
   elif p.module.compileToCpp and param.typ.kind == tyVar and 
       n.kind == nkHiddenAddr:
     initLocExprSingleUse(p, n.sons[0], a)
-    result = rdLoc(a)
+    # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
+    # means '*T'. See posix.nim for lots of examples that do that in the wild.
+    let callee = call.sons[0]
+    if callee.kind == nkSym and
+        {sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and 
+        {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
+      result = addrLoc(a)
+    else:
+      result = rdLoc(a)
   else:
     initLocExprSingleUse(p, n, a)
     result = rdLoc(a)
@@ -166,7 +174,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
     if params != nil: app(params, ~", ")
     if i < sonsLen(typ):
       assert(typ.n.sons[i].kind == nkSym)
-      app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym))
+      app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
     else:
       app(params, genArgNoParam(p, ri.sons[i]))
   fixupCall(p, le, ri, d, op.r, params)
@@ -192,7 +200,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i < sonsLen(typ):
       assert(typ.n.sons[i].kind == nkSym)
-      app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym))
+      app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
     else:
       app(pl, genArgNoParam(p, ri.sons[i]))
     if i < length - 1: app(pl, ~", ")
@@ -424,12 +432,12 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
   assert(sonsLen(typ) == sonsLen(typ.n))
   
   if length > 1:
-    app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym))
+    app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
     app(pl, ~" ")
   app(pl, op.r)
   if length > 2:
     app(pl, ~": ")
-    app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym))
+    app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
   for i in countup(3, length-1):
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i >= sonsLen(typ):
@@ -439,7 +447,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
     app(pl, ~" ")
     app(pl, param.name.s)
     app(pl, ~": ")
-    app(pl, genArg(p, ri.sons[i], param))
+    app(pl, genArg(p, ri.sons[i], param, ri))
   if typ.sons[0] != nil:
     if isInvalidReturnType(typ.sons[0]):
       if sonsLen(ri) > 1: app(pl, ~" ")
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index bd116d6fb..591dd96ec 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -682,7 +682,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
       d.s = OnHeap
     of tyVar:
       d.s = OnUnknown
-      if p.module.compileToCpp:
+      if p.module.compileToCpp and e.kind == nkHiddenDeref:
         putIntoDest(p, d, e.typ, rdLoc(a))
         return
     of tyPtr:
@@ -923,6 +923,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
     L: TLabel
     tmp: TLoc
   getTemp(p, e.typ, tmp)      # force it into a temp!
+  inc p.splitDecls
   expr(p, e.sons[1], tmp)
   L = getLabel(p)
   if m == mOr:
@@ -935,6 +936,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
     d = tmp
   else:
     genAssignment(p, d, tmp, {}) # no need for deep copying
+  dec p.splitDecls
 
 proc genEcho(p: BProc, n: PNode) =
   # this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 5d348c4e4..f5a2c0ef4 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -203,7 +203,7 @@ proc genSingleVar(p: BProc, a: PNode) =
     registerGcRoot(p, v)
   else:
     let imm = isAssignedImmediately(a.sons[2])
-    if imm and p.module.compileToCpp:
+    if imm and p.module.compileToCpp and p.splitDecls == 0:
       # C++ really doesn't like things like 'Foo f; f = x' as that invokes a
       # parameterless constructor followed by an assignment operator. So we
       # generate better code here:
@@ -262,7 +262,7 @@ proc genConstStmt(p: BProc, t: PNode) =
         else: 
           appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", 
                [getTypeDesc(p.module, c.typ), c.loc.r, genConstExpr(p, c.ast)])
-    
+
 proc genIf(p: BProc, n: PNode, d: var TLoc) =
   #
   #  { if (!expr1) goto L1;
@@ -286,17 +286,22 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
     let it = n.sons[i]
     if it.len == 2: 
       when newScopeForIf: startBlock(p)
-      initLocExpr(p, it.sons[0], a)
+      initLocExprSingleUse(p, it.sons[0], a)
       lelse = getLabel(p)
       inc(p.labels)
-      lineFF(p, cpsStmts, "if (!$1) goto $2;$n",
-            "br i1 $1, label %LOC$3, label %$2$nLOC$3: $n",
-            [rdLoc(a), lelse, toRope(p.labels)])
+      lineF(p, cpsStmts, "if (!$1) goto $2;$n",
+            [rdLoc(a), lelse])
       when not newScopeForIf: startBlock(p)
-      expr(p, it.sons[1], d)
+      if p.module.compileToCpp:
+        # avoid "jump to label crosses initialization" error:
+        app(p.s(cpsStmts), "{")
+        expr(p, it.sons[1], d)
+        app(p.s(cpsStmts), "}")
+      else:
+        expr(p, it.sons[1], d)
       endBlock(p)
       if sonsLen(n) > 1:
-        lineFF(p, cpsStmts, "goto $1;$n", "br label %$1$n", [lend])
+        lineF(p, cpsStmts, "goto $1;$n", [lend])
       fixLabel(p, lelse)
     elif it.len == 1:
       startBlock(p)
@@ -355,7 +360,7 @@ proc genReturnStmt(p: BProc, t: PNode) =
     # consume it before we return.
     var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
     linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)    
-  lineFF(p, cpsStmts, "goto BeforeRet;$n", "br label %BeforeRet$n", [])
+  lineF(p, cpsStmts, "goto BeforeRet;$n", [])
 
 proc genComputedGoto(p: BProc; n: PNode) =
   # first pass: Generate array of computed labels:
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 823e3bc1b..ce17da17e 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -506,7 +506,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
     # C type generation into an analysis and a code generation phase somehow.
   case t.kind
   of tyRef, tyPtr, tyVar: 
-    let star = if t.kind == tyVar and compileToCpp(m): "&" else: "*"
+    var star = if t.kind == tyVar and compileToCpp(m): "&" else: "*"
     var et = t.lastSon
     var etB = et.skipTypes(abstractInst)
     if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}: 
@@ -514,6 +514,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
       # ``var set[char]`` in `getParamTypeDesc`
       et = elemType(etB)
       etB = et.skipTypes(abstractInst)
+      star[0] = '*'
     case etB.kind
     of tyObject, tyTuple:
       if isImportedCppType(etB) and et.kind == tyGenericInst:
@@ -529,7 +530,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
       # no restriction! We have a forward declaration for structs
       let x = getUniqueType(etB)
       let name = getTypeForward(m, x)
-      result = con(name, "**")
+      result = con(name, "*" & star)
       idTablePut(m.typeCache, t, result)
       pushType(m, x)
     else:
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index e16d5d0ce..676805958 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -137,79 +137,8 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
     if i - 1 >= start: 
       app(result, substr(frmt, start, i - 1))
 
-const compileTimeRopeFmt = false
-
-when compileTimeRopeFmt:
-  import macros
-
-  type TFmtFragmentKind = enum
-    ffSym,
-    ffLit,
-    ffParam
-
-  type TFragment = object
-    case kind: TFmtFragmentKind
-    of ffSym, ffLit:
-      value: string
-    of ffParam:
-      intValue: int
-
-  iterator fmtStringFragments(s: string): tuple[kind: TFmtFragmentKind,
-                                                value: string,
-                                                intValue: int] =
-    # This is a bit less featured version of the ropecg's algorithm
-    # (be careful when replacing ropecg calls)
-    var
-      i = 0
-      length = s.len
-
-    while i < length:
-      var start = i
-      case s[i]
-      of '$':
-        let n = s[i+1]
-        case n
-        of '$':
-          inc i, 2
-        of '0'..'9':
-          # XXX: use the new case object construction syntax when it's ready
-          yield (kind: ffParam, value: "", intValue: n.ord - ord('1'))
-          inc i, 2
-          start = i
-        else:
-          inc i
-      of '#':
-        inc i
-        var j = i
-        while s[i] in IdentChars: inc i
-        yield (kind: ffSym, value: substr(s, j, i-1), intValue: 0)
-        start = i
-      else: discard
-
-      while i < length:
-        if s[i] != '$' and s[i] != '#': inc i
-        else: break
-
-      if i - 1 >= start:
-        yield (kind: ffLit, value: substr(s, start, i-1), intValue: 0)
-
-  macro rfmt(m: BModule, fmt: static[string], args: varargs[PRope]): expr =
-    ## Experimental optimized rope-formatting operator
-    ## The run-time code it produces will be very fast, but will it speed up
-    ## the compilation of nimrod itself or will the macro execution time
-    ## offset the gains?
-    result = newCall(bindSym"ropeConcat")
-    for frag in fmtStringFragments(fmt):
-      case frag.kind
-      of ffSym:
-        result.add(newCall(bindSym"cgsym", m, newStrLitNode(frag.value)))
-      of ffLit:
-        result.add(newCall(bindSym"~", newStrLitNode(frag.value)))
-      of ffParam:
-        result.add(args[frag.intValue])
-else:
-  template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr =
-    ropecg(m, fmt, args)
+template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr =
+  ropecg(m, fmt, args)
 
 proc appcg(m: BModule, c: var PRope, frmt: TFormatStr, 
            args: varargs[PRope]) = 
@@ -242,24 +171,14 @@ proc lineCg(p: BProc, s: TCProcSection, frmt: TFormatStr,
                args: varargs[PRope]) =
   app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
 
-when compileTimeRopeFmt:
-  template linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr,
-                   args: varargs[PRope]) =
-    line(p, s, rfmt(p.module, frmt, args))
-else:
-  proc linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr,
-               args: varargs[PRope]) =
-    app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
+proc linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr,
+             args: varargs[PRope]) =
+  app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
 
 proc appLineCg(p: BProc, r: var PRope, frmt: TFormatStr,
                args: varargs[PRope]) =
   app(r, indentLine(p, ropecg(p.module, frmt, args)))
 
-proc lineFF(p: BProc, s: TCProcSection, cformat, llvmformat: string,
-               args: varargs[PRope]) =
-  if gCmd == cmdCompileToLLVM: lineF(p, s, llvmformat, args)
-  else: lineF(p, s, cformat, args)
-
 proc safeLineNm(info: TLineInfo): int =
   result = toLinenumber(info)
   if result < 0: result = 0 # negative numbers are not allowed in #line
@@ -723,13 +642,13 @@ proc cgsym(m: BModule, name: string): PRope =
     rawMessage(errSystemNeeds, name)
   result = sym.loc.r
   
-proc generateHeaders(m: BModule) = 
+proc generateHeaders(m: BModule) =
   app(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl)
   var it = PStrEntry(m.headerFiles.head)
-  while it != nil: 
+  while it != nil:
     if it.data[0] notin {'\"', '<'}: 
       appf(m.s[cfsHeaders], "$N#include \"$1\"$N", [toRope(it.data)])
-    else: 
+    else:
       appf(m.s[cfsHeaders], "$N#include $1$N", [toRope(it.data)])
     it = PStrEntry(it.next)
 
@@ -809,9 +728,10 @@ proc genProcAux(m: BModule, prc: PSym) =
     if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM):
       # invoke at proc entry for recursion:
       appcg(p, cpsInit, "\t#nimProfile();$n", [])
+    if p.beforeRetNeeded: app(generatedProc, "{")
     app(generatedProc, p.s(cpsInit))
     app(generatedProc, p.s(cpsStmts))
-    if p.beforeRetNeeded: app(generatedProc, ~"\tBeforeRet: ;$n")
+    if p.beforeRetNeeded: app(generatedProc, ~"\t}BeforeRet: ;$n")
     app(generatedProc, deinitGCFrame(p))
     if optStackTrace in prc.options: app(generatedProc, deinitFrame(p))
     app(generatedProc, returnStmt)
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index 508f98074..bb98454a7 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -82,6 +82,9 @@ type
     maxFrameLen*: int         # max length of frame descriptor
     module*: BModule          # used to prevent excessive parameter passing
     withinLoop*: int          # > 0 if we are within a loop
+    splitDecls*: int          # > 0 if we are in some context for C++ that
+                              # requires 'T x = T()' to become 'T x; x = T()'
+                              # (yes, C++ is weird like that)
     gcFrameId*: Natural       # for the GC stack marking
     gcFrameType*: PRope       # the struct {} we put the GC markers into
   
diff --git a/compiler/transf.nim b/compiler/transf.nim
index f511ed69f..cf13630fd 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -321,6 +321,7 @@ proc transformYield(c: PTransf, n: PNode): PTransNode =
 
 proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
   result = transformSons(c, n)
+  if gCmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
   var n = result.PNode
   case n.sons[0].kind
   of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64: