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
This commit is contained in:
metagn
2024-11-08 16:28:52 +03:00
committed by GitHub
parent 45b8434c7d
commit b3c1fbaf13
6 changed files with 375 additions and 162 deletions

View File

@@ -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

View File

@@ -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 & ")"

View File

@@ -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
builder.add("}")
stmt.state = InBlock
proc addForRangeHeader(builder: var Builder, i, start, bound: Snippet, inclusive: bool = false) =
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)
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")
template addForRangeExclusive(builder: var Builder, i, start, bound: Snippet, body: typed) =
addForRangeHeader(builder, i, start, bound, false)
body
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 addForRangeInclusive(builder: var Builder, i, start, bound: Snippet, body: typed) =
addForRangeHeader(builder, i, start, bound, true)
template addForRangeExclusive(builder: var Builder, i, start, bound: Snippet, body: typed) =
initForRange(builder, i, start, bound, false)
body
builder.add("}\n")
finishFor(builder)
template addForRangeInclusive(builder: var Builder, i, start, bound: Snippet, body: typed) =
initForRange(builder, i, start, bound, true)
body
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")

View File

@@ -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 endBlock(p: BProc)
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)
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..<caseStmt.len:
startBlock(p)
var scope: ScopeBuilder
startSimpleBlock(p, scope)
let it = caseStmt[i]
for j in 0..<it.len-1:
if it[j].kind == nkRange:
@@ -530,7 +551,7 @@ proc genGotoForCase(p: BProc; caseStmt: PNode) =
let val = getOrdValue(it[j])
lineF(p, cpsStmts, "NIMSTATE_$#:$n", [val.rope])
genStmts(p, it.lastSon)
endBlock(p)
endSimpleBlock(p, scope)
iterator fieldValuePairs(n: PNode): tuple[memberSym, valueSym: PNode] =
@@ -588,7 +609,8 @@ proc genComputedGoto(p: BProc; n: PNode) =
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
for i in 1..<caseStmt.len:
startBlock(p)
var scope: ScopeBuilder
startSimpleBlock(p, scope)
let it = caseStmt[i]
for j in 0..<it.len-1:
if it[j].kind == nkRange:
@@ -622,7 +644,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
var a: TLoc = initLocExpr(p, caseStmt[0])
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
endBlock(p)
endSimpleBlock(p, scope)
for j in casePos+1..<n.len:
genStmts(p, n[j])
@@ -646,7 +668,9 @@ proc genWhileStmt(p: BProc, t: PNode) =
loopBody = loopBody[1]
genComputedGoto(p, loopBody)
else:
p.breakIdx = startBlock(p, "while (1) {$n")
var stmt: WhileBuilder
p.breakIdx = startBlockWith(p):
stmt = initWhileStmt(p.s(cpsStmts), cIntValue(1))
p.blocks[p.breakIdx].isLoop = true
a = initLocExpr(p, t[0])
if (t[0].kind != nkIntLit) or (t[0].intVal == 0):
@@ -658,7 +682,8 @@ proc genWhileStmt(p: BProc, t: PNode) =
if optProfiler in p.options:
# invoke at loop body exit:
linefmt(p, cpsStmts, "#nimProfile();$n", [])
endBlock(p)
endBlockWith(p):
finishWhileStmt(p.s(cpsStmts), stmt)
dec(p.withinLoop)
@@ -670,7 +695,8 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
d = getTemp(p, n.typ)
d.flags.incl(lfEnforceDeref)
preserveBreakIdx:
p.breakIdx = startBlock(p)
var scope: ScopeBuilder
p.breakIdx = startSimpleBlock(p, scope)
if n[0].kind != nkEmpty:
# named block?
assert(n[0].kind == nkSym)
@@ -678,7 +704,7 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
sym.loc.k = locOther
sym.position = p.breakIdx+1
expr(p, n[1], d)
endBlock(p)
endSimpleBlock(p, scope)
proc genParForStmt(p: BProc, t: PNode) =
assert(t.len == 3)
@@ -695,32 +721,27 @@ proc genParForStmt(p: BProc, t: PNode) =
var rangeA = initLocExpr(p, call[1])
var rangeB = initLocExpr(p, call[2])
var stepNode: PNode = nil
# $n at the beginning because of #9710
if call.len == 4: # procName(a, b, annotation)
if call[0].sym.name.s == "||": # `||`(a, b, annotation)
lineF(p, cpsStmts, "$n#pragma omp $4$n" &
"for ($1 = $2; $1 <= $3; ++$1)",
[forLoopVar.loc.rdLoc,
rangeA.rdLoc, rangeB.rdLoc,
call[3].getStr.rope])
p.s(cpsStmts).addCPragma("omp " & call[3].getStr)
else:
lineF(p, cpsStmts, "$n#pragma $4$n" &
"for ($1 = $2; $1 <= $3; ++$1)",
[forLoopVar.loc.rdLoc,
rangeA.rdLoc, rangeB.rdLoc,
call[3].getStr.rope])
p.s(cpsStmts).addCPragma(call[3].getStr)
else: # `||`(a, b, step, annotation)
var step: TLoc = initLocExpr(p, call[3])
lineF(p, cpsStmts, "$n#pragma omp $5$n" &
"for ($1 = $2; $1 <= $3; $1 += $4)",
[forLoopVar.loc.rdLoc,
rangeA.rdLoc, rangeB.rdLoc, step.rdLoc,
call[4].getStr.rope])
stepNode = call[3]
p.s(cpsStmts).addCPragma("omp " & call[4].getStr)
p.breakIdx = startBlock(p)
p.breakIdx = startBlockWith(p):
if stepNode == nil:
initForRange(p.s(cpsStmts), forLoopVar.loc.rdLoc, rangeA.rdLoc, rangeB.rdLoc, true)
else:
var step: TLoc = initLocExpr(p, stepNode)
initForStep(p.s(cpsStmts), forLoopVar.loc.rdLoc, rangeA.rdLoc, rangeB.rdLoc, step.rdLoc, true)
p.blocks[p.breakIdx].isLoop = true
genStmts(p, t[2])
endBlock(p)
endBlockWith(p):
finishFor(p.s(cpsStmts))
dec(p.withinLoop)
@@ -1091,9 +1112,11 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
expr(p, t[0], d)
lineCg(p, cpsStmts, "}$n", [])
else:
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")
# First pass: handle Nim based exceptions:
lineCg(p, cpsStmts, "catch (#Exception* T$1_) {$n", [etmp+1])
@@ -1103,6 +1126,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
p.nestedTryStmts[^1].inExcept = true
var hasImportedCppExceptions = false
var i = 1
var ifStmt = default(IfBuilder)
var hasIf = false
var hasElse = false
while (i < t.len) and (t[i].kind == nkExceptBranch):
@@ -1110,14 +1134,22 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
if t[i].len == 1:
hasImportedCppExceptions = true
# general except section:
hasElse = true
if hasIf: lineF(p, cpsStmts, "else ", [])
startBlock(p)
# general except section:
var scope = default(ScopeBuilder)
startBlockWith(p):
if hasIf:
initElseBranch(p.s(cpsStmts), ifStmt)
else:
scope = initScope(p.s(cpsStmts))
# we handled the error:
expr(p, t[i][0], d)
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
endBlock(p)
endBlockWith(p):
if hasIf:
finishBranch(p.s(cpsStmts), ifStmt)
else:
finishScope(p.s(cpsStmts), scope)
else:
var orExpr = newRopeAppender()
var exvar = PNode(nil)
@@ -1140,11 +1172,11 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$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..<t[i].len-1:
@@ -1190,28 +1228,35 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:`
fillLocalName(p, exvar.sym)
fillLoc(exvar.sym.loc, locTemp, exvar, OnStack)
startBlock(p, "catch ($1& $2) {$n", getTypeDesc(p.module, typeNode.typ), rdLoc(exvar.sym.loc))
startBlockWith(p):
lineCg(p, cpsStmts, "catch ($1& $2) {$n", [getTypeDesc(p.module, typeNode.typ), rdLoc(exvar.sym.loc)])
genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type
endBlock(p)
endBlockWith(p):
p.s(cpsStmts).add("}\n")
elif isImportedException(typeNode.typ, p.config):
startBlock(p, "catch ($1&) {$n", getTypeDesc(p.module, t[i][j].typ))
startBlockWith(p):
lineCg(p, cpsStmts, "catch ($1&) {$n", [getTypeDesc(p.module, t[i][j].typ)])
genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type
endBlock(p)
endBlockWith(p):
p.s(cpsStmts).add("}\n")
excl p.flags, noSafePoints
discard pop(p.nestedTryStmts)
# general finally block:
if t.len > 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..<t[i].len-1:
if t[i][j].isInfixAs():
let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:`
fillLocalName(p, exvar.sym)
fillLoc(exvar.sym.loc, locTemp, exvar, OnUnknown)
startBlock(p, "catch ($1& $2) {$n", getTypeDesc(p.module, t[i][j][1].typ), rdLoc(exvar.sym.loc))
startBlockWith(p):
lineCg(p, cpsStmts, "catch ($1& $2) {$n", [getTypeDesc(p.module, t[i][j][1].typ), rdLoc(exvar.sym.loc)])
else:
startBlock(p, "catch ($1&) {$n", getTypeDesc(p.module, t[i][j].typ))
startBlockWith(p):
lineCg(p, cpsStmts, "catch ($1&) {$n", [getTypeDesc(p.module, t[i][j].typ)])
genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type
endBlock(p)
endBlockWith(p):
p.s(cpsStmts).add("}\n")
discard pop(p.nestedTryStmts)
@@ -1282,10 +1334,12 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
# c++ does not have finally, therefore code needs to be generated twice
if not catchAllPresent:
# finally requires catch all presence
startBlock(p, "catch (...) {$n")
startBlockWith(p):
p.s(cpsStmts).add("catch (...) {\n")
genStmts(p, t[^1][0])
line(p, cpsStmts, "throw;\n")
endBlock(p)
endBlockWith(p):
p.s(cpsStmts).add("}\n")
genSimpleBlock(p, t[^1][0])
@@ -1322,30 +1376,48 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
expr(p, t[0], d)
var ifStmt = default(IfBuilder)
var scope = default(ScopeBuilder)
var isIf = false
if 1 < t.len and t[1].kind == nkExceptBranch:
startBlock(p, "if (NIM_UNLIKELY(*nimErr_)) {$n")
startBlockWith(p):
isIf = true
ifStmt = initIfStmt(p.s(cpsStmts))
initElifBranch(p.s(cpsStmts), ifStmt, cUnlikely(cDeref("nimErr_")))
else:
startBlock(p)
startBlockWith(p):
scope = initScope(p.s(cpsStmts))
linefmt(p, cpsStmts, "LA$1_:;$n", [lab])
p.nestedTryStmts[^1].inExcept = true
var i = 1
var innerIfStmt = default(IfBuilder)
var innerScope = default(ScopeBuilder)
var innerIsIf = false
while (i < t.len) and (t[i].kind == nkExceptBranch):
inc p.labels
let nextExcept = p.labels
p.nestedTryStmts[^1].label = nextExcept
var isScope = false
# 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)
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..<t[i].len - 1:
assert(t[i][j].kind == nkType)
@@ -1359,22 +1431,34 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$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..<t[i].len - 1:
@@ -1505,26 +1611,42 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$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])

View File

@@ -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:

View File

@@ -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