From b3c1fbaf139778e96e5249f32d103feebde546a0 Mon Sep 17 00:00:00 2001 From: metagn Date: Fri, 8 Nov 2024 16:28:52 +0300 Subject: [PATCH] adapt blocks in ccgstmts to cbuilder (#24416) This loses indents in codegen for now, another PR includes changes to add indents to `Builder` itself rather than tracking `TBlock`: #24418 --- compiler/cbuilderbase.nim | 6 + compiler/cbuilderexprs.nim | 3 + compiler/cbuilderstmts.nim | 122 +++++++++--- compiler/ccgstmts.nim | 382 ++++++++++++++++++++++++------------- compiler/cgen.nim | 19 +- compiler/cgendata.nim | 1 + 6 files changed, 373 insertions(+), 160 deletions(-) diff --git a/compiler/cbuilderbase.nim b/compiler/cbuilderbase.nim index a441d4d687ea..6be24495c648 100644 --- a/compiler/cbuilderbase.nim +++ b/compiler/cbuilderbase.nim @@ -88,3 +88,9 @@ proc cIntLiteral*(i: BiggestInt): Snippet = proc cIntLiteral*(i: Int128): Snippet = result = cIntLiteral(toInt64(i)) + +type + IfBuilderState* = enum + WaitingIf, WaitingElseIf, InBlock + IfBuilder* = object + state*: IfBuilderState diff --git a/compiler/cbuilderexprs.nim b/compiler/cbuilderexprs.nim index bd07f8bee925..b9083a3075c6 100644 --- a/compiler/cbuilderexprs.nim +++ b/compiler/cbuilderexprs.nim @@ -240,3 +240,6 @@ template cOp(binOp: UntypedUnaryOp, a: Snippet): Snippet = template cIfExpr(cond, a, b: Snippet): Snippet = # XXX used for `min` and `max`, maybe add nifc primitives for these "(" & cond & " ? " & a & " : " & b & ")" + +template cUnlikely(val: Snippet): Snippet = + "NIM_UNLIKELY(" & val & ")" diff --git a/compiler/cbuilderstmts.nim b/compiler/cbuilderstmts.nim index a402f042044b..98d655ce87a2 100644 --- a/compiler/cbuilderstmts.nim +++ b/compiler/cbuilderstmts.nim @@ -68,32 +68,49 @@ template addSingleIfStmtWithCond(builder: var Builder, condBody: typed, body: ty body builder.add("}\n") -type IfStmt = object - needsElse: bool +proc initIfStmt(builder: var Builder): IfBuilder = + IfBuilder(state: WaitingIf) -template addIfStmt(builder: var Builder, stmt: out IfStmt, body: typed) = - stmt = IfStmt(needsElse: false) - body +proc finishIfStmt(builder: var Builder, stmt: IfBuilder) = + assert stmt.state != InBlock builder.add("\n") -template addElifBranch(builder: var Builder, stmt: var IfStmt, cond: Snippet, body: typed) = - if stmt.needsElse: - builder.add(" else ") - else: - stmt.needsElse = true - builder.add("if (") +template addIfStmt(builder: var Builder, stmt: out IfBuilder, body: typed) = + stmt = initIfStmt(builder) + body + finishIfStmt(builder, stmt) + +proc initElifBranch(builder: var Builder, stmt: var IfBuilder, cond: Snippet) = + case stmt.state + of WaitingIf: + builder.add("if (") + of WaitingElseIf: + builder.add(" else if (") + else: assert false, $stmt.state builder.add(cond) builder.add(") {\n") - body - builder.add("}") + stmt.state = InBlock -template addElseBranch(builder: var Builder, stmt: var IfStmt, body: typed) = - assert stmt.needsElse +proc initElseBranch(builder: var Builder, stmt: var IfBuilder) = + assert stmt.state == WaitingElseIf, $stmt.state builder.add(" else {\n") - body + stmt.state = InBlock + +proc finishBranch(builder: var Builder, stmt: var IfBuilder) = builder.add("}") + stmt.state = WaitingElseIf + +template addElifBranch(builder: var Builder, stmt: var IfBuilder, cond: Snippet, body: typed) = + initElifBranch(builder, stmt, cond) + body + finishBranch(builder, stmt) -proc addForRangeHeader(builder: var Builder, i, start, bound: Snippet, inclusive: bool = false) = +template addElseBranch(builder: var Builder, stmt: var IfBuilder, body: typed) = + initElseBranch(builder, stmt) + body + finishBranch(builder, stmt) + +proc initForRange(builder: var Builder, i, start, bound: Snippet, inclusive: bool = false) = builder.add("for (") builder.add(i) builder.add(" = ") @@ -109,15 +126,36 @@ proc addForRangeHeader(builder: var Builder, i, start, bound: Snippet, inclusive builder.add(i) builder.add("++) {\n") +proc initForStep(builder: var Builder, i, start, bound, step: Snippet, inclusive: bool = false) = + builder.add("for (") + builder.add(i) + builder.add(" = ") + builder.add(start) + builder.add("; ") + builder.add(i) + if inclusive: + builder.add(" <= ") + else: + builder.add(" < ") + builder.add(bound) + builder.add("; ") + builder.add(i) + builder.add(" += ") + builder.add(step) + builder.add(") {\n") + +proc finishFor(builder: var Builder) {.inline.} = + builder.add("}\n") + template addForRangeExclusive(builder: var Builder, i, start, bound: Snippet, body: typed) = - addForRangeHeader(builder, i, start, bound, false) + initForRange(builder, i, start, bound, false) body - builder.add("}\n") + finishFor(builder) template addForRangeInclusive(builder: var Builder, i, start, bound: Snippet, body: typed) = - addForRangeHeader(builder, i, start, bound, true) + initForRange(builder, i, start, bound, true) body - builder.add("}\n") + finishFor(builder) template addSwitchStmt(builder: var Builder, val: Snippet, body: typed) = builder.add("switch (") @@ -174,10 +212,43 @@ template addSwitchElse(builder: var Builder, body: typed) = proc addBreak(builder: var Builder) = builder.add("break;\n") +type ScopeBuilder = object + inside: bool + +proc initScope(builder: var Builder): ScopeBuilder = + builder.add("{\n") + result = ScopeBuilder(inside: true) + +proc finishScope(builder: var Builder, scope: var ScopeBuilder) = + assert scope.inside, "scope not inited" + builder.add("}\n") + scope.inside = false + template addScope(builder: var Builder, body: typed) = - builder.add("{") + builder.add("{\n") body - builder.add("\t}") + builder.add("}\n") + +type WhileBuilder = object + inside: bool + +proc initWhileStmt(builder: var Builder, cond: Snippet): WhileBuilder = + builder.add("while (") + builder.add(cond) + builder.add(") {\n") + result = WhileBuilder(inside: true) + +proc finishWhileStmt(builder: var Builder, stmt: var WhileBuilder) = + assert stmt.inside, "while stmt not inited" + builder.add("}\n") + stmt.inside = false + +template addWhileStmt(builder: var Builder, cond: Snippet, body: typed) = + builder.add("while (") + builder.add(cond) + builder.add(") {\n") + body + builder.add("}\n") proc addLabel(builder: var Builder, name: TLabel) = builder.add(name) @@ -237,3 +308,8 @@ proc cInPlaceOp(binOp: UntypedBinaryOp, a, b: Snippet): Snippet = result.add("= ") result.add(b) result.add(";\n") + +template addCPragma(builder: var Builder, val: Snippet) = + builder.add("\n#pragma ") + builder.add(val) + builder.add("\n") diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 51c58660e901..97a7a53e1591 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -54,7 +54,7 @@ proc inExceptBlockLen(p: BProc): int = for x in p.nestedTryStmts: if x.inExcept: result.inc -proc startBlockInternal(p: BProc): int {.discardable.} = +proc startBlockInside(p: BProc): int {.discardable.} = inc(p.labels) result = p.blocks.len @@ -64,12 +64,35 @@ proc startBlockInternal(p: BProc): int {.discardable.} = p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16 p.blocks[result].nestedExceptStmts = p.inExceptBlockLen.int16 -template startBlock(p: BProc, start: FormatStr = "{$n", - args: varargs[Rope]): int = - lineCg(p, cpsStmts, start, args) - startBlockInternal(p) +template startBlockWith(p: BProc, body: typed): int = + body + startBlockInside(p) + +proc blockBody(b: var TBlock; result: var Builder) = + result.add extract(b.sections[cpsLocals]) + if b.frameLen > 0: + result.addInPlaceOp(Add, "NI", dotField("FR_", "len"), b.frameLen.rope) + result.add(extract(b.sections[cpsInit])) + result.add(extract(b.sections[cpsStmts])) + if b.frameLen > 0: + result.addInPlaceOp(Sub, "NI", dotField("FR_", "len"), b.frameLen.rope) + +proc endBlockInside(p: BProc) = + let topBlock = p.blocks.len-1 + # the block is merged into the parent block + p.blocks[topBlock].blockBody(p.blocks[topBlock-1].sections[cpsStmts]) + setLen(p.blocks, topBlock) + +proc endBlockOutside(p: BProc, label: TLabel) = + if label.len != 0: + let topBlock = p.blocks.len - 1 + p.blocks[topBlock].sections[cpsStmts].addLabel(label) -proc endBlock(p: BProc) +template endBlockWith(p: BProc, body: typed) = + let label = p.blocks[p.blocks.len - 1].label + endBlockInside(p) + body + endBlockOutside(p, label) proc genVarTuple(p: BProc, n: PNode) = if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple") @@ -89,10 +112,12 @@ proc genVarTuple(p: BProc, n: PNode) = # do not close and reopen blocks if this is a 'global' but inside of a block (if/while/block) forHcr = forHcr and not isGlobalInBlock + var hcrIf = default(IfBuilder) if forHcr: - # check with the boolean if the initializing code for the tuple should be ran - lineCg(p, cpsStmts, "if ($1)$n", [hcrCond]) - startBlock(p) + startBlockWith(p): + # check with the boolean if the initializing code for the tuple should be ran + hcrIf = initIfStmt(p.s(cpsStmts)) + initElifBranch(p.s(cpsStmts), hcrIf, hcrCond) genLineDir(p, n) var tup = initLocExpr(p, n[^1]) @@ -120,7 +145,10 @@ proc genVarTuple(p: BProc, n: PNode) = if forHcr: # end the block where the tuple gets initialized - endBlock(p) + endBlockWith(p): + finishBranch(p.s(cpsStmts), hcrIf) + finishIfStmt(p.s(cpsStmts), hcrIf) + if forHcr or isGlobalInBlock: # insert the registration of the globals for the different parts of the tuple at the # start of the current scope (after they have been iterated) and init a boolean to @@ -150,43 +178,25 @@ proc assignLabel(b: var TBlock; result: var Builder) {.inline.} = b.label = "LA" & b.id.rope result.add b.label -proc blockBody(b: var TBlock; result: var Builder) = - result.add extract(b.sections[cpsLocals]) - if b.frameLen > 0: - result.addf("FR_.len+=$1;$n", [b.frameLen.rope]) - result.add(extract(b.sections[cpsInit])) - result.add(extract(b.sections[cpsStmts])) +proc startSimpleBlock(p: BProc, scope: out ScopeBuilder): int {.discardable, inline.} = + startBlockWith(p): + scope = initScope(p.s(cpsStmts)) -proc endBlock(p: BProc, blockEnd: Rope) = - let topBlock = p.blocks.len-1 - # the block is merged into the parent block - p.blocks[topBlock].blockBody(p.blocks[topBlock-1].sections[cpsStmts]) - setLen(p.blocks, topBlock) - # this is done after the block is popped so $n is - # properly indented when pretty printing is enabled - line(p, cpsStmts, blockEnd) - -proc endBlock(p: BProc) = - let topBlock = p.blocks.len - 1 - let frameLen = p.blocks[topBlock].frameLen - var blockEnd: Rope = "" - if frameLen > 0: - blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope]) - if p.blocks[topBlock].label.len != 0: - blockEnd.addf("} $1: ;$n", [p.blocks[topBlock].label]) - else: - blockEnd.addf("}$n", []) - endBlock(p, blockEnd) +proc endSimpleBlock(p: BProc, scope: var ScopeBuilder) {.inline.} = + endBlockWith(p): + finishScope(p.s(cpsStmts), scope) proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} = - startBlock(p) + var scope: ScopeBuilder + startSimpleBlock(p, scope) genStmts(p, stmts) - endBlock(p) + endSimpleBlock(p, scope) proc exprBlock(p: BProc, n: PNode, d: var TLoc) = - startBlock(p) + var scope: ScopeBuilder + startSimpleBlock(p, scope) expr(p, n, d) - endBlock(p) + endSimpleBlock(p, scope) template preserveBreakIdx(body: untyped): untyped = var oldBreakIdx = p.breakIdx @@ -414,16 +424,24 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = # we close and reopen the global if (nim_hcr_do_init_) blocks in the main Init function # for the module so we can have globals and top-level code be interleaved and still # be able to re-run it but without the top level code - just the init of globals + var hcrInit = default(IfBuilder) if forHcr: - lineCg(targetProc, cpsStmts, "if (hcrRegisterGlobal($3, \"$1\", sizeof($2), $4, (void**)&$1))$N", - [v.loc.snippet, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc]) - startBlock(targetProc) + startBlockWith(targetProc): + hcrInit = initIfStmt(p.s(cpsStmts)) + initElifBranch(p.s(cpsStmts), hcrInit, cCall("hcrRegisterGlobal", + getModuleDllPath(p.module, v), + '"' & v.loc.snippet & '"', + cSizeof(rdLoc(v.loc)), + traverseProc, + cCast("void**", cAddr(v.loc.snippet)))) if value.kind != nkEmpty and valueAsRope.len == 0: genLineDir(targetProc, vn) if not isCppCtorCall: loadInto(targetProc, vn, value, v.loc) if forHcr: - endBlock(targetProc) + endBlockWith(targetProc): + finishBranch(p.s(cpsStmts), hcrInit) + finishIfStmt(p.s(cpsStmts), hcrInit) proc genSingleVar(p: BProc, a: PNode) = let v = a[0].sym @@ -480,7 +498,8 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) = # bug #4230: avoid false sharing between branches: if d.k == locTemp and isEmptyType(n.typ): d.k = locNone if it.len == 2: - startBlock(p) + var scope: ScopeBuilder + startSimpleBlock(p, scope) a = initLocExprSingleUse(p, it[0]) lelse = getLabel(p) inc(p.labels) @@ -493,14 +512,15 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) = p.s(cpsStmts).add "}" else: expr(p, it[1], d) - endBlock(p) + endSimpleBlock(p, scope) if n.len > 1: lineF(p, cpsStmts, "goto $1;$n", [lend]) fixLabel(p, lelse) elif it.len == 1: - startBlock(p) + var scope: ScopeBuilder + startSimpleBlock(p, scope) expr(p, it[0], d) - endBlock(p) + endSimpleBlock(p, scope) else: internalError(p.config, n.info, "genIf()") if n.len > 1: fixLabel(p, lend) @@ -521,7 +541,8 @@ proc genReturnStmt(p: BProc, t: PNode) = proc genGotoForCase(p: BProc; caseStmt: PNode) = for i in 1..$1, $2)", [memberName, checkFor]) if orExpr.len != 0: - if hasIf: - startBlock(p, "else if ($1) {$n", [orExpr]) - else: - startBlock(p, "if ($1) {$n", [orExpr]) + if not hasIf: hasIf = true + ifStmt = initIfStmt(p.s(cpsStmts)) + startBlockWith(p): + initElifBranch(p.s(cpsStmts), ifStmt, orExpr) if exvar != nil: fillLocalName(p, exvar.sym) fillLoc(exvar.sym.loc, locTemp, exvar, OnStack) @@ -1154,10 +1186,14 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp]) expr(p, t[i][^1], d) linefmt(p, cpsStmts, "#popCurrentException();$n", []) - endBlock(p) + endBlockWith(p): + finishBranch(p.s(cpsStmts), ifStmt) inc(i) if hasIf and not hasElse: - linefmt(p, cpsStmts, "else throw;$n", [etmp]) + p.s(cpsStmts).addElseBranch(ifStmt): + p.s(cpsStmts).add("throw;\n") + if hasIf: + finishIfStmt(p.s(cpsStmts), ifStmt) linefmt(p, cpsStmts, "}$n", []) # Second pass: handle C++ based exceptions: @@ -1177,9 +1213,11 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = if t[i].len == 1: # general except section: - startBlock(p, "catch (...) {$n", []) + startBlockWith(p): + p.s(cpsStmts).add("catch (...) {\n") genExceptBranchBody(t[i][0]) - endBlock(p) + endBlockWith(p): + p.s(cpsStmts).add("}\n") catchAllPresent = true else: for j in 0.. 0 and t[^1].kind == nkFinally: if not catchAllPresent: - startBlock(p, "catch (...) {$n", []) + startBlockWith(p): + p.s(cpsStmts).add("catch (...) {\n") genRestoreFrameAfterException(p) linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) - endBlock(p) + endBlockWith(p): + p.s(cpsStmts).add("}\n") - startBlock(p) + var scope: ScopeBuilder + startSimpleBlock(p, scope) genStmts(p, t[^1][0]) linefmt(p, cpsStmts, "if (T$1_) std::rethrow_exception(T$1_);$n", [etmp]) - endBlock(p) + endSimpleBlock(p, scope) proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) = # There are two versions we generate, depending on whether we @@ -1245,9 +1290,11 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) = cgsym(p.module, "popCurrentExceptionEx") let fin = if t[^1].kind == nkFinally: t[^1] else: nil p.nestedTryStmts.add((fin, false, 0.Natural)) - startBlock(p, "try {$n") + startBlockWith(p): + p.s(cpsStmts).add("try {\n") expr(p, t[0], d) - endBlock(p) + endBlockWith(p): + p.s(cpsStmts).add("}\n") var catchAllPresent = false @@ -1261,20 +1308,25 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) = if t[i].len == 1: # general except section: catchAllPresent = true - startBlock(p, "catch (...) {$n") + startBlockWith(p): + p.s(cpsStmts).add("catch (...) {\n") genExceptBranchBody(t[i][0]) - endBlock(p) + endBlockWith(p): + p.s(cpsStmts).add("}\n") else: for j in 0.. 1: lineF(p, cpsStmts, "else", []) - startBlock(p) + startBlockWith(p): + if innerIsIf: + initElseBranch(p.s(cpsStmts), innerIfStmt) + else: + isScope = true + innerScope = initScope(p.s(cpsStmts)) # we handled the exception, remember this: linefmt(p, cpsStmts, "*nimErr_ = NIM_FALSE;$n", []) expr(p, t[i][0], d) else: + if not innerIsIf: + innerIsIf = true + innerIfStmt = initIfStmt(p.s(cpsStmts)) var orExpr = newRopeAppender() for j in 0..$1, $2)", [memberName, checkFor]) - if i > 1: line(p, cpsStmts, "else ") - startBlock(p, "if ($1) {$n", [orExpr]) + startBlockWith(p): + initElifBranch(p.s(cpsStmts), innerIfStmt, orExpr) # we handled the exception, remember this: linefmt(p, cpsStmts, "*nimErr_ = NIM_FALSE;$n", []) expr(p, t[i][^1], d) linefmt(p, cpsStmts, "#popCurrentException();$n", []) linefmt(p, cpsStmts, "LA$1_:;$n", [nextExcept]) - endBlock(p) + endBlockWith(p): + if isScope: + finishScope(p.s(cpsStmts), innerScope) + else: + finishBranch(p.s(cpsStmts), innerIfStmt) inc(i) + if innerIsIf: + finishIfStmt(p.s(cpsStmts), innerIfStmt) discard pop(p.nestedTryStmts) - endBlock(p) + endBlockWith(p): + if isIf: + finishBranch(p.s(cpsStmts), ifStmt) + finishIfStmt(p.s(cpsStmts), ifStmt) + else: + finishScope(p.s(cpsStmts), scope) if i < t.len and t[i].kind == nkFinally: - startBlock(p) + var finallyScope: ScopeBuilder + startSimpleBlock(p, finallyScope) if not bodyCanRaise(p, t[i][0]): # this is an important optimization; most destroy blocks are detected not to raise an # exception and so we help the C optimizer by not mutating nimErr_ pointlessly: @@ -1391,7 +1475,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = # 3. finally is run for exception handling code without any 'except' # handler present or only handlers that did not match. linefmt(p, cpsStmts, "*nimErr_ = oldNimErrFin$1_;$n", [lab]) - endBlock(p) + endSimpleBlock(p, finallyScope) raiseExit(p) if hasExcept: inc p.withinTryWithExcept @@ -1435,6 +1519,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = genLineDir(p, t) cgsym(p.module, "Exception") var safePoint: Rope = "" + var nonQuirkyIf = default(IfBuilder) if not quirkyExceptions: safePoint = getTempName(p.module) linefmt(p, cpsLocals, "#TSafePoint $1;$n", [safePoint]) @@ -1463,34 +1548,55 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint]) else: linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint]) - lineCg(p, cpsStmts, "if ($1.status == 0) {$n", [safePoint]) + nonQuirkyIf = initIfStmt(p.s(cpsStmts)) + initElifBranch(p.s(cpsStmts), nonQuirkyIf, removeSinglePar( + cOp(Equal, dotField(safePoint, "status"), cIntValue(0)))) let fin = if t[^1].kind == nkFinally: t[^1] else: nil p.nestedTryStmts.add((fin, quirkyExceptions, 0.Natural)) expr(p, t[0], d) + var quirkyIf = default(IfBuilder) + var quirkyScope = default(ScopeBuilder) + var isScope = false if not quirkyExceptions: linefmt(p, cpsStmts, "#popSafePoint();$n", []) - lineCg(p, cpsStmts, "}$n", []) - startBlock(p, "else {$n") + finishBranch(p.s(cpsStmts), nonQuirkyIf) + startBlockWith(p): + initElseBranch(p.s(cpsStmts), nonQuirkyIf) linefmt(p, cpsStmts, "#popSafePoint();$n", []) genRestoreFrameAfterException(p) elif 1 < t.len and t[1].kind == nkExceptBranch: - startBlock(p, "if (#nimBorrowCurrentException()) {$n") + startBlockWith(p): + quirkyIf = initIfStmt(p.s(cpsStmts)) + initElifBranch(p.s(cpsStmts), quirkyIf, + cCall(cgsymValue(p.module, "nimBorrowCurrentException"))) else: - startBlock(p) + isScope = true + startBlockWith(p): + quirkyScope = initScope(p.s(cpsStmts)) p.nestedTryStmts[^1].inExcept = true var i = 1 + var exceptIf = default(IfBuilder) + var exceptIfInited = false while (i < t.len) and (t[i].kind == nkExceptBranch): # bug #4230: avoid false sharing between branches: if d.k == locTemp and isEmptyType(t.typ): d.k = locNone if t[i].len == 1: # general except section: - if i > 1: lineF(p, cpsStmts, "else", []) - startBlock(p) + var scope = default(ScopeBuilder) + startBlockWith(p): + if exceptIfInited: + initElseBranch(p.s(cpsStmts), exceptIf) + else: + scope = initScope(p.s(cpsStmts)) if not quirkyExceptions: linefmt(p, cpsStmts, "$1.status = 0;$n", [safePoint]) expr(p, t[i][0], d) linefmt(p, cpsStmts, "#popCurrentException();$n", []) - endBlock(p) + endBlockWith(p): + if exceptIfInited: + finishBranch(p.s(cpsStmts), exceptIf) + else: + finishScope(p.s(cpsStmts), scope) else: var orExpr = newRopeAppender() for j in 0..$1, $2)", [memberName, checkFor]) - if i > 1: line(p, cpsStmts, "else ") - startBlock(p, "if ($1) {$n", [orExpr]) + if not exceptIfInited: + exceptIf = initIfStmt(p.s(cpsStmts)) + exceptIfInited = true + startBlockWith(p): + initElifBranch(p.s(cpsStmts), exceptIf, orExpr) if not quirkyExceptions: linefmt(p, cpsStmts, "$1.status = 0;$n", [safePoint]) expr(p, t[i][^1], d) linefmt(p, cpsStmts, "#popCurrentException();$n", []) - endBlock(p) + endBlockWith(p): + finishBranch(p.s(cpsStmts), exceptIf) inc(i) + if exceptIfInited: + finishIfStmt(p.s(cpsStmts), exceptIf) discard pop(p.nestedTryStmts) - endBlock(p) # end of else block + endBlockWith(p): + # end of else block + if not quirkyExceptions: + finishBranch(p.s(cpsStmts), nonQuirkyIf) + finishIfStmt(p.s(cpsStmts), nonQuirkyIf) + elif isScope: + finishScope(p.s(cpsStmts), quirkyScope) + else: + finishBranch(p.s(cpsStmts), quirkyIf) + finishIfStmt(p.s(cpsStmts), quirkyIf) if i < t.len and t[i].kind == nkFinally: p.finallySafePoints.add(safePoint) - startBlock(p) + var finallyScope: ScopeBuilder + startSimpleBlock(p, finallyScope) genStmts(p, t[i][0]) # pretend we handled the exception in a 'finally' so that we don't # re-raise the unhandled one but instead keep the old one (it was # not popped either): if not quirkyExceptions and getCompilerProc(p.module.g.graph, "nimLeaveFinally") != nil: linefmt(p, cpsStmts, "if ($1.status != 0) #nimLeaveFinally();$n", [safePoint]) - endBlock(p) + endSimpleBlock(p, finallyScope) discard pop(p.finallySafePoints) if not quirkyExceptions: linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint]) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 013083d96cc9..f46ba67abd8a 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -2210,21 +2210,24 @@ when false: readMergeInfo(getCFile(m), m) result = m -proc addHcrInitGuards(p: BProc, n: PNode, inInitGuard: var bool) = +proc addHcrInitGuards(p: BProc, n: PNode, inInitGuard: var bool, init: var IfBuilder) = if n.kind == nkStmtList: for child in n: - addHcrInitGuards(p, child, inInitGuard) + addHcrInitGuards(p, child, inInitGuard, init) else: let stmtShouldExecute = n.kind in {nkVarSection, nkLetSection} or nfExecuteOnReload in n.flags if inInitGuard: if stmtShouldExecute: - endBlock(p) + endBlockWith(p): + finishBranch(p.s(cpsStmts), init) + finishIfStmt(p.s(cpsStmts), init) inInitGuard = false else: if not stmtShouldExecute: - line(p, cpsStmts, "if (nim_hcr_do_init_)\n") - startBlock(p) + startBlockWith(p): + init = initIfStmt(p.s(cpsStmts)) + initElifBranch(p.s(cpsStmts), init, "nim_hcr_do_init_") inInitGuard = true genStmts(p, n) @@ -2240,7 +2243,7 @@ proc genTopLevelStmt*(m: BModule; n: PNode) = transformedN = injectDestructorCalls(m.g.graph, m.idgen, m.module, transformedN) if m.hcrOn: - addHcrInitGuards(m.initProc, transformedN, m.inHcrInitGuard) + addHcrInitGuards(m.initProc, transformedN, m.inHcrInitGuard, m.hcrInitGuard) else: genProcBody(m.initProc, transformedN) @@ -2356,7 +2359,9 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = if sym != nil: cgsymImpl m, sym if m.inHcrInitGuard: - endBlock(m.initProc) + endBlockWith(m.initProc): + finishBranch(m.initProc.s(cpsStmts), m.hcrInitGuard) + finishIfStmt(m.initProc.s(cpsStmts), m.hcrInitGuard) if sfMainModule in m.module.flags: if m.hcrOn: diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 3dc042174fd5..0b1b53b83b29 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -163,6 +163,7 @@ type preInitProc*: BProc # code executed before the init proc hcrCreateTypeInfosProc*: Builder # type info globals are in here when HCR=on inHcrInitGuard*: bool # We are currently within a HCR reloading guard. + hcrInitGuard*: IfBuilder typeStack*: TTypeSeq # used for type generation dataCache*: TNodeTable typeNodes*, nimTypes*: int # used for type info generation