Cosmetic compiler cleanup (#12718)

* Cleanup compiler code base

* Unify add calls

* Unify len invocations

* Unify range operators

* Fix oversight

* Remove {.procvar.} pragma

* initCandidate -> newCandidate where reasonable

* Unify safeLen calls
This commit is contained in:
Clyybber 2019-11-28 17:13:04 +01:00 • committed by Andreas Rumpf
commit 7e747d11c6
109 changed files with 6115 additions and 6254 deletions

View file

@ -46,7 +46,7 @@ proc inExceptBlockLen(p: BProc): int =
proc startBlockInternal(p: BProc): int {.discardable.} =
inc(p.labels)
result = len(p.blocks)
result = p.blocks.len
setLen(p.blocks, result + 1)
p.blocks[result].id = p.labels
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
@ -62,16 +62,15 @@ proc endBlock(p: BProc)
proc genVarTuple(p: BProc, n: PNode) =
var tup, field: TLoc
if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
var L = len(n)
# if we have a something that's been captured, use the lowering instead:
for i in 0 .. L-3:
for i in 0..<n.len-2:
if n[i].kind != nkSym:
genStmts(p, lowerTupleUnpacking(p.module.g.graph, n, p.prc))
return
# check only the first son
var forHcr = treatGlobalDifferentlyForHCR(p.module, n.sons[0].sym)
var forHcr = treatGlobalDifferentlyForHCR(p.module, n[0].sym)
let hcrCond = if forHcr: getTempName(p.module) else: nil
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]]
# determine if the tuple is constructed at top-level scope or inside of a block (if/while/block)
@ -85,10 +84,10 @@ proc genVarTuple(p: BProc, n: PNode) =
startBlock(p)
genLineDir(p, n)
initLocExpr(p, n.sons[L-1], tup)
initLocExpr(p, n[^1], tup)
var t = tup.t.skipTypes(abstractInst)
for i in 0 .. L-3:
let vn = n.sons[i]
for i in 0..<n.len-2:
let vn = n[i]
let v = vn.sym
if sfCompileTime in v.flags: continue
var traverseProc: Rope
@ -100,13 +99,13 @@ proc genVarTuple(p: BProc, n: PNode) =
registerTraverseProc(p, v, traverseProc)
else:
assignLocalVar(p, vn)
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[L-1]))
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1]))
initLoc(field, locExpr, vn, tup.storage)
if t.kind == tyTuple:
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
else:
if t.n.sons[i].kind != nkSym: internalError(p.config, n.info, "genVarTuple")
field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n.sons[i].sym)]
if t.n[i].kind != nkSym: internalError(p.config, n.info, "genVarTuple")
field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n[i].sym)]
putLocIntoDest(p, v.loc, field)
if forHcr or isGlobalInBlock:
hcrGlobals.add((loc: v.loc, tp: if traverseProc == nil: ~"NULL" else: traverseProc))
@ -121,12 +120,12 @@ proc genVarTuple(p: BProc, n: PNode) =
lineCg(p, cpsLocals, "NIM_BOOL $1 = NIM_FALSE;$n", [hcrCond])
for curr in hcrGlobals:
lineCg(p, cpsLocals, "$1 |= hcrRegisterGlobal($4, \"$2\", sizeof($3), $5, (void**)&$2);$N",
[hcrCond, curr.loc.r, rdLoc(curr.loc), getModuleDllPath(p.module, n.sons[0].sym), curr.tp])
[hcrCond, curr.loc.r, rdLoc(curr.loc), getModuleDllPath(p.module, n[0].sym), curr.tp])
proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
if ri.kind in nkCallKinds and (ri.sons[0].kind != nkSym or
ri.sons[0].sym.magic == mNone):
if ri.kind in nkCallKinds and (ri[0].kind != nkSym or
ri[0].sym.magic == mNone):
genAsgnCall(p, le, ri, a)
else:
# this is a hacky way to fix #1181 (tmissingderef)::
@ -153,7 +152,7 @@ proc blockBody(b: var TBlock): Rope =
proc endBlock(p: BProc, blockEnd: Rope) =
let topBlock = p.blocks.len-1
# the block is merged into the parent block
add(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
p.blocks[topBlock-1].sections[cpsStmts].add(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
@ -190,7 +189,7 @@ proc genState(p: BProc, n: PNode) =
internalAssert p.config, n.len == 1
let n0 = n[0]
if n0.kind == nkIntLit:
let idx = n.sons[0].intVal
let idx = n[0].intVal
linefmt(p, cpsStmts, "STATE$1: ;$n", [idx])
elif n0.kind == nkStrLit:
linefmt(p, cpsStmts, "$1: ;$n", [n0.strVal])
@ -201,7 +200,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
var stack = newSeq[tuple[fin: PNode, inExcept: bool]](0)
for i in 1 .. howManyTrys:
for i in 1..howManyTrys:
let tryStmt = p.nestedTryStmts.pop
if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
# Pop safe points generated by try
@ -236,7 +235,7 @@ proc genGotoState(p: BProc, n: PNode) =
# case 0: goto STATE0;
# ...
var a: TLoc
initLocExpr(p, n.sons[0], a)
initLocExpr(p, n[0], a)
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
p.beforeRetNeeded = true
lineF(p, cpsStmts, "case -1:$n", [])
@ -244,12 +243,12 @@ proc genGotoState(p: BProc, n: PNode) =
howManyTrys = p.nestedTryStmts.len,
howManyExcepts = p.inExceptBlockLen)
lineF(p, cpsStmts, " goto BeforeRet_;$n", [])
var statesCounter = lastOrd(p.config, n.sons[0].typ)
var statesCounter = lastOrd(p.config, n[0].typ)
if n.len >= 2 and n[1].kind == nkIntLit:
statesCounter = getInt(n[1])
let prefix = if n.len == 3 and n[2].kind == nkStrLit: n[2].strVal.rope
else: rope"STATE"
for i in 0i64 .. toInt64(statesCounter):
for i in 0i64..toInt64(statesCounter):
lineF(p, cpsStmts, "case $2: goto $1$2;$n", [prefix, rope(i)])
lineF(p, cpsStmts, "}$n", [])
@ -257,11 +256,11 @@ proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
initLoc(d, locExpr, n, OnUnknown)
if n.sons[0].kind == nkClosure:
initLocExpr(p, n.sons[0].sons[1], a)
if n[0].kind == nkClosure:
initLocExpr(p, n[0][1], a)
d.r = "(((NI*) $1)[1] < 0)" % [rdLoc(a)]
else:
initLocExpr(p, n.sons[0], a)
initLocExpr(p, n[0], a)
# the environment is guaranteed to contain the 'state' field at offset 1:
d.r = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)]
@ -322,12 +321,12 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
if value.kind in nkCallKinds and value[0].kind == nkSym and
sfConstructor in value[0].sym.flags:
var params: Rope
let typ = skipTypes(value.sons[0].typ, abstractInst)
let typ = skipTypes(value[0].typ, abstractInst)
assert(typ.kind == tyProc)
for i in 1..<value.len:
if params != nil: params.add(~", ")
assert(len(typ) == len(typ.n))
add(params, genOtherArg(p, value, i, typ))
assert(typ.len == typ.n.len)
params.add(genOtherArg(p, value, i, typ))
if params == nil:
lineF(p, cpsStmts, "$#;$n", [decl])
else:
@ -368,15 +367,15 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
proc genSingleVar(p: BProc, a: PNode) =
let v = a[0].sym
if sfCompileTime in v.flags: return
genSingleVar(p, v, a[0], a.sons[2])
genSingleVar(p, v, a[0], a[2])
proc genClosureVar(p: BProc, a: PNode) =
var immediateAsgn = a.sons[2].kind != nkEmpty
var immediateAsgn = a[2].kind != nkEmpty
var v: TLoc
initLocExpr(p, a.sons[0], v)
initLocExpr(p, a[0], v)
genLineDir(p, a)
if immediateAsgn:
loadInto(p, a.sons[0], a.sons[2], v)
loadInto(p, a[0], a[2], v)
else:
constructLoc(p, v)
@ -385,7 +384,7 @@ proc genVarStmt(p: BProc, n: PNode) =
if it.kind == nkCommentStmt: continue
if it.kind == nkIdentDefs:
# can be a lifted var nowadays ...
if it.sons[0].kind == nkSym:
if it[0].kind == nkSym:
genSingleVar(p, it)
else:
genClosureVar(p, it)
@ -416,53 +415,53 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
if d.k == locTemp and isEmptyType(n.typ): d.k = locNone
if it.len == 2:
startBlock(p)
initLocExprSingleUse(p, it.sons[0], a)
initLocExprSingleUse(p, it[0], a)
lelse = getLabel(p)
inc(p.labels)
lineF(p, cpsStmts, "if (!$1) goto $2;$n",
[rdLoc(a), lelse])
if p.module.compileToCpp:
# avoid "jump to label crosses initialization" error:
add(p.s(cpsStmts), "{")
expr(p, it.sons[1], d)
add(p.s(cpsStmts), "}")
p.s(cpsStmts).add "{"
expr(p, it[1], d)
p.s(cpsStmts).add "}"
else:
expr(p, it.sons[1], d)
expr(p, it[1], d)
endBlock(p)
if len(n) > 1:
if n.len > 1:
lineF(p, cpsStmts, "goto $1;$n", [lend])
fixLabel(p, lelse)
elif it.len == 1:
startBlock(p)
expr(p, it.sons[0], d)
expr(p, it[0], d)
endBlock(p)
else: internalError(p.config, n.info, "genIf()")
if len(n) > 1: fixLabel(p, lend)
if n.len > 1: fixLabel(p, lend)
proc genReturnStmt(p: BProc, t: PNode) =
if nfPreventCg in t.flags: return
p.beforeRetNeeded = true
genLineDir(p, t)
if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
if (t[0].kind != nkEmpty): genStmts(p, t[0])
blockLeaveActions(p,
howManyTrys = p.nestedTryStmts.len,
howManyExcepts = p.inExceptBlockLen)
if (p.finallySafePoints.len > 0) and not p.noSafePoints:
# If we're in a finally block, and we came here by exception
# consume it before we return.
var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
var safePoint = p.finallySafePoints[^1]
linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", [safePoint])
lineF(p, cpsStmts, "goto BeforeRet_;$n", [])
proc genGotoForCase(p: BProc; caseStmt: PNode) =
for i in 1 ..< caseStmt.len:
for i in 1..<caseStmt.len:
startBlock(p)
let it = caseStmt.sons[i]
for j in 0 .. it.len-2:
if it.sons[j].kind == nkRange:
let it = caseStmt[i]
for j in 0..<it.len-1:
if it[j].kind == nkRange:
localError(p.config, it.info, "range notation not available for computed goto")
return
let val = getOrdValue(it.sons[j])
let val = getOrdValue(it[j])
lineF(p, cpsStmts, "NIMSTATE_$#:$n", [val.rope])
genStmts(p, it.lastSon)
endBlock(p)
@ -473,7 +472,7 @@ iterator fieldValuePairs(n: PNode): tuple[memberSym, valueSym: PNode] =
for identDefs in n:
if identDefs.kind == nkIdentDefs:
let valueSym = identDefs[^1]
for i in 0 ..< identDefs.len-2:
for i in 0..<identDefs.len-2:
let memberSym = identDefs[i]
yield((memberSym: memberSym, valueSym: valueSym))
@ -481,22 +480,22 @@ proc genComputedGoto(p: BProc; n: PNode) =
# first pass: Generate array of computed labels:
var casePos = -1
var arraySize: int
for i in 0 ..< n.len:
let it = n.sons[i]
for i in 0..<n.len:
let it = n[i]
if it.kind == nkCaseStmt:
if lastSon(it).kind != nkOfBranch:
localError(p.config, it.info,
"case statement must be exhaustive for computed goto"); return
casePos = i
if enumHasHoles(it.sons[0].typ):
if enumHasHoles(it[0].typ):
localError(p.config, it.info,
"case statement cannot work on enums with holes for computed goto"); return
let aSize = lengthOrd(p.config, it.sons[0].typ)
let aSize = lengthOrd(p.config, it[0].typ)
if aSize > 10_000:
localError(p.config, it.info,
"case statement has too many cases for computed goto"); return
arraySize = toInt(aSize)
if firstOrd(p.config, it.sons[0].typ) != 0:
if firstOrd(p.config, it[0].typ) != 0:
localError(p.config, it.info,
"case statement has to start at 0 for computed goto"); return
if casePos < 0:
@ -510,54 +509,54 @@ proc genComputedGoto(p: BProc; n: PNode) =
gotoArray.addf("&&TMP$#_};$n", [rope(id+arraySize)])
line(p, cpsLocals, gotoArray)
for j in 0 ..< casePos:
genStmts(p, n.sons[j])
for j in 0..<casePos:
genStmts(p, n[j])
let caseStmt = n.sons[casePos]
let caseStmt = n[casePos]
var a: TLoc
initLocExpr(p, caseStmt.sons[0], a)
initLocExpr(p, caseStmt[0], a)
# first goto:
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
for i in 1 ..< caseStmt.len:
for i in 1..<caseStmt.len:
startBlock(p)
let it = caseStmt.sons[i]
for j in 0 .. it.len-2:
if it.sons[j].kind == nkRange:
let it = caseStmt[i]
for j in 0..<it.len-1:
if it[j].kind == nkRange:
localError(p.config, it.info, "range notation not available for computed goto")
return
let val = getOrdValue(it.sons[j])
let val = getOrdValue(it[j])
lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(toInt64(val)+id+1)])
genStmts(p, it.lastSon)
for j in casePos+1 ..< n.sons.len:
genStmts(p, n.sons[j])
for j in casePos+1..<n.len:
genStmts(p, n[j])
for j in 0 ..< casePos:
for j in 0..<casePos:
# prevent new local declarations
# compile declarations as assignments
let it = n.sons[j]
let it = n[j]
if it.kind in {nkLetSection, nkVarSection}:
let asgn = copyNode(it)
asgn.kind = nkAsgn
asgn.sons.setLen 2
for sym, value in it.fieldValuePairs:
if value.kind != nkEmpty:
asgn.sons[0] = sym
asgn.sons[1] = value
asgn[0] = sym
asgn[1] = value
genStmts(p, asgn)
else:
genStmts(p, it)
var a: TLoc
initLocExpr(p, caseStmt.sons[0], a)
initLocExpr(p, caseStmt[0], a)
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
endBlock(p)
for j in casePos+1 ..< n.sons.len:
genStmts(p, n.sons[j])
for j in casePos+1..<n.len:
genStmts(p, n[j])
proc genWhileStmt(p: BProc, t: PNode) =
@ -565,23 +564,23 @@ proc genWhileStmt(p: BProc, t: PNode) =
# significantly worse code
var
a: TLoc
assert(len(t) == 2)
assert(t.len == 2)
inc(p.withinLoop)
genLineDir(p, t)
preserveBreakIdx:
var loopBody = t.sons[1]
var loopBody = t[1]
if loopBody.stmtsContainPragma(wComputedGoto) and
hasComputedGoto in CC[p.config.cCompiler].props:
# for closure support weird loop bodies are generated:
if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty:
loopBody = loopBody.sons[1]
if loopBody.len == 2 and loopBody[0].kind == nkEmpty:
loopBody = loopBody[1]
genComputedGoto(p, loopBody)
else:
p.breakIdx = startBlock(p, "while (1) {$n")
p.blocks[p.breakIdx].isLoop = true
initLocExpr(p, t.sons[0], a)
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
initLocExpr(p, t[0], a)
if (t[0].kind != nkIntLit) or (t[0].intVal == 0):
let label = assignLabel(p.blocks[p.breakIdx])
lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
genStmts(p, loopBody)
@ -602,30 +601,30 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
d.flags.incl(lfEnforceDeref)
preserveBreakIdx:
p.breakIdx = startBlock(p)
if n.sons[0].kind != nkEmpty:
if n[0].kind != nkEmpty:
# named block?
assert(n.sons[0].kind == nkSym)
var sym = n.sons[0].sym
assert(n[0].kind == nkSym)
var sym = n[0].sym
sym.loc.k = locOther
sym.position = p.breakIdx+1
expr(p, n.sons[1], d)
expr(p, n[1], d)
endBlock(p)
proc genParForStmt(p: BProc, t: PNode) =
assert(len(t) == 3)
assert(t.len == 3)
inc(p.withinLoop)
genLineDir(p, t)
preserveBreakIdx:
let forLoopVar = t.sons[0].sym
let forLoopVar = t[0].sym
var rangeA, rangeB: TLoc
assignLocalVar(p, t.sons[0])
assignLocalVar(p, t[0])
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
#discard mangleName(forLoopVar)
let call = t.sons[1]
assert(len(call) in {4, 5})
initLocExpr(p, call.sons[1], rangeA)
initLocExpr(p, call.sons[2], rangeB)
let call = t[1]
assert(call.len in {4, 5})
initLocExpr(p, call[1], rangeA)
initLocExpr(p, call[2], rangeB)
# $n at the beginning because of #9710
if call.len == 4: # `||`(a, b, annotation)
@ -633,29 +632,29 @@ proc genParForStmt(p: BProc, t: PNode) =
"for ($1 = $2; $1 <= $3; ++$1)",
[forLoopVar.loc.rdLoc,
rangeA.rdLoc, rangeB.rdLoc,
call.sons[3].getStr.rope])
call[3].getStr.rope])
else: # `||`(a, b, step, annotation)
var step: TLoc
initLocExpr(p, call.sons[3], step)
initLocExpr(p, call[3], step)
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.sons[4].getStr.rope])
call[4].getStr.rope])
p.breakIdx = startBlock(p)
p.blocks[p.breakIdx].isLoop = true
genStmts(p, t.sons[2])
genStmts(p, t[2])
endBlock(p)
dec(p.withinLoop)
proc genBreakStmt(p: BProc, t: PNode) =
var idx = p.breakIdx
if t.sons[0].kind != nkEmpty:
if t[0].kind != nkEmpty:
# named break?
assert(t.sons[0].kind == nkSym)
var sym = t.sons[0].sym
assert(t[0].kind == nkSym)
var sym = t[0].sym
doAssert(sym.loc.k == locOther)
idx = sym.position-1
else:
@ -704,17 +703,15 @@ proc genRaiseStmt(p: BProc, t: PNode) =
template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
rangeFormat, eqFormat: FormatStr, labl: TLabel) =
var
x, y: TLoc
var length = len(b)
for i in 0 .. length - 2:
if b.sons[i].kind == nkRange:
initLocExpr(p, b.sons[i].sons[0], x)
initLocExpr(p, b.sons[i].sons[1], y)
var x, y: TLoc
for i in 0..<b.len - 1:
if b[i].kind == nkRange:
initLocExpr(p, b[i][0], x)
initLocExpr(p, b[i][1], y)
lineCg(p, cpsStmts, rangeFormat,
[rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
else:
initLocExpr(p, b.sons[i], x)
initLocExpr(p, b[i], x)
lineCg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
@ -724,12 +721,11 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
# bug #4230: avoid false sharing between branches:
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
lineF(p, cpsStmts, "LA$1_: ;$n", [rope(labId + i)])
if t.sons[i].kind == nkOfBranch:
var length = len(t.sons[i])
exprBlock(p, t.sons[i].sons[length - 1], d)
if t[i].kind == nkOfBranch:
exprBlock(p, t[i][^1], d)
lineF(p, cpsStmts, "goto $1;$n", [lend])
else:
exprBlock(p, t.sons[i].sons[0], d)
exprBlock(p, t[i][0], d)
result = lend
template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
@ -740,8 +736,8 @@ template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
var labId = p.labels
for i in 1..until:
inc(p.labels)
if t.sons[i].kind == nkOfBranch: # else statement
genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
if t[i].kind == nkOfBranch: # else statement
genCaseGenericBranch(p, t[i], a, rangeFormat, eqFormat,
"LA" & rope(p.labels) & "_")
else:
lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)])
@ -758,38 +754,37 @@ template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
template genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: FormatStr) =
var a: TLoc
initLocExpr(p, t.sons[0], a)
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, len(t)-1, a)
initLocExpr(p, t[0], a)
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, t.len-1, a)
fixLabel(p, lend)
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
branches: var openArray[Rope]) =
var x: TLoc
var length = len(b)
for i in 0 .. length - 2:
assert(b.sons[i].kind != nkRange)
initLocExpr(p, b.sons[i], x)
assert(b.sons[i].kind in {nkStrLit..nkTripleStrLit})
var j = int(hashString(p.config, b.sons[i].strVal) and high(branches))
for i in 0..<b.len - 1:
assert(b[i].kind != nkRange)
initLocExpr(p, b[i], x)
assert(b[i].kind in {nkStrLit..nkTripleStrLit})
var j = int(hashString(p.config, b[i].strVal) and high(branches))
appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n",
[rdLoc(e), rdLoc(x), labl])
proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
# count how many constant strings there are in the case:
var strings = 0
for i in 1 ..< len(t):
if t.sons[i].kind == nkOfBranch: inc(strings, len(t.sons[i]) - 1)
for i in 1..<t.len:
if t[i].kind == nkOfBranch: inc(strings, t[i].len - 1)
if strings > stringCaseThreshold:
var bitMask = math.nextPowerOfTwo(strings) - 1
var branches: seq[Rope]
newSeq(branches, bitMask + 1)
var a: TLoc
initLocExpr(p, t.sons[0], a) # fist pass: generate ifs+goto:
initLocExpr(p, t[0], a) # fist pass: generate ifs+goto:
var labId = p.labels
for i in 1 ..< len(t):
for i in 1..<t.len:
inc(p.labels)
if t.sons[i].kind == nkOfBranch:
genCaseStringBranch(p, t.sons[i], a, "LA" & rope(p.labels) & "_",
if t[i].kind == nkOfBranch:
genCaseStringBranch(p, t[i], a, "LA" & rope(p.labels) & "_",
branches)
else:
# else statement: nothing to do yet
@ -797,28 +792,28 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
discard
linefmt(p, cpsStmts, "switch (#hashString($1) & $2) {$n",
[rdLoc(a), bitMask])
for j in 0 .. high(branches):
for j in 0..high(branches):
if branches[j] != nil:
lineF(p, cpsStmts, "case $1: $n$2break;$n",
[intLiteral(j), branches[j]])
lineF(p, cpsStmts, "}$n", []) # else statement:
if t.sons[len(t)-1].kind != nkOfBranch:
if t[^1].kind != nkOfBranch:
lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)])
# third pass: generate statements
var lend = genCaseSecondPass(p, t, d, labId, len(t)-1)
var lend = genCaseSecondPass(p, t, d, labId, t.len-1)
fixLabel(p, lend)
else:
genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
proc branchHasTooBigRange(b: PNode): bool =
for i in 0 .. len(b)-2:
for i in 0..<b.len-1:
# last son is block
if (b.sons[i].kind == nkRange) and
b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit:
if (b[i].kind == nkRange) and
b[i][1].intVal - b[i][0].intVal > RangeExpandLimit:
return true
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
for i in 1..n.len-1:
for i in 1..<n.len:
var branch = n[i]
var stmtBlock = lastSon(branch)
if stmtBlock.stmtsContainPragma(wLinearScanEnd):
@ -828,8 +823,7 @@ proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
result = i
proc genCaseRange(p: BProc, branch: PNode) =
var length = branch.len
for j in 0 .. length-2:
for j in 0..<branch.len-1:
if branch[j].kind == nkRange:
if hasSwitchRange in CC[p.config.cCompiler].props:
lineF(p, cpsStmts, "case $1 ... $2:$n", [
@ -849,7 +843,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
# generate if part (might be empty):
var a: TLoc
initLocExpr(p, n.sons[0], a)
initLocExpr(p, n[0], a)
var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
eqFormat = "if ($1 == $2) goto $3;$n",
@ -859,7 +853,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
if splitPoint+1 < n.len:
lineF(p, cpsStmts, "switch ($1) {$n", [rdCharLoc(a)])
var hasDefault = false
for i in splitPoint+1 ..< n.len:
for i in splitPoint+1..<n.len:
# bug #4230: avoid false sharing between branches:
if d.k == locTemp and isEmptyType(n.typ): d.k = locNone
var branch = n[i]
@ -880,14 +874,14 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) =
genLineDir(p, t)
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
case skipTypes(t.sons[0].typ, abstractVarRange).kind
case skipTypes(t[0].typ, abstractVarRange).kind
of tyString:
genStringCase(p, t, d)
of tyFloat..tyFloat128:
genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
"if ($1 == $2) goto $3;$n")
else:
if t.sons[0].kind == nkSym and sfGoto in t.sons[0].sym.flags:
if t[0].kind == nkSym and sfGoto in t[0].sym.flags:
genGotoForCase(p, t)
else:
genOrdinalCase(p, t, d)
@ -926,7 +920,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
genLineDir(p, t)
discard cgsym(p.module, "popCurrentExceptionEx")
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
add(p.nestedTryStmts, (fin, false))
p.nestedTryStmts.add((fin, false))
startBlock(p, "try {$n")
expr(p, t[0], d)
endBlock(p)
@ -947,7 +941,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
genExceptBranchBody(t[i][0])
endBlock(p)
else:
for j in 0..t[i].len-2:
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:`
fillLoc(exvar.sym.loc, locTemp, exvar, mangleLocalName(p, exvar.sym), OnUnknown)
@ -1023,40 +1017,38 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
else:
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
let length = len(t)
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
add(p.nestedTryStmts, (fin, quirkyExceptions))
expr(p, t.sons[0], d)
p.nestedTryStmts.add((fin, quirkyExceptions))
expr(p, t[0], d)
if not quirkyExceptions:
linefmt(p, cpsStmts, "#popSafePoint();$n", [])
endBlock(p)
startBlock(p, "else {$n")
linefmt(p, cpsStmts, "#popSafePoint();$n", [])
genRestoreFrameAfterException(p)
elif 1 < length and t.sons[1].kind == nkExceptBranch:
elif 1 < t.len and t[1].kind == nkExceptBranch:
startBlock(p, "if (#getCurrentException()) {$n")
else:
startBlock(p)
p.nestedTryStmts[^1].inExcept = true
var i = 1
while (i < length) and (t.sons[i].kind == nkExceptBranch):
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
var blen = len(t.sons[i])
if blen == 1:
if t[i].len == 1:
# general except section:
if i > 1: lineF(p, cpsStmts, "else", [])
startBlock(p)
if not quirkyExceptions:
linefmt(p, cpsStmts, "$1.status = 0;$n", [safePoint])
expr(p, t.sons[i].sons[0], d)
expr(p, t[i][0], d)
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
endBlock(p)
else:
var orExpr: Rope = nil
for j in 0 .. blen - 2:
assert(t.sons[i].sons[j].kind == nkType)
if orExpr != nil: add(orExpr, "||")
for j in 0..<t[i].len - 1:
assert(t[i][j].kind == nkType)
if orExpr != nil: orExpr.add("||")
let checkFor = if optTinyRtti in p.config.globalOptions:
genTypeInfo2Name(p.module, t[i][j].typ)
else:
@ -1068,15 +1060,15 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
startBlock(p, "if ($1) {$n", [orExpr])
if not quirkyExceptions:
linefmt(p, cpsStmts, "$1.status = 0;$n", [safePoint])
expr(p, t.sons[i].sons[blen-1], d)
expr(p, t[i][^1], d)
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
endBlock(p)
inc(i)
discard pop(p.nestedTryStmts)
endBlock(p) # end of else block
if i < length and t.sons[i].kind == nkFinally:
if i < t.len and t[i].kind == nkFinally:
p.finallySafePoints.add(safePoint)
genSimpleBlock(p, t.sons[i].sons[0])
genSimpleBlock(p, t[i][0])
discard pop(p.finallySafePoints)
if not quirkyExceptions:
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint])
@ -1120,12 +1112,12 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
if x[j] in {'"', ':'}:
# don't modify the line if already in quotes or
# some clobber register list:
add(result, x); add(result, "\L")
result.add(x); result.add("\L")
else:
# ignore empty lines
add(result, "\"")
add(result, x)
add(result, "\\n\"\n")
result.add("\"")
result.add(x)
result.add("\\n\"\n")
else:
res.add("\L")
result = res.rope
@ -1139,25 +1131,25 @@ proc genAsmStmt(p: BProc, t: PNode) =
# work:
if p.prc == nil:
# top level asm statement?
add(p.module.s[cfsProcHeaders], runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s]))
p.module.s[cfsProcHeaders].add runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s])
else:
add(p.s(cpsStmts), indentLine(p, runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s])))
p.s(cpsStmts).add indentLine(p, runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s]))
proc determineSection(n: PNode): TCFileSection =
result = cfsProcHeaders
if n.len >= 1 and n.sons[0].kind in {nkStrLit..nkTripleStrLit}:
let sec = n.sons[0].strVal
if n.len >= 1 and n[0].kind in {nkStrLit..nkTripleStrLit}:
let sec = n[0].strVal
if sec.startsWith("/*TYPESECTION*/"): result = cfsTypes
elif sec.startsWith("/*VARSECTION*/"): result = cfsVars
elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders
proc genEmit(p: BProc, t: PNode) =
var s = genAsmOrEmitStmt(p, t.sons[1])
var s = genAsmOrEmitStmt(p, t[1])
if p.prc == nil:
# top level emit pragma?
let section = determineSection(t[1])
genCLineDir(p.module.s[section], t.info, p.config)
add(p.module.s[section], s)
p.module.s[section].add(s)
else:
genLineDir(p, t)
line(p, cpsStmts, s)
@ -1169,18 +1161,18 @@ proc genPragma(p: BProc, n: PNode) =
of wInjectStmt:
var p = newProc(nil, p.module)
p.options = p.options - {optLineTrace, optStackTrace}
genStmts(p, it.sons[1])
genStmts(p, it[1])
p.module.injectStmt = p.s(cpsStmts)
else: discard
proc fieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
if optFieldCheck in p.options:
var le = asgn.sons[0]
var le = asgn[0]
if le.kind == nkCheckedFieldExpr:
var field = le.sons[0].sons[1].sym
var field = le[0][1].sym
result = sfDiscriminant in field.flags
elif le.kind == nkDotExpr:
var field = le.sons[1].sym
var field = le[1].sym
result = sfDiscriminant in field.flags
proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
@ -1188,14 +1180,13 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
var t = skipTypes(objtype, abstractVar)
assert t.kind == tyObject
discard genTypeInfo(p.module, t, a.lode.info)
var L = toInt64(lengthOrd(p.config, field.typ))
if not containsOrIncl(p.module.declaredThings, field.id):
appcg(p.module, cfsVars, "extern $1",
[discriminatorTableDecl(p.module, t, field)])
lineCg(p, cpsStmts,
"#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
intLiteral(L+1)])
intLiteral(toInt64(lengthOrd(p.config, field.typ))+1)])
proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLoc) =
const ObjDiscMappingProcSlot = -5
@ -1214,12 +1205,12 @@ proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLo
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
var a, tmp: TLoc
var dotExpr = e.sons[0]
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr.sons[0]
initLocExpr(p, e.sons[0], a)
var dotExpr = e[0]
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr[0]
initLocExpr(p, e[0], a)
getTemp(p, a.t, tmp)
expr(p, e.sons[1], tmp)
let field = dotExpr.sons[1].sym
expr(p, e[1], tmp)
let field = dotExpr[1].sym
if optTinyRtti in p.config.globalOptions:
let t = dotExpr[0].typ.skipTypes(abstractInst)
var oldVal, newVal: TLoc
@ -1229,13 +1220,13 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
"#nimFieldDiscriminantCheckV2($1, $2);$n",
[rdLoc(oldVal), rdLoc(newVal)])
else:
genDiscriminantCheck(p, a, tmp, dotExpr.sons[0].typ, field)
genDiscriminantCheck(p, a, tmp, dotExpr[0].typ, field)
genAssignment(p, a, tmp, {})
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
if e.sons[0].kind == nkSym and sfGoto in e.sons[0].sym.flags:
if e[0].kind == nkSym and sfGoto in e[0].sym.flags:
genLineDir(p, e)
genGotoVar(p, e.sons[1])
genGotoVar(p, e[1])
elif not fieldDiscriminantCheckNeeded(p, e):
let le = e[0]
let ri = e[1]