From 7f4d2ede806b67dc7257e2664b2d9f9b2d512502 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 14 Apr 2025 22:38:14 +0800 Subject: [PATCH] fixes inefficient codegen for field return --- compiler/injectdestructors.nim | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 932851a3cad9..b941c78ef6b8 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -100,6 +100,7 @@ when false: proc isLastReadImpl(n: PNode; c: var Con; scope: var Scope): bool = let root = parampatterns.exprRoot(n, allowCalls=false) if root == nil: return false + elif sfSingleUsedTemp in root.flags: return true var s = addr(scope) while s != nil: @@ -167,8 +168,7 @@ proc isLastRead(n: PNode; c: var Con; s: var Scope): bool = if not hasDestructor(c, n.typ) and (n.typ.kind != tyObject or isTrival(getAttachedOp(c.graph, n.typ, attachedAsgn))): return true let m = skipConvDfa(n) - result = (m.kind == nkSym and sfSingleUsedTemp in m.sym.flags) or - isLastReadImpl(n, c, s) + result = isLastReadImpl(n, c, s) proc isFirstWrite(n: PNode; c: var Con): bool = let m = skipConvDfa(n) @@ -1122,6 +1122,25 @@ proc genFieldAccessSideEffects(c: var Con; s: var Scope; dest, ri: PNode; flags: var snk = c.genSink(s, dest, newAccess, flags) result = newTree(nkStmtList, v, snk, c.genWasMoved(newAccess)) +proc ownsData(c: var Con; s: var Scope; orig: PNode; flags: set[MoveOrCopyFlag]): PNode = + var n = orig + while true: + case n.kind + of nkDotExpr, nkCheckedFieldExpr, nkBracketExpr: + n = n[0] + else: + break + if n.kind in nkCallKinds and n.typ != nil and hasDestructor(c, n.typ): + result = newNodeIT(nkStmtListExpr, orig.info, orig.typ) + let tmp = c.getTemp(s, n.typ, n.info) + tmp.sym.flags.incl sfSingleUsedTemp + result.add newTree(nkFastAsgn, tmp, copyTree(n)) + s.final.add c.genDestroy(tmp) + n[] = tmp[] + result.add copyTree(orig) + else: + result = nil + proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopyFlag] = {}): PNode = var ri = ri var isEnsureMove = 0 @@ -1205,7 +1224,11 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy of nkRaiseStmt: result = pRaiseStmt(ri, c, s) else: - if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s) and + let isOwnsData = ownsData(c, s, ri2, flags) + + if isOwnsData != nil: + result = moveOrCopy(dest, isOwnsData, c, s, flags) + elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s) and canBeMoved(c, dest.typ): # Rule 3: `=sink`(x, z); wasMoved(z) let snk = c.genSink(s, dest, ri, flags)