Skip to content

Commit

Permalink
lots of C++ codegen improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Araq committed Feb 7, 2015
1 parent d020ad0 commit e84834d
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 119 deletions.
24 changes: 16 additions & 8 deletions compiler/ccgcalls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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, ~", ")
Expand Down Expand Up @@ -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):
Expand All @@ -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, ~" ")
Expand Down
4 changes: 3 additions & 1 deletion compiler/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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)``
Expand Down
23 changes: 14 additions & 9 deletions compiler/ccgstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
5 changes: 3 additions & 2 deletions compiler/ccgtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -506,14 +506,15 @@ 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}:
# this is correct! sets have no proper base type, so we treat
# ``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:
Expand All @@ -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:
Expand Down
100 changes: 10 additions & 90 deletions compiler/cgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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]) =
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions compiler/cgendata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions compiler/transf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
8 changes: 6 additions & 2 deletions lib/pure/os.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1074,8 +1074,12 @@ when defined(windows):
# because we support Windows GUI applications, things get really
# messy here...
when useWinUnicode:
proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
importc: "wcschr", header: "<string.h>".}
when defined(cpp):
proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", header: "<string.h>".}
else:
proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
importc: "wcschr", header: "<string.h>".}
else:
proc strEnd(cstr: cstring, c = 0'i32): cstring {.
importc: "strchr", header: "<string.h>".}
Expand Down
6 changes: 4 additions & 2 deletions lib/system/dyncalls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,18 @@ elif defined(windows) or defined(dos):
type
THINSTANCE {.importc: "HINSTANCE".} = object
x: pointer
proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
importcpp: "(void*)GetProcAddress(@)", header: "<windows.h>", stdcall.}
else:
type
THINSTANCE {.importc: "HINSTANCE".} = pointer
proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
importc: "GetProcAddress", header: "<windows.h>", stdcall.}

proc freeLibrary(lib: THINSTANCE) {.
importc: "FreeLibrary", header: "<windows.h>", stdcall.}
proc winLoadLibrary(path: cstring): THINSTANCE {.
importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
importc: "GetProcAddress", header: "<windows.h>", stdcall.}

proc nimUnloadLibrary(lib: TLibHandle) =
freeLibrary(cast[THINSTANCE](lib))
Expand Down
16 changes: 11 additions & 5 deletions lib/system/sysio.nim
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,17 @@ proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n")
when (defined(windows) and not defined(useWinAnsi)) or defined(nimdoc):
include "system/widestrs"

when defined(windows) and not defined(useWinAnsi):
proc wfopen(filename, mode: WideCString): pointer {.
importc: "_wfopen", nodecl.}
proc wfreopen(filename, mode: WideCString, stream: File): File {.
importc: "_wfreopen", nodecl.}
when defined(windows) and not defined(useWinAnsi):
when defined(cpp):
proc wfopen(filename, mode: WideCString): pointer {.
importcpp: "_wfopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.}
proc wfreopen(filename, mode: WideCString, stream: File): File {.
importc: "_wfreopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.}
else:
proc wfopen(filename, mode: WideCString): pointer {.
importc: "_wfopen", nodecl.}
proc wfreopen(filename, mode: WideCString, stream: File): File {.
importc: "_wfreopen", nodecl.}

proc fopen(filename, mode: cstring): pointer =
var f = newWideCString(filename)
Expand Down

0 comments on commit e84834d

Please sign in to comment.