Double sink checks
This commit is contained in:
parent
e5b9d89bcf
commit
ae24b87219
2 changed files with 65 additions and 13 deletions
|
|
@ -116,7 +116,7 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
||||||
strutils, options, dfa, lowerings, tables, modulegraphs,
|
strutils, options, dfa, lowerings, tables, modulegraphs, msgs,
|
||||||
lineinfos, parampatterns
|
lineinfos, parampatterns
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -128,6 +128,8 @@ type
|
||||||
g: ControlFlowGraph
|
g: ControlFlowGraph
|
||||||
jumpTargets: IntSet
|
jumpTargets: IntSet
|
||||||
destroys, topLevelVars: PNode
|
destroys, topLevelVars: PNode
|
||||||
|
tracingSinkedParams: bool # we aren't checking double sink for proc args in if, case, loops since they possibly not taken
|
||||||
|
alreadySinkedParams: Table[int, TLineInfo]
|
||||||
graph: ModuleGraph
|
graph: ModuleGraph
|
||||||
emptyNode: PNode
|
emptyNode: PNode
|
||||||
otherRead: PNode
|
otherRead: PNode
|
||||||
|
|
@ -365,6 +367,16 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode =
|
||||||
result.add genWasMoved(n, c)
|
result.add genWasMoved(n, c)
|
||||||
result.add tempAsNode
|
result.add tempAsNode
|
||||||
|
|
||||||
|
proc sinkParamConsumed(c: var Con, s: PNode, tracing = true) =
|
||||||
|
assert s.kind == nkSym
|
||||||
|
let isConsumed =
|
||||||
|
if c.tracingSinkedParams and tracing:
|
||||||
|
c.alreadySinkedParams.hasKeyOrPut(s.sym.id, s.info)
|
||||||
|
else: c.alreadySinkedParams.hasKey(s.sym.id)
|
||||||
|
if isConsumed:
|
||||||
|
localError(c.graph.config, s.info, "sink parameter `" & $s.sym.name.s &
|
||||||
|
"` is already consumed at " & toFileLineCol(c. graph.config, c.alreadySinkedParams[s.sym.id]))
|
||||||
|
|
||||||
proc passCopyToSink(n: PNode; c: var Con): PNode =
|
proc passCopyToSink(n: PNode; c: var Con): PNode =
|
||||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||||
let tmp = getTemp(c, n.typ, n.info)
|
let tmp = getTemp(c, n.typ, n.info)
|
||||||
|
|
@ -399,10 +411,14 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||||
elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkBracket, nkCharLit..nkFloat128Lit}:
|
elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkBracket, nkCharLit..nkFloat128Lit}:
|
||||||
discard "object construction to sink parameter: nothing to do"
|
discard "object construction to sink parameter: nothing to do"
|
||||||
result = arg
|
result = arg
|
||||||
elif arg.kind == nkSym and (isSinkParam(arg.sym) or
|
elif arg.kind == nkSym and isSinkParam(arg.sym):
|
||||||
arg.sym.kind in InterestingSyms and isLastRead(arg, c)):
|
# Sinked params can be consumed only once. We need to reset the memory
|
||||||
# it is the last read be final consumption. We need to reset the memory
|
# to disable the destructor which we have not elided
|
||||||
# to disable the destructor which we have not elided:
|
result = destructiveMoveVar(arg, c)
|
||||||
|
sinkParamConsumed(c, arg)
|
||||||
|
elif arg.kind == nkSym and arg.sym.kind in InterestingSyms and isLastRead(arg, c):
|
||||||
|
# it is the last read, can be sinked. We need to reset the memory
|
||||||
|
# to disable the destructor which we have not elided
|
||||||
result = destructiveMoveVar(arg, c)
|
result = destructiveMoveVar(arg, c)
|
||||||
elif arg.kind in {nkBlockExpr, nkBlockStmt}:
|
elif arg.kind in {nkBlockExpr, nkBlockStmt}:
|
||||||
result = copyNode(arg)
|
result = copyNode(arg)
|
||||||
|
|
@ -415,6 +431,7 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||||
result.add pArg(arg[^1], c, isSink)
|
result.add pArg(arg[^1], c, isSink)
|
||||||
elif arg.kind in {nkIfExpr, nkIfStmt}:
|
elif arg.kind in {nkIfExpr, nkIfStmt}:
|
||||||
result = copyNode(arg)
|
result = copyNode(arg)
|
||||||
|
c.tracingSinkedParams = false
|
||||||
for i in 0..<arg.len:
|
for i in 0..<arg.len:
|
||||||
var branch = copyNode(arg[i])
|
var branch = copyNode(arg[i])
|
||||||
if arg[i].kind in {nkElifBranch, nkElifExpr}:
|
if arg[i].kind in {nkElifBranch, nkElifExpr}:
|
||||||
|
|
@ -423,9 +440,11 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||||
else:
|
else:
|
||||||
branch.add pArgIfTyped(arg[i][0])
|
branch.add pArgIfTyped(arg[i][0])
|
||||||
result.add branch
|
result.add branch
|
||||||
|
c.tracingSinkedParams = true
|
||||||
elif arg.kind == nkCaseStmt:
|
elif arg.kind == nkCaseStmt:
|
||||||
result = copyNode(arg)
|
result = copyNode(arg)
|
||||||
result.add p(arg[0], c)
|
result.add p(arg[0], c)
|
||||||
|
c.tracingSinkedParams = false
|
||||||
for i in 1..<arg.len:
|
for i in 1..<arg.len:
|
||||||
var branch: PNode
|
var branch: PNode
|
||||||
if arg[i].kind == nkOfbranch:
|
if arg[i].kind == nkOfbranch:
|
||||||
|
|
@ -439,6 +458,7 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||||
branch = copyNode(arg[i])
|
branch = copyNode(arg[i])
|
||||||
branch.add pArgIfTyped(arg[i][0])
|
branch.add pArgIfTyped(arg[i][0])
|
||||||
result.add branch
|
result.add branch
|
||||||
|
c.tracingSinkedParams = true
|
||||||
else:
|
else:
|
||||||
# an object that is not temporary but passed to a 'sink' parameter
|
# an object that is not temporary but passed to a 'sink' parameter
|
||||||
# results in a copy.
|
# results in a copy.
|
||||||
|
|
@ -482,6 +502,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||||
result.add moveOrCopy(dest, ri[1], c)
|
result.add moveOrCopy(dest, ri[1], c)
|
||||||
of nkIfExpr, nkIfStmt:
|
of nkIfExpr, nkIfStmt:
|
||||||
result = newNodeI(nkIfStmt, ri.info)
|
result = newNodeI(nkIfStmt, ri.info)
|
||||||
|
c.tracingSinkedParams = false
|
||||||
for i in 0..<ri.len:
|
for i in 0..<ri.len:
|
||||||
var branch = copyNode(ri[i])
|
var branch = copyNode(ri[i])
|
||||||
if ri[i].kind in {nkElifBranch, nkElifExpr}:
|
if ri[i].kind in {nkElifBranch, nkElifExpr}:
|
||||||
|
|
@ -490,9 +511,11 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||||
else:
|
else:
|
||||||
branch.add moveOrCopyIfTyped(ri[i][0])
|
branch.add moveOrCopyIfTyped(ri[i][0])
|
||||||
result.add branch
|
result.add branch
|
||||||
|
c.tracingSinkedParams = true
|
||||||
of nkCaseStmt:
|
of nkCaseStmt:
|
||||||
result = newNodeI(nkCaseStmt, ri.info)
|
result = newNodeI(nkCaseStmt, ri.info)
|
||||||
result.add p(ri[0], c)
|
result.add p(ri[0], c)
|
||||||
|
c.tracingSinkedParams = false
|
||||||
for i in 1..<ri.len:
|
for i in 1..<ri.len:
|
||||||
var branch: PNode
|
var branch: PNode
|
||||||
if ri[i].kind == nkOfbranch:
|
if ri[i].kind == nkOfbranch:
|
||||||
|
|
@ -506,6 +529,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||||
branch = copyNode(ri[i])
|
branch = copyNode(ri[i])
|
||||||
branch.add moveOrCopyIfTyped(ri[i][0])
|
branch.add moveOrCopyIfTyped(ri[i][0])
|
||||||
result.add branch
|
result.add branch
|
||||||
|
c.tracingSinkedParams = true
|
||||||
of nkBracket:
|
of nkBracket:
|
||||||
# array constructor
|
# array constructor
|
||||||
result = genSink(c, dest.typ, dest, ri)
|
result = genSink(c, dest.typ, dest, ri)
|
||||||
|
|
@ -535,7 +559,13 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||||
ri2[i] = pArg(ri[i], c, isSink = true)
|
ri2[i] = pArg(ri[i], c, isSink = true)
|
||||||
result.add ri2
|
result.add ri2
|
||||||
of nkSym:
|
of nkSym:
|
||||||
if isSinkParam(ri.sym) or (ri.sym.kind != skParam and isLastRead(ri, c)):
|
if isSinkParam(ri.sym):
|
||||||
|
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||||
|
var snk = genSink(c, dest.typ, dest, ri)
|
||||||
|
snk.add ri
|
||||||
|
result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved))
|
||||||
|
sinkParamConsumed(c, ri)
|
||||||
|
elif ri.sym.kind != skParam and isLastRead(ri, c):
|
||||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||||
var snk = genSink(c, dest.typ, dest, ri)
|
var snk = genSink(c, dest.typ, dest, ri)
|
||||||
snk.add ri
|
snk.add ri
|
||||||
|
|
@ -603,7 +633,28 @@ proc p(n: PNode; c: var Con): PNode =
|
||||||
else:
|
else:
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
recurse(n, result)
|
recurse(n, result)
|
||||||
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef,
|
of nkSym:
|
||||||
|
result = n
|
||||||
|
sinkParamConsumed(c, n, tracing = false)
|
||||||
|
of nkIfStmt, nkIfExpr:
|
||||||
|
c.tracingSinkedParams = false
|
||||||
|
result = copyNode(n)
|
||||||
|
recurse(n, result)
|
||||||
|
c.tracingSinkedParams = true
|
||||||
|
of nkCaseStmt, nkWhileStmt:
|
||||||
|
result = copyNode(n)
|
||||||
|
result.add p(n[0], c)
|
||||||
|
c.tracingSinkedParams = false
|
||||||
|
for i in 1..<n.len:
|
||||||
|
result.add p(n[i], c)
|
||||||
|
of nkForStmt:
|
||||||
|
result = copyNode(n)
|
||||||
|
for i in 1..n.len-2:
|
||||||
|
result.add p(n[i], c)
|
||||||
|
c.tracingSinkedParams = false
|
||||||
|
result.add p(n[^1], c)
|
||||||
|
c.tracingSinkedParams = true
|
||||||
|
of nkNone..pred(nkSym), succ(nkSym) .. nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef,
|
||||||
nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef:
|
nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef:
|
||||||
result = n
|
result = n
|
||||||
else:
|
else:
|
||||||
|
|
@ -617,6 +668,7 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
|
||||||
c.owner = owner
|
c.owner = owner
|
||||||
c.destroys = newNodeI(nkStmtList, n.info)
|
c.destroys = newNodeI(nkStmtList, n.info)
|
||||||
c.topLevelVars = newNodeI(nkVarSection, n.info)
|
c.topLevelVars = newNodeI(nkVarSection, n.info)
|
||||||
|
c.alreadySinkedParams = initTable[int, TLineInfo](8)
|
||||||
c.graph = g
|
c.graph = g
|
||||||
c.emptyNode = newNodeI(nkEmpty, n.info)
|
c.emptyNode = newNodeI(nkEmpty, n.info)
|
||||||
let cfg = constructCfg(owner, n)
|
let cfg = constructCfg(owner, n)
|
||||||
|
|
|
||||||
|
|
@ -67,17 +67,17 @@ proc `[]=`*(m: var Matrix, i, j: int, s: float) =
|
||||||
proc `-`*(m: sink Matrix): Matrix =
|
proc `-`*(m: sink Matrix): Matrix =
|
||||||
## Unary minus
|
## Unary minus
|
||||||
result = m
|
result = m
|
||||||
for i in 0 ..< m.m:
|
for i in 0 ..< result.m:
|
||||||
for j in 0 ..< m.n:
|
for j in 0 ..< result.n:
|
||||||
result[i, j] = -m[i, j]
|
result[i, j] = -result[i, j]
|
||||||
|
|
||||||
proc `+`*(a: sink Matrix; b: Matrix): Matrix =
|
proc `+`*(a: sink Matrix; b: Matrix): Matrix =
|
||||||
## ``C = A + B``
|
## ``C = A + B``
|
||||||
assert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.")
|
assert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.")
|
||||||
result = a
|
result = a
|
||||||
for i in 0 ..< a.m:
|
for i in 0 ..< result.m:
|
||||||
for j in 0 ..< a.n:
|
for j in 0 ..< result.n:
|
||||||
result[i, j] = a[i, j] + b[i, j]
|
result[i, j] = result[i, j] + b[i, j]
|
||||||
|
|
||||||
proc `-`*(a: sink Matrix; b: Matrix): Matrix =
|
proc `-`*(a: sink Matrix; b: Matrix): Matrix =
|
||||||
## ``C = A - B``
|
## ``C = A - B``
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue