diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2020-05-19 21:42:53 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-19 21:42:53 +0200 |
commit | b35d370d885b07d3f4eca527197f42f532bdcf64 (patch) | |
tree | ac2de2a7fbe3e3646ef4e3063da4675473e233e1 /compiler | |
parent | e909486e5cde5a4a77cd6f21b42fc9ab38ec2ae6 (diff) | |
download | Nim-b35d370d885b07d3f4eca527197f42f532bdcf64.tar.gz |
specialize genericReset (#14398)
* progress * make tests green * maybe we also want to reset pointers, dunno * progress * cleanup; fixes #13879 [backport:1.2]
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ccgexprs.nim | 46 | ||||
-rw-r--r-- | compiler/ccgreset.nim | 94 | ||||
-rw-r--r-- | compiler/cgen.nim | 8 |
3 files changed, 123 insertions, 25 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 0b9958ee4..ec54081a2 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1194,9 +1194,11 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = proc genReset(p: BProc, n: PNode) = var a: TLoc initLocExpr(p, n[1], a) - linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", - [addrLoc(p.config, a), - genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)]) + specializeReset(p, a) + when false: + linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", + [addrLoc(p.config, a), + genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)]) proc genDefault(p: BProc; n: PNode; d: var TLoc) = if d.k == locNone: getTemp(p, n.typ, d, needsInit=true) @@ -2793,6 +2795,21 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope = else: globalError(p.config, info, "cannot create null element for: " & $t.kind) +proc caseObjDefaultBranch(obj: PNode; branch: Int128): int = + for i in 1 ..< obj.len: + for j in 0 .. obj[i].len - 2: + if obj[i][j].kind == nkRange: + let x = getOrdValue(obj[i][j][0]) + let y = getOrdValue(obj[i][j][1]) + if branch >= x and branch <= y: + return i + elif getOrdValue(obj[i][j]) == branch: + return i + if obj[i].len == 1: + # else branch + return i + assert(false, "unreachable") + proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode, result: var Rope; count: var int; isConst: bool, info: TLineInfo) = @@ -2815,31 +2832,14 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode, branch = getOrdValue(constOrNil[i]) break - var selectedBranch = -1 - block branchSelection: - for i in 1 ..< obj.len: - for j in 0 .. obj[i].len - 2: - if obj[i][j].kind == nkRange: - let x = getOrdValue(obj[i][j][0]) - let y = getOrdValue(obj[i][j][1]) - if branch >= x and branch <= y: - selectedBranch = i - break branchSelection - elif getOrdValue(obj[i][j]) == branch: - selectedBranch = i - break branchSelection - if obj[i].len == 1: - # else branch - selectedBranch = i - assert(selectedBranch >= 1) - + let selectedBranch = caseObjDefaultBranch(obj, branch) result.add "{" var countB = 0 let b = lastSon(obj[selectedBranch]) # designated initilization is the only way to init non first element of unions # branches are allowed to have no members (b.len == 0), in this case they don't need initializer - if b.kind == nkRecList and b.len > 0: - result.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {" + if b.kind == nkRecList and b.len > 0: + result.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {" getNullValueAux(p, t, b, constOrNil, result, countB, isConst, info) result.add "}" elif b.kind == nkSym: diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim new file mode 100644 index 000000000..ef1505f57 --- /dev/null +++ b/compiler/ccgreset.nim @@ -0,0 +1,94 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# included from cgen.nim + +## Code specialization instead of the old, incredibly slow 'genericReset' +## implementation. + +proc specializeResetT(p: BProc, accessor: Rope, typ: PType) + +proc specializeResetN(p: BProc, accessor: Rope, n: PNode; + typ: PType) = + if n == nil: return + case n.kind + of nkRecList: + for i in 0..<n.len: + specializeResetN(p, accessor, n[i], typ) + of nkRecCase: + if (n[0].kind != nkSym): internalError(p.config, n.info, "specializeResetN") + let disc = n[0].sym + if disc.loc.r == nil: fillObjectFields(p.module, typ) + if disc.loc.t == nil: + internalError(p.config, n.info, "specializeResetN()") + lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r]) + for i in 1..<n.len: + let branch = n[i] + assert branch.kind in {nkOfBranch, nkElse} + if branch.kind == nkOfBranch: + genCaseRange(p, branch) + else: + lineF(p, cpsStmts, "default:$n", []) + specializeResetN(p, accessor, lastSon(branch), typ) + lineF(p, cpsStmts, "break;$n", []) + lineF(p, cpsStmts, "} $n", []) + specializeResetT(p, "$1.$2" % [accessor, disc.loc.r], disc.loc.t) + of nkSym: + let field = n.sym + if field.typ.kind == tyVoid: return + if field.loc.r == nil: fillObjectFields(p.module, typ) + if field.loc.t == nil: + internalError(p.config, n.info, "specializeResetN()") + specializeResetT(p, "$1.$2" % [accessor, field.loc.r], field.loc.t) + else: internalError(p.config, n.info, "specializeResetN()") + +proc specializeResetT(p: BProc, accessor: Rope, typ: PType) = + if typ == nil: return + + case typ.kind + of tyGenericInst, tyGenericBody, tyTypeDesc, tyAlias, tyDistinct, tyInferred, + tySink, tyOwned: + specializeResetT(p, accessor, lastSon(typ)) + of tyArray: + let arraySize = lengthOrd(p.config, typ[0]) + var i: TLoc + getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) + linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", + [i.r, arraySize]) + specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.r]), typ[1]) + lineF(p, cpsStmts, "}$n", []) + of tyObject: + for i in 0..<typ.len: + var x = typ[i] + if x != nil: x = x.skipTypes(skipPtrs) + specializeResetT(p, accessor.parentObj(p.module), x) + if typ.n != nil: specializeResetN(p, accessor, typ.n, typ) + of tyTuple: + let typ = getUniqueType(typ) + for i in 0..<typ.len: + specializeResetT(p, ropecg(p.module, "$1.Field$2", [accessor, i]), typ[i]) + + of tyString, tyRef, tySequence: + lineCg(p, cpsStmts, "#unsureAsgnRef((void**)&$1, NIM_NIL);$n", [accessor]) + + of tyProc: + if typ.callConv == ccClosure: + lineCg(p, cpsStmts, "#unsureAsgnRef((void**)&$1.ClE_0, NIM_NIL);$n", [accessor]) + lineCg(p, cpsStmts, "$1.ClP_0 = NIM_NIL;$n", [accessor]) + else: + lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor]) + of tyChar, tyBool, tyEnum, tyInt..tyUInt64: + lineCg(p, cpsStmts, "$1 = 0;$n", [accessor]) + of tyCString, tyPointer, tyPtr, tyVar, tyLent: + lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor]) + else: + discard + +proc specializeReset(p: BProc, a: TLoc) = + specializeResetT(p, rdLoc(a), a.t) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index c32e86a88..8fa824fcc 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -390,6 +390,8 @@ proc isComplexValueType(t: PType): bool {.inline.} = result = t.kind in {tyArray, tySet, tyTuple, tyObject} or (t.kind == tyProc and t.callConv == ccClosure) +include ccgreset + proc resetLoc(p: BProc, loc: var TLoc) = let containsGcRef = optSeqDestructors notin p.config.globalOptions and containsGarbageCollectedRef(loc.t) let typ = skipTypes(loc.t, abstractVarRange) @@ -407,8 +409,10 @@ proc resetLoc(p: BProc, loc: var TLoc) = linefmt(p, cpsStmts, "$1 = 0;$n", [rdLoc(loc)]) else: if loc.storage != OnStack and containsGcRef: - linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", - [addrLoc(p.config, loc), genTypeInfo(p.module, loc.t, loc.lode.info)]) + specializeReset(p, loc) + when false: + linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", + [addrLoc(p.config, loc), genTypeInfo(p.module, loc.t, loc.lode.info)]) # XXX: generated reset procs should not touch the m_type # field, so disabling this should be safe: genObjectInit(p, cpsStmts, loc.t, loc, constructObj) |