From d2b45dbe8514c615e54cdb61808b90913deec4e1 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 12 Apr 2012 14:12:32 +0300 Subject: [PATCH 1/9] C variables are created in their enclosing block instead of their enclosing function --- compiler/ccgcalls.nim | 34 +++++---- compiler/ccgexprs.nim | 38 +++++----- compiler/ccgmerge.nim | 4 +- compiler/ccgstmts.nim | 146 +++++++++++++++++++++---------------- compiler/ccgthreadvars.nim | 4 +- compiler/ccgtrav.nim | 24 +++--- compiler/cgen.nim | 70 +++++++++--------- compiler/cgendata.nim | 11 ++- 8 files changed, 180 insertions(+), 151 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index cb60146265..c1ad8614f8 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -6,6 +6,8 @@ # See the file "copying.txt", included in this # distribution, for details about the copyright. # +# +# included from cgen.nim proc leftAppearsOnRightSide(le, ri: PNode): bool = if le != nil: @@ -34,15 +36,15 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) = resetLoc(p, d) app(pl, addrLoc(d)) app(pl, ")") - app(p.s[cpsStmts], pl) - appf(p.s[cpsStmts], ";$n") + app(p.s(cpsStmts), pl) + appf(p.s(cpsStmts), ";$n") else: var tmp: TLoc getTemp(p, typ.sons[0], tmp) app(pl, addrLoc(tmp)) app(pl, ")") - app(p.s[cpsStmts], pl) - appf(p.s[cpsStmts], ";$n") + app(p.s(cpsStmts), pl) + appf(p.s(cpsStmts), ";$n") genAssignment(p, d, tmp, {}) # no need for deep copying else: app(pl, ")") @@ -54,8 +56,8 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) = genAssignment(p, d, list, {}) # no need for deep copying else: app(pl, ")") - app(p.s[cpsStmts], pl) - appf(p.s[cpsStmts], ";$n") + app(p.s(cpsStmts), pl) + appf(p.s(cpsStmts), ";$n") proc isInCurrentFrame(p: BProc, n: PNode): bool = # checks if `n` is an expression that refers to the current frame; @@ -164,7 +166,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = if i < length - 1: app(pl, ", ") template genCallPattern = - appf(p.s[cpsStmts], CallPattern, op.r, pl, pl.addComma, rawProc) + appf(p.s(cpsStmts), CallPattern, op.r, pl, pl.addComma, rawProc) let rawProc = getRawProcType(p, typ) if typ.sons[0] != nil: @@ -179,13 +181,13 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = resetLoc(p, d) app(pl, addrLoc(d)) genCallPattern() - appf(p.s[cpsStmts], ";$n") + appf(p.s(cpsStmts), ";$n") else: var tmp: TLoc getTemp(p, typ.sons[0], tmp) app(pl, addrLoc(tmp)) genCallPattern() - appf(p.s[cpsStmts], ";$n") + appf(p.s(cpsStmts), ";$n") genAssignment(p, d, tmp, {}) # no need for deep copying else: if d.k == locNone: getTemp(p, typ.sons[0], d) @@ -196,7 +198,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = genAssignment(p, d, list, {}) # no need for deep copying else: genCallPattern() - appf(p.s[cpsStmts], ";$n") + appf(p.s(cpsStmts), ";$n") proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = var op, a: TLoc @@ -261,15 +263,15 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = app(pl, "Result: ") app(pl, addrLoc(d)) app(pl, "]") - app(p.s[cpsStmts], pl) - appf(p.s[cpsStmts], ";$n") + app(p.s(cpsStmts), pl) + appf(p.s(cpsStmts), ";$n") else: var tmp: TLoc getTemp(p, typ.sons[0], tmp) app(pl, addrLoc(tmp)) app(pl, "]") - app(p.s[cpsStmts], pl) - appf(p.s[cpsStmts], ";$n") + app(p.s(cpsStmts), pl) + appf(p.s(cpsStmts), ";$n") genAssignment(p, d, tmp, {}) # no need for deep copying else: app(pl, "]") @@ -281,8 +283,8 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = genAssignment(p, d, list, {}) # no need for deep copying else: app(pl, "]") - app(p.s[cpsStmts], pl) - appf(p.s[cpsStmts], ";$n") + app(p.s(cpsStmts), pl) + appf(p.s(cpsStmts), ";$n") proc genCall(p: BProc, e: PNode, d: var TLoc) = if e.sons[0].typ.callConv == ccClosure: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index d031422082..34418f3534 100755 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -160,7 +160,7 @@ proc getStorageLoc(n: PNode): TStorageLoc = proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = if dest.s == OnStack or optRefcGC notin gGlobalOptions: - appf(p.s[cpsStmts], "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) + appf(p.s(cpsStmts), "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) if needToKeepAlive in flags: keepAlive(p, dest) elif dest.s == OnHeap: # location is on heap @@ -180,13 +180,13 @@ proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # appf(p.s[cpsStmts], 'if ($1) nimGCunref($1);$n', [rdLoc(dest)]) # appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]) if canFormAcycle(dest.t): - appcg(p.module, p.s[cpsStmts], "#asgnRef((void**) $1, $2);$n", + appcg(p.module, p.s(cpsStmts), "#asgnRef((void**) $1, $2);$n", [addrLoc(dest), rdLoc(src)]) else: - appcg(p.module, p.s[cpsStmts], "#asgnRefNoCycle((void**) $1, $2);$n", + appcg(p.module, p.s(cpsStmts), "#asgnRefNoCycle((void**) $1, $2);$n", [addrLoc(dest), rdLoc(src)]) else: - appcg(p.module, p.s[cpsStmts], "#unsureAsgnRef((void**) $1, $2);$n", + appcg(p.module, p.s(cpsStmts), "#unsureAsgnRef((void**) $1, $2);$n", [addrLoc(dest), rdLoc(src)]) if needToKeepAlive in flags: keepAlive(p, dest) @@ -736,9 +736,9 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) = expr(p, e.sons[1], tmp) L = getLabel(p) if m == mOr: - appf(p.s[cpsStmts], "if ($1) goto $2;$n", [rdLoc(tmp), L]) + appf(p.s(cpsStmts), "if ($1) goto $2;$n", [rdLoc(tmp), L]) else: - appf(p.s[cpsStmts], "if (!($1)) goto $2;$n", [rdLoc(tmp), L]) + appf(p.s(cpsStmts), "if (!($1)) goto $2;$n", [rdLoc(tmp), L]) expr(p, e.sons[2], tmp) fixLabel(p, L) if d.k == locNone: @@ -771,9 +771,9 @@ proc genIfExpr(p: BProc, n: PNode, d: var TLoc) = of nkElifExpr: initLocExpr(p, it.sons[0], a) Lelse = getLabel(p) - appf(p.s[cpsStmts], "if (!$1) goto $2;$n", [rdLoc(a), Lelse]) + appf(p.s(cpsStmts), "if (!$1) goto $2;$n", [rdLoc(a), Lelse]) expr(p, it.sons[1], tmp) - appf(p.s[cpsStmts], "goto $1;$n", [Lend]) + appf(p.s(cpsStmts), "goto $1;$n", [Lend]) fixLabel(p, Lelse) of nkElseExpr: expr(p, it.sons[0], tmp) @@ -832,7 +832,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = appf(lens, "$1->$2 + ", [rdLoc(a), lenField()]) appcg(p.module, appends, "#appendString($1, $2);$n", [tmp.r, rdLoc(a)]) appcg(p, cpsStmts, "$1 = #rawNewString($2$3);$n", [tmp.r, lens, toRope(L)]) - app(p.s[cpsStmts], appends) + app(p.s(cpsStmts), appends) if d.k == locNone: d = tmp keepAlive(p, tmp) @@ -874,7 +874,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = appcg(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n", [rdLoc(dest), lens, toRope(L)]) keepAlive(p, dest) - app(p.s[cpsStmts], appends) + app(p.s(cpsStmts), appends) proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = # seq &= x --> @@ -1171,7 +1171,7 @@ proc binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) = assert(d.k == locNone) InitLocExpr(p, e.sons[1], a) InitLocExpr(p, e.sons[2], b) - appf(p.s[cpsStmts], frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]) + appf(p.s(cpsStmts), frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]) proc genInOp(p: BProc, e: PNode, d: var TLoc) = var a, b, x, y: TLoc @@ -1247,7 +1247,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) if d.k == locNone: getTemp(p, a.t, d) - appf(p.s[cpsStmts], lookupOpr[op], + appf(p.s(cpsStmts), lookupOpr[op], [rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)]) of mEqSet: binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)") @@ -1257,7 +1257,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) if d.k == locNone: getTemp(p, a.t, d) - appf(p.s[cpsStmts], + appf(p.s(cpsStmts), "for ($1 = 0; $1 < $2; $1++) $n" & " $3[$1] = $4[$1] $6 $5[$1];$n", [ rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b), @@ -1467,35 +1467,35 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = if d.k == locNone: getTemp(p, e.typ, d) if getSize(e.typ) > 8: # big set: - appf(p.s[cpsStmts], "memset($1, 0, sizeof($1));$n", [rdLoc(d)]) + appf(p.s(cpsStmts), "memset($1, 0, sizeof($1));$n", [rdLoc(d)]) for i in countup(0, sonsLen(e) - 1): if e.sons[i].kind == nkRange: getTemp(p, getSysType(tyInt), idx) # our counter initLocExpr(p, e.sons[i].sons[0], a) initLocExpr(p, e.sons[i].sons[1], b) - appf(p.s[cpsStmts], "for ($1 = $3; $1 <= $4; $1++) $n" & + appf(p.s(cpsStmts), "for ($1 = $3; $1 <= $4; $1++) $n" & "$2[$1/8] |=(1<<($1%8));$n", [rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ), rdSetElemLoc(b, e.typ)]) else: initLocExpr(p, e.sons[i], a) - appf(p.s[cpsStmts], "$1[$2/8] |=(1<<($2%8));$n", + appf(p.s(cpsStmts), "$1[$2/8] |=(1<<($2%8));$n", [rdLoc(d), rdSetElemLoc(a, e.typ)]) else: # small set var ts = "NI" & $(getSize(e.typ) * 8) - appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(d)]) + appf(p.s(cpsStmts), "$1 = 0;$n", [rdLoc(d)]) for i in countup(0, sonsLen(e) - 1): if e.sons[i].kind == nkRange: getTemp(p, getSysType(tyInt), idx) # our counter initLocExpr(p, e.sons[i].sons[0], a) initLocExpr(p, e.sons[i].sons[1], b) - appf(p.s[cpsStmts], "for ($1 = $3; $1 <= $4; $1++) $n" & + appf(p.s(cpsStmts), "for ($1 = $3; $1 <= $4; $1++) $n" & "$2 |=(1<<((" & ts & ")($1)%(sizeof(" & ts & ")*8)));$n", [ rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ), rdSetElemLoc(b, e.typ)]) else: initLocExpr(p, e.sons[i], a) - appf(p.s[cpsStmts], + appf(p.s(cpsStmts), "$1 |=(1<<((" & ts & ")($2)%(sizeof(" & ts & ")*8)));$n", [rdLoc(d), rdSetElemLoc(a, e.typ)]) diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index 36d1417a6c..45463a397d 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -280,7 +280,7 @@ proc mergeRequired*(m: BModule): bool = #echo "not empty: ", i, " ", ropeToStr(m.s[i]) return true for i in low(TCProcSection)..high(TCProcSection): - if m.initProc.s[i] != nil: + if m.initProc.s(i) != nil: #echo "not empty: ", i, " ", ropeToStr(m.initProc.s[i]) return true @@ -292,5 +292,5 @@ proc mergeFiles*(cfilename: string, m: BModule) = for i in low(TCFileSection)..high(TCFileSection): m.s[i] = con(old.f[i], m.s[i]) for i in low(TCProcSection)..high(TCProcSection): - m.initProc.s[i] = con(old.p[i], m.initProc.s[i]) + m.initProc.s(i) = con(old.p[i], m.initProc.s(i)) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 5ad9d8b448..20c0e5566a 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -120,6 +120,7 @@ proc genIfStmt(p: BProc, n: PNode) = # elsePart # Lend: # + ## XXX: push blocks here var a: TLoc Lelse: TLabel @@ -132,12 +133,12 @@ proc genIfStmt(p: BProc, n: PNode) = initLocExpr(p, it.sons[0], a) Lelse = getLabel(p) inc(p.labels) - appff(p.s[cpsStmts], "if (!$1) goto $2;$n", + appff(p.s(cpsStmts), "if (!$1) goto $2;$n", "br i1 $1, label %LOC$3, label %$2$n" & "LOC$3: $n", [rdLoc(a), Lelse, toRope(p.labels)]) genStmts(p, it.sons[1]) if sonsLen(n) > 1: - appff(p.s[cpsStmts], "goto $1;$n", "br label %$1$n", [Lend]) + appff(p.s(cpsStmts), "goto $1;$n", "br label %$1$n", [Lend]) fixLabel(p, Lelse) of nkElse: genStmts(p, it.sons[0]) @@ -169,52 +170,69 @@ proc genReturnStmt(p: BProc, t: PNode) = genLineDir(p, t) if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0]) blockLeaveActions(p, min(1, p.nestedTryStmts.len)) - appff(p.s[cpsStmts], "goto BeforeRet;$n", "br label %BeforeRet$n", []) + appff(p.s(cpsStmts), "goto BeforeRet;$n", "br label %BeforeRet$n", []) -proc genWhileStmt(p: BProc, t: PNode) = +proc startBlock(p: BProc, start = "{$n"): int = + inc(p.labels) + result = len(p.blocks) + setlen(p.blocks, result + 1) + p.blocks[result].id = p.labels + p.blocks[result].nestedTryStmts = p.nestedTryStmts.len + appf(p.s(cpsStmts), start) + +proc assignLabel(b: var TBlock): PRope {.inline.} = + b.label = con("LA", b.id.toRope) + result = b.label + +proc blockBody(b: var TBlock): PRope {.inline.} = + result = b.sections[cpsLocals].con(b.sections[cpsInit]).con(b.sections[cpsStmts]) + +var gBlockEndBracket = ropef("}$n") + +proc endBlock(p: BProc) = + let topBlock = p.blocks.len - 1 + let blockEnd = if p.blocks[topBlock].label != nil: + ropef("} $1: ;$n", [p.blocks[topBlock].label]) + else: + gBlockEndBracket + # the block is merged into the parent block + app(p.blocks[topBlock - 1].sections[cpsStmts], p.blocks[topBlock].blockBody) + setlen(p.blocks, topBlock) + # this is done after the block is popped so $n is + # properly indented when pretty printing is enabled + app(p.s(cpsStmts), blockEnd) + +proc genWhileStmt(p: BProc, t: PNode) = # we don't generate labels here as for example GCC would produce # significantly worse code var a: TLoc Labl: TLabel - length: int + assert(sonsLen(t) == 2) inc(p.withinLoop) genLineDir(p, t) - assert(sonsLen(t) == 2) - inc(p.labels) - Labl = con("LA", toRope(p.labels)) - length = len(p.blocks) - setlen(p.blocks, length + 1) - p.blocks[length].id = - p.labels # negative because it isn't used yet - p.blocks[length].nestedTryStmts = p.nestedTryStmts.len - appf(p.s[cpsStmts], "while (1) {$n") + + var blockIdx = startBlock(p, "while (1) {$n") initLocExpr(p, t.sons[0], a) if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0): - p.blocks[length].id = abs(p.blocks[length].id) - appf(p.s[cpsStmts], "if (!$1) goto $2;$n", [rdLoc(a), Labl]) + let label = assignLabel(p.blocks[blockIdx]) + appf(p.s(cpsStmts), "if (!$1) goto $2;$n", [rdLoc(a), label]) genStmts(p, t.sons[1]) - if p.blocks[length].id > 0: appf(p.s[cpsStmts], "} $1: ;$n", [Labl]) - else: appf(p.s[cpsStmts], "}$n") - setlen(p.blocks, len(p.blocks) - 1) + endBlock(p) + dec(p.withinLoop) proc genBlock(p: BProc, t: PNode, d: var TLoc) = - inc(p.labels) - var idx = len(p.blocks) + var idx = startBlock(p) if t.sons[0].kind != nkEmpty: # named block? assert(t.sons[0].kind == nkSym) var sym = t.sons[0].sym sym.loc.k = locOther sym.loc.a = idx - setlen(p.blocks, idx + 1) - p.blocks[idx].id = -p.labels # negative because it isn't used yet - p.blocks[idx].nestedTryStmts = p.nestedTryStmts.len if t.kind == nkBlockExpr: genStmtListExpr(p, t.sons[1], d) else: genStmts(p, t.sons[1]) - if p.blocks[idx].id > 0: - appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(p.blocks[idx].id)]) - setlen(p.blocks, idx) + endBlock(p) proc genBreakStmt(p: BProc, t: PNode) = var idx = len(p.blocks) - 1 @@ -224,10 +242,10 @@ proc genBreakStmt(p: BProc, t: PNode) = var sym = t.sons[0].sym assert(sym.loc.k == locOther) idx = sym.loc.a - p.blocks[idx].id = abs(p.blocks[idx].id) # label is used + let label = assignLabel(p.blocks[idx]) blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts) genLineDir(p, t) - appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.blocks[idx].id)]) + appf(p.s(cpsStmts), "goto $1;$n", [label]) proc getRaiseFrmt(p: BProc): string = #if gCmd == cmdCompileToCpp: @@ -269,11 +287,11 @@ proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, proc genCaseSecondPass(p: BProc, t: PNode, labId, until: int): TLabel = var Lend = getLabel(p) for i in 1..until: - appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(labId + i)]) + appf(p.s(cpsStmts), "LA$1: ;$n", [toRope(labId + i)]) if t.sons[i].kind == nkOfBranch: var length = sonsLen(t.sons[i]) genStmts(p, t.sons[i].sons[length - 1]) - appf(p.s[cpsStmts], "goto $1;$n", [Lend]) + appf(p.s(cpsStmts), "goto $1;$n", [Lend]) else: genStmts(p, t.sons[i].sons[0]) result = Lend @@ -288,13 +306,13 @@ proc genIfForCaseUntil(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr, genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat, con("LA", toRope(p.labels))) else: - appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)]) + appf(p.s(cpsStmts), "goto LA$1;$n", [toRope(p.labels)]) if until < t.len-1: inc(p.labels) var gotoTarget = p.labels - appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(gotoTarget)]) + appf(p.s(cpsStmts), "goto LA$1;$n", [toRope(gotoTarget)]) result = genCaseSecondPass(p, t, labId, until) - appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(gotoTarget)]) + appf(p.s(cpsStmts), "LA$1: ;$n", [toRope(gotoTarget)]) else: result = genCaseSecondPass(p, t, labId, until) @@ -346,11 +364,11 @@ proc genStringCase(p: BProc, t: PNode) = if interior != brn: echo "BUG! ", interior, "-", brn if branches[j] != nil: - appf(p.s[cpsStmts], "case $1: $n$2break;$n", + appf(p.s(cpsStmts), "case $1: $n$2break;$n", [intLiteral(j), branches[j]]) - appf(p.s[cpsStmts], "}$n") # else statement: + appf(p.s(cpsStmts), "}$n") # else statement: if t.sons[sonsLen(t) - 1].kind != nkOfBranch: - appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)]) + appf(p.s(cpsStmts), "goto LA$1;$n", [toRope(p.labels)]) # third pass: generate statements var Lend = genCaseSecondPass(p, t, labId, sonsLen(t)-1) fixLabel(p, Lend) @@ -379,16 +397,16 @@ proc genCaseRange(p: BProc, branch: PNode) = for j in 0 .. length-2: if branch[j].kind == nkRange: if hasSwitchRange in CC[ccompiler].props: - appf(p.s[cpsStmts], "case $1 ... $2:$n", [ + appf(p.s(cpsStmts), "case $1 ... $2:$n", [ genLiteral(p, branch[j][0]), genLiteral(p, branch[j][1])]) else: var v = copyNode(branch[j][0]) while v.intVal <= branch[j][1].intVal: - appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, v)]) + appf(p.s(cpsStmts), "case $1:$n", [genLiteral(p, v)]) Inc(v.intVal) else: - appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, branch[j])]) + appf(p.s(cpsStmts), "case $1:$n", [genLiteral(p, branch[j])]) proc genOrdinalCase(p: BProc, n: PNode) = # analyse 'case' statement: @@ -404,7 +422,7 @@ proc genOrdinalCase(p: BProc, n: PNode) = # generate switch part (might be empty): if splitPoint+1 < n.len: - appf(p.s[cpsStmts], "switch ($1) {$n", [rdCharLoc(a)]) + appf(p.s(cpsStmts), "switch ($1) {$n", [rdCharLoc(a)]) var hasDefault = false for i in splitPoint+1 .. < n.len: var branch = n[i] @@ -413,13 +431,13 @@ proc genOrdinalCase(p: BProc, n: PNode) = genStmts(p, branch.lastSon) else: # else part of case statement: - appf(p.s[cpsStmts], "default:$n") + appf(p.s(cpsStmts), "default:$n") genStmts(p, branch[0]) hasDefault = true - appf(p.s[cpsStmts], "break;$n") + appf(p.s(cpsStmts), "break;$n") if (hasAssume in CC[ccompiler].props) and not hasDefault: - appf(p.s[cpsStmts], "default: __assume(0);$n") - appf(p.s[cpsStmts], "}$n") + appf(p.s(cpsStmts), "default: __assume(0);$n") + appf(p.s(cpsStmts), "}$n") if Lend != nil: fixLabel(p, Lend) proc genCaseStmt(p: BProc, t: PNode) = @@ -475,42 +493,42 @@ proc genTryStmtCpp(p: BProc, t: PNode) = exc = getTempName() if not hasGeneralExceptSection(t): rethrowFlag = getTempName() - appf(p.s[cpsLocals], "volatile NIM_BOOL $1 = NIM_FALSE;$n", [rethrowFlag]) + appf(p.s(cpsLocals), "volatile NIM_BOOL $1 = NIM_FALSE;$n", [rethrowFlag]) if optStackTrace in p.Options: appcg(p, cpsStmts, "#setFrame((TFrame*)&F);$n") - appf(p.s[cpsStmts], "try {$n") + appf(p.s(cpsStmts), "try {$n") add(p.nestedTryStmts, t) genStmts(p, t.sons[0]) length = sonsLen(t) if t.sons[1].kind == nkExceptBranch: - appf(p.s[cpsStmts], "} catch (NimException& $1) {$n", [exc]) + appf(p.s(cpsStmts), "} catch (NimException& $1) {$n", [exc]) if rethrowFlag != nil: - appf(p.s[cpsStmts], "$1 = NIM_TRUE;$n", [rethrowFlag]) - appf(p.s[cpsStmts], "if ($1.sp.exc) {$n", [exc]) + appf(p.s(cpsStmts), "$1 = NIM_TRUE;$n", [rethrowFlag]) + appf(p.s(cpsStmts), "if ($1.sp.exc) {$n", [exc]) i = 1 while (i < length) and (t.sons[i].kind == nkExceptBranch): blen = sonsLen(t.sons[i]) if blen == 1: # general except section: - appf(p.s[cpsStmts], "default:$n") + appf(p.s(cpsStmts), "default:$n") genStmts(p, t.sons[i].sons[0]) else: for j in countup(0, blen - 2): assert(t.sons[i].sons[j].kind == nkType) - appf(p.s[cpsStmts], "case $1:$n", [toRope(t.sons[i].sons[j].typ.id)]) + appf(p.s(cpsStmts), "case $1:$n", [toRope(t.sons[i].sons[j].typ.id)]) genStmts(p, t.sons[i].sons[blen - 1]) if rethrowFlag != nil: - appf(p.s[cpsStmts], "$1 = NIM_FALSE; ", [rethrowFlag]) - appf(p.s[cpsStmts], "break;$n") + appf(p.s(cpsStmts), "$1 = NIM_FALSE; ", [rethrowFlag]) + appf(p.s(cpsStmts), "break;$n") inc(i) if t.sons[1].kind == nkExceptBranch: - appf(p.s[cpsStmts], "}}$n") # end of catch-switch statement + appf(p.s(cpsStmts), "}}$n") # end of catch-switch statement appcg(p, cpsStmts, "#popSafePoint();") discard pop(p.nestedTryStmts) if (i < length) and (t.sons[i].kind == nkFinally): genStmts(p, t.sons[i].sons[0]) if rethrowFlag != nil: - appf(p.s[cpsStmts], "if ($1) { throw; }$n", [rethrowFlag]) + appf(p.s(cpsStmts), "if ($1) { throw; }$n", [rethrowFlag]) proc genTryStmt(p: BProc, t: PNode) = # code to generate: @@ -535,6 +553,8 @@ proc genTryStmt(p: BProc, t: PNode) = # printf('fin!\n'); # if (exception not cleared) # propagateCurrentException(); + # + # XXX: push blocks here genLineDir(p, t) var safePoint = getTempName() discard cgsym(p.module, "E_Base") @@ -543,7 +563,7 @@ proc genTryStmt(p: BProc, t: PNode) = "$1.status = setjmp($1.context);$n", [safePoint]) if optStackTrace in p.Options: appcg(p, cpsStmts, "#setFrame((TFrame*)&F);$n") - appf(p.s[cpsStmts], "if ($1.status == 0) {$n", [safePoint]) + appf(p.s(cpsStmts), "if ($1.status == 0) {$n", [safePoint]) var length = sonsLen(t) add(p.nestedTryStmts, t) genStmts(p, t.sons[0]) @@ -554,13 +574,13 @@ proc genTryStmt(p: BProc, t: PNode) = var blen = sonsLen(t.sons[i]) if blen == 1: # general except section: - if i > 1: appf(p.s[cpsStmts], "else {$n") + if i > 1: appf(p.s(cpsStmts), "else {$n") appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint]) inc p.popCurrExc genStmts(p, t.sons[i].sons[0]) dec p.popCurrExc appcg(p, cpsStmts, "#popCurrentException();$n", []) - if i > 1: appf(p.s[cpsStmts], "}$n") + if i > 1: appf(p.s(cpsStmts), "}$n") else: inc p.popCurrExc var orExpr: PRope = nil @@ -570,15 +590,15 @@ proc genTryStmt(p: BProc, t: PNode) = appcg(p.module, orExpr, "#isObj(#getCurrentException()->Sup.m_type, $1)", [genTypeInfo(p.module, t.sons[i].sons[j].typ)]) - if i > 1: app(p.s[cpsStmts], "else ") - appf(p.s[cpsStmts], "if ($1) {$n", [orExpr]) + if i > 1: app(p.s(cpsStmts), "else ") + appf(p.s(cpsStmts), "if ($1) {$n", [orExpr]) appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint]) genStmts(p, t.sons[i].sons[blen-1]) dec p.popCurrExc # code to clear the exception: appcg(p, cpsStmts, "#popCurrentException();}$n", []) inc(i) - appf(p.s[cpsStmts], "}$n") # end of if statement + appf(p.s(cpsStmts), "}$n") # end of if statement if i < length and t.sons[i].kind == nkFinally: genStmts(p, t.sons[i].sons[0]) appcg(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint]) @@ -608,7 +628,7 @@ proc genAsmStmt(p: BProc, t: PNode) = assert(t.kind == nkAsmStmt) genLineDir(p, t) var s = genAsmOrEmitStmt(p, t) - appf(p.s[cpsStmts], CC[ccompiler].asmStmtFrmt, [s]) + appf(p.s(cpsStmts), CC[ccompiler].asmStmtFrmt, [s]) proc genEmit(p: BProc, t: PNode) = genLineDir(p, t) @@ -617,7 +637,7 @@ proc genEmit(p: BProc, t: PNode) = # top level emit pragma? app(p.module.s[cfsProcHeaders], s) else: - app(p.s[cpsStmts], s) + app(p.s(cpsStmts), s) var breakPointId: int = 0 diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index 18eaceb69c..94c34d13c1 100755 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -10,6 +10,8 @@ ## Thread var support for crappy architectures that lack native support for ## thread local storage. (**Thank you Mac OS X!**) +# included from cgen.nim + proc emulatedThreadVars(): bool {.inline.} = result = {optThreads, optTlsEmulation} <= gGlobalOptions @@ -17,7 +19,7 @@ proc AccessThreadLocalVar(p: BProc, s: PSym) = if emulatedThreadVars() and not p.ThreadVarAccessed: p.ThreadVarAccessed = true p.module.usesThreadVars = true - appf(p.s[cpsLocals], "NimThreadVars* NimTV;$n") + appf(p.s(cpsLocals), "NimThreadVars* NimTV;$n") appcg(p, cpsInit, "NimTV=(NimThreadVars*)#GetThreadLocalVars();$n") var diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 8aaf5370fb..d95ea8b09b 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -10,6 +10,8 @@ ## Generates traversal procs for the C backend. Traversal procs are only an ## optimization; the GC works without them too. +# included from cgen.nim + type TTraversalClosure {.pure, final.} = object p: BProc @@ -29,17 +31,17 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) = if (n.sons[0].kind != nkSym): InternalError(n.info, "genTraverseProc") var p = c.p let disc = n.sons[0].sym - p.s[cpsStmts].appf("switch ($1.$2) {$n", accessor, disc.loc.r) + p.s(cpsStmts).appf("switch ($1.$2) {$n", accessor, disc.loc.r) for i in countup(1, sonsLen(n) - 1): let branch = n.sons[i] assert branch.kind in {nkOfBranch, nkElse} if branch.kind == nkOfBranch: genCaseRange(c.p, branch) else: - p.s[cpsStmts].appf("default:$n") + p.s(cpsStmts).appf("default:$n") genTraverseProc(c, accessor, lastSon(branch)) - p.s[cpsStmts].appf("break;$n") - p.s[cpsStmts].appf("} $n") + p.s(cpsStmts).appf("break;$n") + p.s(cpsStmts).appf("} $n") of nkSym: let field = n.sym genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t) @@ -61,10 +63,10 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) = let arraySize = lengthOrd(typ.sons[0]) var i: TLoc getTemp(p, getSysType(tyInt), i) - appf(p.s[cpsStmts], "for ($1 = 0; $1 < $2; $1++) {$n", + appf(p.s(cpsStmts), "for ($1 = 0; $1 < $2; $1++) {$n", i.r, arraySize.toRope) genTraverseProc(c, ropef("$1[$2]", accessor, i.r), typ.sons[1]) - appf(p.s[cpsStmts], "}$n") + appf(p.s(cpsStmts), "}$n") of tyObject: for i in countup(0, sonsLen(typ) - 1): genTraverseProc(c, accessor.parentObj, typ.sons[i]) @@ -87,10 +89,10 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) = assert typ.kind == tySequence var i: TLoc getTemp(p, getSysType(tyInt), i) - appf(p.s[cpsStmts], "for ($1 = 0; $1 < $2->$3; $1++) {$n", + appf(p.s(cpsStmts), "for ($1 = 0; $1 < $2->$3; $1++) {$n", i.r, accessor, toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len")) genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0]) - appf(p.s[cpsStmts], "}$n") + appf(p.s(cpsStmts), "}$n") proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope = var c: TTraversalClosure @@ -104,8 +106,8 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope = let header = ropef("N_NIMCALL(void, $1)(void* p, NI op)", result) let t = getTypeDesc(m, typ) - p.s[cpsLocals].appf("$1 a;$n", t) - p.s[cpsInit].appf("a = ($1)p;$n", t) + p.s(cpsLocals).appf("$1 a;$n", t) + p.s(cpsInit).appf("a = ($1)p;$n", t) c.p = p if typ.kind == tySequence: @@ -118,7 +120,7 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope = genTraverseProc(c, "(*a)".toRope, typ.sons[0]) let generatedProc = ropef("$1 {$n$2$3$4}$n", - [header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]]) + [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]) m.s[cfsProcHeaders].appf("$1;$n", header) m.s[cfsProcs].app(generatedProc) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index de91205e2c..acaa785f8c 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -151,7 +151,7 @@ proc appcg(m: BModule, s: TCFileSection, frmt: TFormatStr, proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr, args: openarray[PRope]) = - app(p.s[s], ropecg(p.module, frmt, args)) + app(p.s(s), ropecg(p.module, frmt, args)) proc safeLineNm(info: TLineInfo): int = result = toLinenumber(info) @@ -168,14 +168,14 @@ proc genCLineDir(r: var PRope, info: TLineInfo) = proc genLineDir(p: BProc, t: PNode) = var line = t.info.safeLineNm - genCLineDir(p.s[cpsStmts], t.info.toFullPath, line) + genCLineDir(p.s(cpsStmts), t.info.toFullPath, line) if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and (p.prc == nil or sfPure notin p.prc.flags): appcg(p, cpsStmts, "#endb($1);$n", [toRope(line)]) elif ({optLineTrace, optStackTrace} * p.Options == {optLineTrace, optStackTrace}) and (p.prc == nil or sfPure notin p.prc.flags): - appf(p.s[cpsStmts], "F.line = $1;F.filename = $2;$n", + appf(p.s(cpsStmts), "F.line = $1;F.filename = $2;$n", [toRope(line), makeCString(toFilename(t.info).extractFilename)]) include "ccgtypes.nim" @@ -232,29 +232,29 @@ proc isComplexValueType(t: PType): bool {.inline.} = proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) = if not isComplexValueType(skipTypes(loc.t, abstractVarRange)): if containsGcref and p.WithInLoop > 0: - appf(p.s[cpsInit], "$1 = 0;$n", [rdLoc(loc)]) + appf(p.s(cpsInit), "$1 = 0;$n", [rdLoc(loc)]) var nilLoc: TLoc initLoc(nilLoc, locTemp, loc.t, onStack) nilLoc.r = toRope("NIM_NIL") # puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``: genRefAssign(p, loc, nilLoc, {afSrcIsNil}) else: - appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)]) + appf(p.s(cpsStmts), "$1 = 0;$n", [rdLoc(loc)]) else: if containsGcref and p.WithInLoop > 0: - appf(p.s[cpsInit], "memset((void*)$1, 0, sizeof($2));$n", + appf(p.s(cpsInit), "memset((void*)$1, 0, sizeof($2));$n", [addrLoc(loc), rdLoc(loc)]) genObjectInit(p, cpsInit, loc.t, loc, true) appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", [addrLoc(loc), genTypeInfo(p.module, loc.t)]) else: - appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", + appf(p.s(cpsStmts), "memset((void*)$1, 0, sizeof($2));$n", [addrLoc(loc), rdLoc(loc)]) genObjectInit(p, cpsStmts, loc.t, loc, true) proc zeroTemp(p: BProc, loc: TLoc) = if not isComplexValueType(skipTypes(loc.t, abstractVarRange)): - appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)]) + appf(p.s(cpsStmts), "$1 = 0;$n", [rdLoc(loc)]) when false: var nilLoc: TLoc initLoc(nilLoc, locTemp, loc.t, onStack) @@ -262,7 +262,7 @@ proc zeroTemp(p: BProc, loc: TLoc) = # puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``: genRefAssign(p, loc, nilLoc, {afSrcIsNil}) else: - appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", + appf(p.s(cpsStmts), "memset((void*)$1, 0, sizeof($2));$n", [addrLoc(loc), rdLoc(loc)]) # XXX no object init necessary for temporaries? when false: @@ -291,7 +291,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc) = result.r = con("%LOC", toRope(p.labels)) else: result.r = con("LOC", toRope(p.labels)) - appf(p.s[cpsLocals], "$1 $2;$n", [getTypeDesc(p.module, t), result.r]) + appf(p.s(cpsLocals), "$1 $2;$n", [getTypeDesc(p.module, t), result.r]) result.k = locTemp result.a = - 1 result.t = getUniqueType(t) @@ -361,7 +361,7 @@ proc allocParam(p: BProc, s: PSym) = var tmp = con("%LOC", toRope(p.labels)) incl(s.loc.flags, lfParamCopy) incl(s.loc.flags, lfIndirect) - appf(p.s[cpsInit], "$1 = alloca $3$n" & "store $3 $2, $3* $1$n", + appf(p.s(cpsInit), "$1 = alloca $3$n" & "store $3 $2, $3* $1$n", [tmp, s.loc.r, getTypeDesc(p.module, s.loc.t)]) s.loc.r = tmp @@ -371,7 +371,7 @@ proc localDebugInfo(p: BProc, s: PSym) = if skipTypes(s.typ, abstractVar).kind == tyOpenArray: return var a = con("&", s.loc.r) if (s.kind == skParam) and ccgIntroducedPtr(s): a = s.loc.r - appf(p.s[cpsInit], + appf(p.s(cpsInit), "F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n", [toRope(p.frameLen), makeCString(normalize(s.name.s)), a, genTypeInfo(p.module, s.loc.t)]) @@ -384,13 +384,13 @@ proc assignLocalVar(p: BProc, s: PSym) = if s.loc.k == locNone: fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack) if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) - app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t)) - if sfRegister in s.flags: app(p.s[cpsLocals], " register") + app(p.s(cpsLocals), getTypeDesc(p.module, s.loc.t)) + if sfRegister in s.flags: app(p.s(cpsLocals), " register") #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: # app(p.s[cpsLocals], " GC_GUARD") if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0): - app(p.s[cpsLocals], " volatile") - appf(p.s[cpsLocals], " $1;$n", [s.loc.r]) + app(p.s(cpsLocals), " volatile") + appf(p.s(cpsLocals), " $1;$n", [s.loc.r]) localDebugInfo(p, s) include ccgthreadvars @@ -433,7 +433,7 @@ proc getLabel(p: BProc): TLabel = result = con("LA", toRope(p.labels)) proc fixLabel(p: BProc, labl: TLabel) = - appf(p.s[cpsStmts], "$1: ;$n", [labl]) + appf(p.s(cpsStmts), "$1: ;$n", [labl]) proc genVarPrototype(m: BModule, sym: PSym) proc requestConstImpl(p: BProc, sym: PSym) @@ -481,9 +481,9 @@ proc loadDynamicLib(m: BModule, lib: PLib) = var p = newProc(nil, m) var dest: TLoc initLocExpr(p, lib.path, dest) - app(m.s[cfsVars], p.s[cpsLocals]) - app(m.s[cfsDynLibInit], p.s[cpsInit]) - app(m.s[cfsDynLibInit], p.s[cpsStmts]) + app(m.s[cfsVars], p.s(cpsLocals)) + app(m.s[cfsDynLibInit], p.s(cpsInit)) + app(m.s[cfsDynLibInit], p.s(cpsStmts)) appcg(m, m.s[cfsDynLibInit], "if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n", [tmp, rdLoc(dest)]) @@ -551,13 +551,13 @@ proc getFrameDecl(p: BProc) = [toRope(p.frameLen)]) else: slots = nil - appff(p.s[cpsLocals], "volatile struct {TFrame* prev;" & + appff(p.s(cpsLocals), "volatile struct {TFrame* prev;" & "NCSTRING procname;NI line;NCSTRING filename;" & "NI len;$n$1} F;$n", "%TF = type {%TFrame*, i8*, %NI, %NI$1}$n" & "%F = alloca %TF$n", [slots]) inc(p.labels) - prepend(p.s[cpsInit], ropeff("F.len = $1;$n", + prepend(p.s(cpsInit), ropeff("F.len = $1;$n", "%LOC$2 = getelementptr %TF %F, %NI 4$n" & "store %NI $1, %NI* %LOC$2$n", [toRope(p.frameLen), toRope(p.labels)])) @@ -613,32 +613,32 @@ proc genProcAux(m: BModule, prc: PSym) = var generatedProc: PRope if sfPure in prc.flags: generatedProc = ropeff("$1 {$n$2$3$4}$n", "define $1 {$n$2$3$4}$n", - [header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]]) + [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]) else: generatedProc = ropeff("$1 {$n", "define $1 {$n", [header]) app(generatedProc, initGCFrame(p)) if optStackTrace in prc.options: getFrameDecl(p) - app(generatedProc, p.s[cpsLocals]) + app(generatedProc, p.s(cpsLocals)) var procname = CStringLit(p, generatedProc, prc.name.s) var filename = CStringLit(p, generatedProc, toFilename(prc.info)) app(generatedProc, initFrame(p, procname, filename)) else: - app(generatedProc, p.s[cpsLocals]) + app(generatedProc, p.s(cpsLocals)) if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM): if gProcProfile >= 64 * 1024: InternalError(prc.info, "too many procedures for profiling") discard cgsym(m, "profileData") - appf(p.s[cpsLocals], "ticks NIM_profilingStart;$n") + appf(p.s(cpsLocals), "ticks NIM_profilingStart;$n") if prc.loc.a < 0: appf(m.s[cfsDebugInit], "profileData[$1].procname = $2;$n", [ toRope(gProcProfile), makeCString(prc.name.s)]) prc.loc.a = gProcProfile inc(gProcProfile) - prepend(p.s[cpsInit], ropef("NIM_profilingStart = getticks();$n")) - app(generatedProc, p.s[cpsInit]) - app(generatedProc, p.s[cpsStmts]) + prepend(p.s(cpsInit), ropef("NIM_profilingStart = getticks();$n")) + app(generatedProc, p.s(cpsInit)) + app(generatedProc, p.s(cpsStmts)) if p.beforeRetNeeded: appf(generatedProc, "BeforeRet: $n;") app(generatedProc, deinitGCFrame(p)) if optStackTrace in prc.options: app(generatedProc, deinitFrame(p)) @@ -858,8 +858,8 @@ proc genInitCode(m: BModule) = app(prc, initGCFrame(m.initProc)) app(prc, genSectionStart(cpsLocals)) - app(prc, m.initProc.s[cpsLocals]) - app(prc, m.preInitProc.s[cpsLocals]) + app(prc, m.initProc.s(cpsLocals)) + app(prc, m.preInitProc.s(cpsLocals)) app(prc, genSectionEnd(cpsLocals)) app(prc, genSectionStart(cfsTypeInit1)) @@ -876,13 +876,13 @@ proc genInitCode(m: BModule) = app(prc, genSectionEnd(i)) app(prc, genSectionStart(cpsInit)) - app(prc, m.preInitProc.s[cpsInit]) - app(prc, m.initProc.s[cpsInit]) + app(prc, m.preInitProc.s(cpsInit)) + app(prc, m.initProc.s(cpsInit)) app(prc, genSectionEnd(cpsInit)) app(prc, genSectionStart(cpsStmts)) - app(prc, m.preInitProc.s[cpsStmts]) - app(prc, m.initProc.s[cpsStmts]) + app(prc, m.preInitProc.s(cpsStmts)) + app(prc, m.initProc.s(cpsStmts)) if optStackTrace in m.initProc.options and not m.PreventStackTrace: app(prc, deinitFrame(m.initProc)) app(prc, genSectionEnd(cpsStmts)) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index fafccce187..8b263b696e 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -48,13 +48,14 @@ type TCProcSections* = array[TCProcSection, PRope] # represents a generated C proc BModule* = ref TCGen BProc* = ref TCProc - TBlock{.final.} = object + TBlock*{.final.} = object id*: int # the ID of the label; positive means that it - # has been used (i.e. the label should be emitted) + label*: PRope # generated text for the label + # nil if label is not used nestedTryStmts*: int # how many try statements is it nested into + sections*: TCProcSections # the code beloging TCProc{.final.} = object # represents C proc that is currently generated - s*: TCProcSections # the procs sections; short name for readability prc*: PSym # the Nimrod proc that this C proc belongs to BeforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed ThreadVarAccessed*: bool # true if the proc already accessed some threadvar @@ -113,6 +114,8 @@ var gForwardedProcsCounter*: int = 0 gNimDat*: BModule # generated global data +proc s*(prc: BProc, s: TCProcSection): var PRope {.inline.} = + result = prc.blocks[prc.blocks.len - 1].sections[s] proc newProc*(prc: PSym, module: BModule): BProc = new(result) @@ -120,6 +123,6 @@ proc newProc*(prc: PSym, module: BModule): BProc = result.module = module if prc != nil: result.options = prc.options else: result.options = gOptions - result.blocks = @[] + newSeq(result.blocks, 1) result.nestedTryStmts = @[] From caf78780096c157560f50cf0a4958fdf07d09a7d Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 12 Apr 2012 15:07:42 +0300 Subject: [PATCH 2/9] Proper C scopes for if, try and case statements even thought the setjmp implementation for try statement won't be used in C++, using properly scoped variables for them is beneficial, because we'll be able to establish a 1:1 relation between nimrod scopes and C scopes. Once we have that, we'll be able to keep the original names of local variables to greatly improve the debugging experience (i.e. watch expressions and hover tooltips will work). --- compiler/ccgstmts.nim | 172 +++++++++++++++++++++++------------------- compiler/cgendata.nim | 2 + lib/system.nim | 12 +-- 3 files changed, 103 insertions(+), 83 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 20c0e5566a..8b624fd235 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -47,6 +47,51 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} = else: expr(p, ri, a) +proc startBlock(p: BProc, start: TFormatStr = "{$n", + args: openarray[PRope]): int {.discardable.} = + inc(p.labels) + result = len(p.blocks) + setlen(p.blocks, result + 1) + p.blocks[result].id = p.labels + p.blocks[result].nestedTryStmts = p.nestedTryStmts.len + appcg(p, cpsLocals, start, args) + +proc assignLabel(b: var TBlock): PRope {.inline.} = + b.label = con("LA", b.id.toRope) + result = b.label + +proc blockBody(b: var TBlock): PRope {.inline.} = + return b.sections[cpsLocals].con(b.sections[cpsInit]).con(b.sections[cpsStmts]) + +proc endBlock(p: BProc, blockEnd: PRope) = + let topBlock = p.blocks.len - 1 + # the block is merged into the parent block + app(p.blocks[topBlock - 1].sections[cpsStmts], p.blocks[topBlock].blockBody) + setlen(p.blocks, topBlock) + # this is done after the block is popped so $n is + # properly indented when pretty printing is enabled + app(p.s(cpsStmts), blockEnd) + +var gBlockEndBracket = ropef("}$n") + +proc endBlock(p: BProc) = + let topBlock = p.blocks.len - 1 + let blockEnd = if p.blocks[topBlock].label != nil: + ropef("} $1: ;$n", [p.blocks[topBlock].label]) + else: + gBlockEndBracket + endBlock(p, blockEnd) + +proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} = + startBlock(p) + genStmts(p, stmts) + endBlock(p) + +template preserveBreakIdx(body: stmt): stmt = + var oldBreakIdx = p.breakIdx + body + p.breakIdx = oldBreakIdx + proc genSingleVar(p: BProc, a: PNode) = var v = a.sons[0].sym if sfCompileTime in v.flags: return @@ -110,17 +155,15 @@ proc genConstStmt(p: BProc, t: PNode) = proc genIfStmt(p: BProc, n: PNode) = # # if (!expr1) goto L1; - # thenPart + # { thenPart } # goto LEnd # L1: # if (!expr2) goto L2; - # thenPart2 + # { thenPart2 } # goto LEnd # L2: - # elsePart + # { elsePart } # Lend: - # - ## XXX: push blocks here var a: TLoc Lelse: TLabel @@ -136,12 +179,12 @@ proc genIfStmt(p: BProc, n: PNode) = appff(p.s(cpsStmts), "if (!$1) goto $2;$n", "br i1 $1, label %LOC$3, label %$2$n" & "LOC$3: $n", [rdLoc(a), Lelse, toRope(p.labels)]) - genStmts(p, it.sons[1]) + genSimpleBlock(p, it.sons[1]) if sonsLen(n) > 1: appff(p.s(cpsStmts), "goto $1;$n", "br label %$1$n", [Lend]) fixLabel(p, Lelse) - of nkElse: - genStmts(p, it.sons[0]) + of nkElse: + genSimpleBlock(p, it.sons[0]) else: internalError(n.info, "genIfStmt()") if sonsLen(n) > 1: fixLabel(p, Lend) @@ -171,36 +214,6 @@ proc genReturnStmt(p: BProc, t: PNode) = if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0]) blockLeaveActions(p, min(1, p.nestedTryStmts.len)) appff(p.s(cpsStmts), "goto BeforeRet;$n", "br label %BeforeRet$n", []) - -proc startBlock(p: BProc, start = "{$n"): int = - inc(p.labels) - result = len(p.blocks) - setlen(p.blocks, result + 1) - p.blocks[result].id = p.labels - p.blocks[result].nestedTryStmts = p.nestedTryStmts.len - appf(p.s(cpsStmts), start) - -proc assignLabel(b: var TBlock): PRope {.inline.} = - b.label = con("LA", b.id.toRope) - result = b.label - -proc blockBody(b: var TBlock): PRope {.inline.} = - result = b.sections[cpsLocals].con(b.sections[cpsInit]).con(b.sections[cpsStmts]) - -var gBlockEndBracket = ropef("}$n") - -proc endBlock(p: BProc) = - let topBlock = p.blocks.len - 1 - let blockEnd = if p.blocks[topBlock].label != nil: - ropef("} $1: ;$n", [p.blocks[topBlock].label]) - else: - gBlockEndBracket - # the block is merged into the parent block - app(p.blocks[topBlock - 1].sections[cpsStmts], p.blocks[topBlock].blockBody) - setlen(p.blocks, topBlock) - # this is done after the block is popped so $n is - # properly indented when pretty printing is enabled - app(p.s(cpsStmts), blockEnd) proc genWhileStmt(p: BProc, t: PNode) = # we don't generate labels here as for example GCC would produce @@ -211,31 +224,33 @@ proc genWhileStmt(p: BProc, t: PNode) = assert(sonsLen(t) == 2) inc(p.withinLoop) genLineDir(p, t) - - var blockIdx = startBlock(p, "while (1) {$n") - initLocExpr(p, t.sons[0], a) - if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0): - let label = assignLabel(p.blocks[blockIdx]) - appf(p.s(cpsStmts), "if (!$1) goto $2;$n", [rdLoc(a), label]) - genStmts(p, t.sons[1]) - endBlock(p) + + preserveBreakIdx: + p.breakIdx = startBlock(p, "while (1) {$n") + initLocExpr(p, t.sons[0], a) + if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0): + let label = assignLabel(p.blocks[p.breakIdx]) + appf(p.s(cpsStmts), "if (!$1) goto $2;$n", [rdLoc(a), label]) + genStmts(p, t.sons[1]) + endBlock(p) dec(p.withinLoop) -proc genBlock(p: BProc, t: PNode, d: var TLoc) = - var idx = startBlock(p) - if t.sons[0].kind != nkEmpty: - # named block? - assert(t.sons[0].kind == nkSym) - var sym = t.sons[0].sym - sym.loc.k = locOther - sym.loc.a = idx - if t.kind == nkBlockExpr: genStmtListExpr(p, t.sons[1], d) - else: genStmts(p, t.sons[1]) - endBlock(p) - +proc genBlock(p: BProc, t: PNode, d: var TLoc) = + preserveBreakIdx: + p.breakIdx = startBlock(p) + if t.sons[0].kind != nkEmpty: + # named block? + assert(t.sons[0].kind == nkSym) + var sym = t.sons[0].sym + sym.loc.k = locOther + sym.loc.a = p.breakIdx + if t.kind == nkBlockExpr: genStmtListExpr(p, t.sons[1], d) + else: genStmts(p, t.sons[1]) + endBlock(p) + proc genBreakStmt(p: BProc, t: PNode) = - var idx = len(p.blocks) - 1 + var idx = p.breakIdx if t.sons[0].kind != nkEmpty: # named break? assert(t.sons[0].kind == nkSym) @@ -290,10 +305,10 @@ proc genCaseSecondPass(p: BProc, t: PNode, labId, until: int): TLabel = appf(p.s(cpsStmts), "LA$1: ;$n", [toRope(labId + i)]) if t.sons[i].kind == nkOfBranch: var length = sonsLen(t.sons[i]) - genStmts(p, t.sons[i].sons[length - 1]) + genSimpleBlock(p, t.sons[i].sons[length - 1]) appf(p.s(cpsStmts), "goto $1;$n", [Lend]) else: - genStmts(p, t.sons[i].sons[0]) + genSimpleBlock(p, t.sons[i].sons[0]) result = Lend proc genIfForCaseUntil(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr, @@ -428,11 +443,11 @@ proc genOrdinalCase(p: BProc, n: PNode) = var branch = n[i] if branch.kind == nkOfBranch: genCaseRange(p, branch) - genStmts(p, branch.lastSon) + genSimpleBlock(p, branch.lastSon) else: # else part of case statement: appf(p.s(cpsStmts), "default:$n") - genStmts(p, branch[0]) + genSimpleBlock(p, branch[0]) hasDefault = true appf(p.s(cpsStmts), "break;$n") if (hasAssume in CC[ccompiler].props) and not hasDefault: @@ -484,6 +499,8 @@ proc genTryStmtCpp(p: BProc, t: PNode) = # excHandler = excHandler->prev; // we handled the exception # finallyPart(); # if (tmpRethrow) throw; + # + # XXX: push blocks var rethrowFlag: PRope exc: PRope @@ -529,7 +546,7 @@ proc genTryStmtCpp(p: BProc, t: PNode) = genStmts(p, t.sons[i].sons[0]) if rethrowFlag != nil: appf(p.s(cpsStmts), "if ($1) { throw; }$n", [rethrowFlag]) - + proc genTryStmt(p: BProc, t: PNode) = # code to generate: # @@ -549,12 +566,13 @@ proc genTryStmt(p: BProc, t: PNode) = # clearException(); # } # } - # /* finally: */ - # printf('fin!\n'); + # { + # /* finally: */ + # printf('fin!\n'); + # } # if (exception not cleared) # propagateCurrentException(); # - # XXX: push blocks here genLineDir(p, t) var safePoint = getTempName() discard cgsym(p.module, "E_Base") @@ -563,24 +581,25 @@ proc genTryStmt(p: BProc, t: PNode) = "$1.status = setjmp($1.context);$n", [safePoint]) if optStackTrace in p.Options: appcg(p, cpsStmts, "#setFrame((TFrame*)&F);$n") - appf(p.s(cpsStmts), "if ($1.status == 0) {$n", [safePoint]) + startBlock(p, "if ($1.status == 0) {$n", [safePoint]) var length = sonsLen(t) add(p.nestedTryStmts, t) genStmts(p, t.sons[0]) - appcg(p, cpsStmts, "#popSafePoint();$n} else {$n#popSafePoint();$n") + endBlock(p, ropecg(p.module, "#popSafePoint();$n } else {$n#popSafePoint();$n")) discard pop(p.nestedTryStmts) var i = 1 while (i < length) and (t.sons[i].kind == nkExceptBranch): var blen = sonsLen(t.sons[i]) if blen == 1: # general except section: - if i > 1: appf(p.s(cpsStmts), "else {$n") + if i > 1: appf(p.s(cpsStmts), "else") + startBlock(p) appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint]) inc p.popCurrExc genStmts(p, t.sons[i].sons[0]) dec p.popCurrExc appcg(p, cpsStmts, "#popCurrentException();$n", []) - if i > 1: appf(p.s(cpsStmts), "}$n") + endBlock(p) else: inc p.popCurrExc var orExpr: PRope = nil @@ -591,16 +610,15 @@ proc genTryStmt(p: BProc, t: PNode) = "#isObj(#getCurrentException()->Sup.m_type, $1)", [genTypeInfo(p.module, t.sons[i].sons[j].typ)]) if i > 1: app(p.s(cpsStmts), "else ") - appf(p.s(cpsStmts), "if ($1) {$n", [orExpr]) + startBlock(p, "if ($1) {$n", [orExpr]) appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint]) genStmts(p, t.sons[i].sons[blen-1]) dec p.popCurrExc - # code to clear the exception: - appcg(p, cpsStmts, "#popCurrentException();}$n", []) + endBlock(p, ropecg(p.module, "#popCurrentException();}$n")) inc(i) - appf(p.s(cpsStmts), "}$n") # end of if statement - if i < length and t.sons[i].kind == nkFinally: - genStmts(p, t.sons[i].sons[0]) + appf(p.s(cpsStmts), "}$n") # end of else block + if i < length and t.sons[i].kind == nkFinally: + genSimpleBlock(p, t.sons[i].sons[0]) appcg(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint]) proc genAsmOrEmitStmt(p: BProc, t: PNode): PRope = diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 8b263b696e..43aaf70686 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -65,6 +65,8 @@ type # before 'break'|'return' labels*: Natural # for generating unique labels in the C proc blocks*: seq[TBlock] # nested blocks + breakIdx*: int # the block that will be exited + # with a regular break options*: TOptions # options that should be used for code # generation; this is the same as prc.options # unless prc == nil diff --git a/lib/system.nim b/lib/system.nim index 91b43432c6..9a00979d50 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -1593,12 +1593,12 @@ proc echo*[Ty](x: openarray[Ty]) {.magic: "Echo", noSideEffect.} template newException*(exceptn: typeDesc, message: string): expr = ## creates an exception object of type ``exceptn`` and sets its ``msg`` field ## to `message`. Returns the new exception object. - block: # open a new scope - var - e: ref exceptn - new(e) - e.msg = message - e + # block: # open a new scope + var + e: ref exceptn + new(e) + e.msg = message + e when not defined(EcmaScript) and not defined(NimrodVM): {.push stack_trace: off.} From f25c638dc4109445ce1476d6e6f18be034805a0a Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Fri, 13 Apr 2012 16:01:26 +0300 Subject: [PATCH 3/9] experimental support for preserving local variable names in the generated code --- compiler/ast.nim | 28 ++++++++++------- compiler/ccgtypes.nim | 70 +++++++++++++++++++++++++++++++++++++++++-- compiler/options.nim | 4 ++- compiler/semgnrc.nim | 2 ++ compiler/semstmts.nim | 12 +++++++- compiler/wordrecg.nim | 52 +++++++++++++++++++++++++++----- 6 files changed, 146 insertions(+), 22 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index c6a2b32e7e..10a3d80394 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -244,12 +244,17 @@ const sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher sfNoInit* = sfMainModule # don't generate code to init the variable - sfImmediate* = sfDeadCodeElim # macro or template is immediately expanded - # without considering any possible overloads + sfImmediate* = sfDeadCodeElim + # macro or template is immediately expanded + # without considering any possible overloads - sfAnon* = sfCompilerProc # symbol name that was generated by the compiler - # the compiler will avoid printing such names - # in user messages. + sfAnon* = sfDiscardable + # symbol name that was generated by the compiler + # the compiler will avoid printing such names + # in user messages. + + sfShadowed* = sfInnerProc + # a variable that was shadowed in some inner scope const # getting ready for the future expr/stmt merge @@ -647,6 +652,14 @@ const resultPos* = 5 dispatcherPos* = 6 # caution: if method has no 'result' it can be position 5! + nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix, + nkCommand, nkCallStrLit} + + nkLambdaKinds* = {nkLambda, nkDo} + + skLocalVars* = {skVar, skLet, skForVar, skParam} + + # creator procs: proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym): PSym proc NewType*(kind: TTypeKind, owner: PSym): PType @@ -691,11 +704,6 @@ proc copyNode*(src: PNode): PNode proc copyTree*(src: PNode): PNode # does copy its sons! -const nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, - nkCallStrLit} - -const nkLambdaKinds* = {nkLambda, nkDo} - proc isCallExpr*(n: PNode): bool = result = n.kind in nkCallKinds diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 6195ff2f48..3578b1f5ec 100755 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -32,6 +32,15 @@ proc mangle(name: string): string = add(result, "HEX") add(result, toHex(ord(name[i]), 2)) +proc isCKeyword(w: PIdent): bool = + # nimrod and C++ share some keywords + # it's more efficient to test the whole nimrod keywords range + case w.id + of cppKeywordsLow..cppKeywordsHigh, + nimKeywordsLow..nimKeywordsHigh, + ord(wInline): return true + else: return false + proc mangleName(s: PSym): PRope = result = s.loc.r if result == nil: @@ -45,9 +54,64 @@ proc mangleName(s: PSym): PRope = of skTemp, skParam, skType, skEnumField, skModule: result = toRope("%") else: InternalError(s.info, "mangleName") - app(result, toRope(mangle(s.name.s))) - app(result, "_") - app(result, toRope(s.id)) + when oKeepVariableNames: + let keepOrigName = s.kind in skLocalVars - {skForVar} and + {sfFromGeneric, sfGlobal, sfShadowed} * s.flags == {} and + not isCKeyword(s.name) + # XXX: This is still very experimental + # + # Even with all these inefficient checks, the bootstrap + # time is actually improved. This is probably because so many + # rope concatenations and are now eliminated. + # + # Future notes: + # sfFromGeneric seems to be needed in order to avoid multiple + # definitions of certain varialbes generated in transf with + # names such as: + # `r`, `res` + # I need to study where these come from. + # + # about sfShadowed: + # consider the following nimrod code: + # var x = 10 + # block: + # var x = something(x) + # The generated C code will be: + # NI x; + # x = 10; + # { + # NI x; + # x = something(x); // Oops, x is already shadowed here + # } + # Right now, we work-around by not keeping the original name + # of the shadowed variable, but we can do better - we can + # create an alternative reference to it in the outer scope and + # use that in the inner scope. + # + # about isCKeyword: + # nimrod variable names can be C keywords. + # We need to avoid such names in the generated code. + # XXX: Study whether mangleName is called just once per variable. + # Otherwise, there might be better place to do this. + # + # about sfGlobal: + # This seems to be harder - a top level extern variable from + # another modules can have the same name as a local one. + # Maybe we should just implement sfShadowed for them too. + # + # about skForVar: + # These are not properly scoped now - we need to add blocks + # around for loops in transf + if keepOrigName: + result = s.name.s.toRope + else: + app(result, toRope(mangle(s.name.s))) + app(result, "_") + app(result, toRope(s.id)) + else: + app(result, toRope(mangle(s.name.s))) + app(result, "_") + app(result, toRope(s.id)) s.loc.r = result proc isCompileTimeOnly(t: PType): bool = diff --git a/compiler/options.nim b/compiler/options.nim index 0d7763be07..3a2352c7f1 100755 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -113,7 +113,9 @@ var gKeepComments*: bool = true # whether the parser needs to keep comments implicitImports*: seq[string] = @[] # modules that are to be implicitly imported implicitIncludes*: seq[string] = @[] # modules that are to be implicitly included - + +const oKeepVariableNames* = true + proc mainCommandArg*: string = ## This is intended for commands like check or parse ## which will work on the main project file unless diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 6a1c2f5294..d8f017c4c5 100755 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -15,6 +15,8 @@ # So we have to eval templates/macros right here so that symbol # lookup can be accurate. +# included from sem.nim + type TSemGenericFlag = enum withinBind, withinTypeDesc diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 0449c56448..d729a691fe 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -216,7 +216,14 @@ proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode = result = result.sons[1] elif not sameType(result.typ, typ): changeType(result, typ) - + +proc findShadowedVar(c: PContext, v: PSym): PSym = + for i in countdown(c.tab.tos - 2, 0): + let shadowed = StrTableGet(c.tab.stack[i], v.name) + if shadowed != nil: + if shadowed.kind in skLocalVars: + return shadowed + proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = if isTopLevel(c): result = semIdentWithPragma(c, kind, n, {sfExported}) @@ -267,6 +274,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = for j in countup(0, length-3): var v = semIdentDef(c, a.sons[j], symkind) addInterfaceDecl(c, v) + when oKeepVariableNames: + let shadowed = findShadowedVar(c, v) + if shadowed != nil: shadowed.flags.incl(sfShadowed) if def != nil and def.kind != nkEmpty: # this is only needed for the evaluation pass: v.ast = def diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index f96ba7751b..3ae9f7be91 100755 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -38,8 +38,8 @@ type wMagic, wThread, wFinal, wProfiler, wObjChecks, wImmediate, wImportCpp, wImportObjC, wImportCompilerProc, - wImportc, wExportc, wExtern, wIncompleteStruct, - wAlign, wNodecl, wPure, wVolatile, wRegister, wSideeffect, wHeader, + wImportc, wExportc, wIncompleteStruct, + wAlign, wNodecl, wPure, wSideeffect, wHeader, wNosideeffect, wNoreturn, wMerge, wLib, wDynlib, wCompilerproc, wProcVar, wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef, wLinedir, wStacktrace, wLinetrace, wLink, wCompile, @@ -58,13 +58,36 @@ type wWatchPoint, wSubsChar, wAcyclic, wShallow, wUnroll, wLinearScanEnd, wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wNoStackFrame, - wImplicitStatic, wGlobal + wImplicitStatic, wGlobal, + + wAuto, wBool, wCatch, wChar, wClass, + wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast, + wExplicit, wExtern, wFalse, wFloat, wFriend, + wGoto, wInt, wLong, wMutable, wNamespace, wNew, wOperator, + wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast, + wShort, wSigned, wSizeof, wStatic_cast, wStruct, wSwitch, + wThis, wThrow, wTrue, wTypedef, wTypeid, wTypename, + wUnion, wUnsigned, wUsing, wVirtual, wVoid, wVolatile, wWchar_t, + + wAlignas, wAlignof, wConstexpr, wDecltype, wNullptr, wNoexcept, + wThread_local, wStatic_assert, wChar16_t, wChar32_t, TSpecialWords* = set[TSpecialWord] const oprLow* = ord(wColon) oprHigh* = ord(wDotDot) + + nimKeywordsLow* = ord(wAsm) + nimKeywordsHigh* = ord(wYield) + + cppKeywordsLow* = ord(wAuto) + cppKeywordsHigh* = ord(wChar32_t) + + cppNimSharedKeywords* = { + wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport, + wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile } + specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["", "addr", "and", "as", "asm", "atomic", @@ -86,14 +109,14 @@ const "magic", "thread", "final", "profiler", "objchecks", "immediate", "importcpp", "importobjc", - "importcompilerproc", "importc", "exportc", "extern", "incompletestruct", - "align", "nodecl", "pure", "volatile", "register", "sideeffect", + "importcompilerproc", "importc", "exportc", "incompletestruct", + "align", "nodecl", "pure", "sideeffect", "header", "nosideeffect", "noreturn", "merge", "lib", "dynlib", "compilerproc", "procvar", "fatal", "error", "warning", "hint", "line", "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace", "link", "compile", "linksys", "deprecated", "varargs", "byref", "callconv", "breakpoint", "debugger", "nimcall", "stdcall", - "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure", + "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure", "noconv", "on", "off", "checks", "rangechecks", "boundchecks", "overflowchecks", "nilchecks", "floatchecks", "nanchecks", "infchecks", @@ -107,7 +130,22 @@ const "watchpoint", "subschar", "acyclic", "shallow", "unroll", "linearscanend", "write", "putenv", "prependenv", "appendenv", "threadvar", "emit", - "nostackframe", "implicitstatic", "global"] + "nostackframe", "implicitstatic", "global", + + "auto", "bool", "catch", "char", "class", + "const_cast", "default", "delete", "double", + "dynamic_cast", "explicit", "extern", "false", + "float", "friend", "goto", "int", "long", "mutable", + "namespace", "new", "operator", + "private", "protected", "public", "register", "reinterpret_cast", + "short", "signed", "sizeof", "static_cast", "struct", "switch", + "this", "throw", "true", "typedef", "typeid", + "typename", "union", "unsigned", "using", "virtual", "void", "volatile", + "wchar_t", + + "alignas", "alignof", "constexpr", "decltype", "nullptr", "noexcept", + "thread_local", "static_assert", "char16_t", "char32_t", + ] proc findStr*(a: openarray[string], s: string): int = for i in countup(low(a), high(a)): From 42e0b082144a2c03ef18e0cabc372c90f1753148 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sat, 14 Apr 2012 13:26:47 +0300 Subject: [PATCH 4/9] fix the usage of definedInScope in pegs.=~ template `=~`*(s: string, pattern: TPeg): bool = when not definedInScope(matches): var matches: array[0..maxSubpatterns-1, string] It seems that this never worked as intended. I discovered it now, because when variables' names are preserved, multiple variables named `matches` were created. The reason this happens is that when the template is used as an if condition, the if scope is already entered, but the variables end up in the outer scope. This patch is consistent with how `expr` templates work, but makes the definition of a variable injection template like := a bit harder, yet still possible. (note that if foo := bar(): is still not creating properly scoped variable prior to the patch) --- compiler/semstmts.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index d729a691fe..e7051231bc 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -50,8 +50,8 @@ proc semIf(c: PContext, n: PNode): PNode = case it.kind of nkElifBranch: checkSonsLen(it, 2) - openScope(c.tab) it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0])) + openScope(c.tab) it.sons[1] = semStmt(c, it.sons[1]) closeScope(c.tab) of nkElse: From 567b5b07ea4d7400b4e24822f6d4d6328e9bd2ec Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 15 Apr 2012 00:38:57 +0300 Subject: [PATCH 5/9] fixes #20 properly --- compiler/ccgcalls.nim | 3 --- compiler/ccgstmts.nim | 10 +++++++- compiler/cgen.nim | 56 +++++++++++++++++++------------------------ compiler/semstmts.nim | 5 ++-- 4 files changed, 36 insertions(+), 38 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index c1ad8614f8..f2fa6a2808 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -18,9 +18,6 @@ proc leftAppearsOnRightSide(le, ri: PNode): bool = proc hasNoInit(call: PNode): bool {.inline.} = result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags -proc resetLoc(p: BProc, d: var TLoc) = - zeroVar(p, d, containsGarbageCollectedRef(d.t)) - proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) = var pl = pl var typ = ri.sons[0].typ # getUniqueType() is too expensive here! diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 8b624fd235..9fd27bfeb8 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -101,7 +101,15 @@ proc genSingleVar(p: BProc, a: PNode) = if v.owner.kind != skModule: targetProc = p.module.preInitProc assignGlobalVar(targetProc, v) - genObjectInit(targetProc, cpsInit, v.typ, v.loc, true) + # XXX: be careful here. + # Global variables should not be zeromem-ed within loops + # (see bug #20). + # That's why we are doing the construction inside the preInitProc. + # genObjectInit relies on the C runtime's guarantees that + # global variables will be initialized to zero. + genObjectInit(p.module.preInitProc, cpsInit, v.typ, v.loc, true) + # Alternative construction using default constructor (which may zeromem): + # if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc) else: assignLocalVar(p, v) initLocalVar(p, v, immediateAsgn) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index acaa785f8c..e8073b5557 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -229,45 +229,37 @@ proc isComplexValueType(t: PType): bool {.inline.} = result = t.kind in {tyArray, tyArrayConstr, tySet, tyTuple, tyObject} or (t.kind == tyProc and t.callConv == ccClosure) -proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) = +proc resetLoc(p: BProc, loc: var TLoc) = + let containsGcRef = containsGarbageCollectedRef(loc.t) if not isComplexValueType(skipTypes(loc.t, abstractVarRange)): - if containsGcref and p.WithInLoop > 0: - appf(p.s(cpsInit), "$1 = 0;$n", [rdLoc(loc)]) + if containsGcRef: var nilLoc: TLoc initLoc(nilLoc, locTemp, loc.t, onStack) nilLoc.r = toRope("NIM_NIL") - # puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``: genRefAssign(p, loc, nilLoc, {afSrcIsNil}) else: appf(p.s(cpsStmts), "$1 = 0;$n", [rdLoc(loc)]) else: - if containsGcref and p.WithInLoop > 0: - appf(p.s(cpsInit), "memset((void*)$1, 0, sizeof($2));$n", - [addrLoc(loc), rdLoc(loc)]) - genObjectInit(p, cpsInit, loc.t, loc, true) - appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", - [addrLoc(loc), genTypeInfo(p.module, loc.t)]) + if loc.s != OnStack: + appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", + [addrLoc(loc), genTypeInfo(p.module, loc.t)]) + # XXX: generated reset procs should not touch the m_type + # field, so disabling this should be safe: + genObjectInit(p, cpsStmts, loc.t, loc, true) else: - appf(p.s(cpsStmts), "memset((void*)$1, 0, sizeof($2));$n", - [addrLoc(loc), rdLoc(loc)]) + appf(p.s(cpsStmts), "memset((void*)$1, 0, sizeof($2));$n", + [addrLoc(loc), rdLoc(loc)]) + # XXX: We can be extra clever here and call memset only + # on the bytes following the m_type field? genObjectInit(p, cpsStmts, loc.t, loc, true) -proc zeroTemp(p: BProc, loc: TLoc) = +proc constructLoc(p: BProc, loc: TLoc, section = cpsStmts) = if not isComplexValueType(skipTypes(loc.t, abstractVarRange)): - appf(p.s(cpsStmts), "$1 = 0;$n", [rdLoc(loc)]) - when false: - var nilLoc: TLoc - initLoc(nilLoc, locTemp, loc.t, onStack) - nilLoc.r = toRope("NIM_NIL") - # puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``: - genRefAssign(p, loc, nilLoc, {afSrcIsNil}) + appf(p.s(section), "$1 = 0;$n", [rdLoc(loc)]) else: - appf(p.s(cpsStmts), "memset((void*)$1, 0, sizeof($2));$n", - [addrLoc(loc), rdLoc(loc)]) - # XXX no object init necessary for temporaries? - when false: - appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", - [addrLoc(loc), genTypeInfo(p.module, loc.t)]) + appf(p.s(section), "memset((void*)$1, 0, sizeof($2));$n", + [addrLoc(loc), rdLoc(loc)]) + genObjectInit(p, section, loc.t, loc, true) proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = if sfNoInit notin v.flags: @@ -279,11 +271,13 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = # ``var v = X()`` gets transformed into ``X(&v)``. # Nowadays the logic in ccgcalls deals with this case however. if not immediateAsgn: - zeroVar(p, v.loc, containsGarbageCollectedRef(v.typ)) - -proc initTemp(p: BProc, tmp: var TLoc) = + constructLoc(p, v.loc) + +proc initTemp(p: BProc, tmp: var TLoc) = + # XXX: This is still suspicious. + # Objects should always be constructed? if containsGarbageCollectedRef(tmp.t) or isInvalidReturnType(tmp.t): - zeroTemp(p, tmp) + constructLoc(p, tmp) proc getTemp(p: BProc, t: PType, result: var TLoc) = inc(p.labels) @@ -410,7 +404,7 @@ proc assignGlobalVar(p: BProc, s: PSym) = appf(p.module.s[cfsVars], " $1;$n", [s.loc.r]) if p.withinLoop > 0: # fixes tests/run/tzeroarray: - initLocalVar(p, s, false) + resetLoc(p, s.loc) if p.module.module.options * {optStackTrace, optEndb} == {optStackTrace, optEndb}: appcg(p.module, p.module.s[cfsDebugInit], diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index e7051231bc..b9b418c985 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -220,9 +220,8 @@ proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode = proc findShadowedVar(c: PContext, v: PSym): PSym = for i in countdown(c.tab.tos - 2, 0): let shadowed = StrTableGet(c.tab.stack[i], v.name) - if shadowed != nil: - if shadowed.kind in skLocalVars: - return shadowed + if shadowed != nil and shadowed.kind in skLocalVars: + return shadowed proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = if isTopLevel(c): From 20d56875de743d23988a2b0d6a17709e899881c9 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 15 Apr 2012 02:52:09 +0300 Subject: [PATCH 6/9] fix threading tests --- compiler/ccgthreadvars.nim | 5 +++-- compiler/cgendata.nim | 9 +++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index 94c34d13c1..38c5c0f5e3 100755 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -19,8 +19,9 @@ proc AccessThreadLocalVar(p: BProc, s: PSym) = if emulatedThreadVars() and not p.ThreadVarAccessed: p.ThreadVarAccessed = true p.module.usesThreadVars = true - appf(p.s(cpsLocals), "NimThreadVars* NimTV;$n") - appcg(p, cpsInit, "NimTV=(NimThreadVars*)#GetThreadLocalVars();$n") + appf(p.procSec(cpsLocals), "NimThreadVars* NimTV;$n") + app(p.procSec(cpsInit), + ropecg(p.module, "NimTV=(NimThreadVars*)#GetThreadLocalVars();$n")) var nimtv: PRope # nimrod thread vars; the struct body diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 43aaf70686..f1463bbdcf 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -116,8 +116,13 @@ var gForwardedProcsCounter*: int = 0 gNimDat*: BModule # generated global data -proc s*(prc: BProc, s: TCProcSection): var PRope {.inline.} = - result = prc.blocks[prc.blocks.len - 1].sections[s] +proc s*(p: BProc, s: TCProcSection): var PRope {.inline.} = + # section in the current block + result = p.blocks[p.blocks.len - 1].sections[s] + +proc procSec*(p: BProc, s: TCProcSection): var PRope {.inline.} = + # top level proc sections + result = p.blocks[0].sections[s] proc newProc*(prc: PSym, module: BModule): BProc = new(result) From 57fe3e8c41c6c046b2ad91ea382ce7c31061f04d Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 15 Apr 2012 02:53:32 +0300 Subject: [PATCH 7/9] avoid duplicated variable names in unrolled loops --- compiler/semdata.nim | 1 + compiler/semstmts.nim | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 80aed2fd4f..f97da4717a 100755 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -62,6 +62,7 @@ type AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot # store this info in the syms themselves!) InGenericContext*: int # > 0 if we are in a generic + InUnrolledContext*: int # > 0 if we are unrolling a loop converters*: TSymSeq # sequence of converters optionStack*: TLinkedList libs*: TLinkedList # all libs used by this module diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index b9b418c985..9e879ad0be 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -274,8 +274,10 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var v = semIdentDef(c, a.sons[j], symkind) addInterfaceDecl(c, v) when oKeepVariableNames: - let shadowed = findShadowedVar(c, v) - if shadowed != nil: shadowed.flags.incl(sfShadowed) + if c.InUnrolledContext > 0: v.flags.incl(sfShadowed) + else: + let shadowed = findShadowedVar(c, v) + if shadowed != nil: shadowed.flags.incl(sfShadowed) if def != nil and def.kind != nkEmpty: # this is only needed for the evaluation pass: v.ast = def @@ -401,7 +403,9 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = openScope(c.tab) var body = transfFieldLoopBody(loopBody, n, tupleTypeA, i, ord(m==mFieldPairs)) + inc c.InUnrolledContext stmts.add(SemStmt(c, body)) + dec c.InUnrolledContext closeScope(c.tab) Dec(c.p.nestedLoopCounter) var b = newNodeI(nkBreakStmt, n.info) From 1ba31f8df73573e61154b37b51e11d357a8ff7fa Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 15 Apr 2012 02:54:12 +0300 Subject: [PATCH 8/9] minor changes to make the test suite green again --- lib/pure/colors.nim | 19 +++++++------------ lib/pure/pegs.nim | 1 - tests/run/tpegs.nim | 1 - 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index 00edaad9c7..9f824e5de2 100755 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -29,19 +29,14 @@ template colorOp(op: expr) {.immediate.} = extract(a, ar, ag, ab) extract(b, br, bg, bb) result = rawRGB(op(ar, br), op(ag, bg), op(ab, bb)) - -template satPlus(a, b: expr): expr = - # saturated plus: - block: - var result = a +% b - if result > 255: result = 255 - result -template satMinus(a, b: expr): expr = - block: - var result = a -% b - if result < 0: result = 0 - result +proc satPlus(a, b: int): int {.inline.} = + result = a +% b + if result > 255: result = 255 + +proc satMinus(a, b: int): int {.inline.} = + result = a -% b + if result < 0: result = 0 proc `+`*(a, b: TColor): TColor = ## adds two colors: This uses saturated artithmetic, so that each color diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index b5c72491c6..f4f347b46e 100755 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -1738,7 +1738,6 @@ when isMainModule: else: assert false - var matches: array[0..5, string] if match("abcdefg", peg"c {d} ef {g}", matches, 2): assert matches[0] == "d" assert matches[1] == "g" diff --git a/tests/run/tpegs.nim b/tests/run/tpegs.nim index 8fe3020735..0834d38a7c 100755 --- a/tests/run/tpegs.nim +++ b/tests/run/tpegs.nim @@ -1734,7 +1734,6 @@ when isMainModule: else: doAssert false - var matches: array[0..5, string] if match("abcdefg", peg"c {d} ef {g}", matches, 2): doAssert matches[0] == "d" doAssert matches[1] == "g" From 043a40eee6d33dec66a55c51123453c072e8d7be Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 15 Apr 2012 03:46:25 +0300 Subject: [PATCH 9/9] fix incorrect path for rodfile tests' nimcache --- tests/specials.nim | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/specials.nim b/tests/specials.nim index 3dc083f2e1..99e5c4c106 100644 --- a/tests/specials.nim +++ b/tests/specials.nim @@ -10,20 +10,21 @@ ## Include for the tester that contains test suites that test special features ## of the compiler. +# included from tester.nim # ---------------- ROD file tests --------------------------------------------- const rodfilesDir = "tests/rodfiles" + nimcacheDir = rodfilesDir / "nimcache" -proc delNimCache() = - let dir = rodfilesDir / "nimcache" +proc delNimCache() = try: - removeDir(dir) + removeDir(nimcacheDir) except EOS: - echo "[Warning] could not delete: ", dir + echo "[Warning] could not delete: ", nimcacheDir proc plusCache(options: string): string = return options & - " --symbolFiles:on --nimcache:./nimcache" + " --symbolFiles:on --nimcache:" & nimcacheDir proc runRodFiles(r: var TResults, options: string) = template test(filename: expr): stmt =