NIR: progress (#22817)

Done:

- [x] Implement conversions to openArray/varargs.
- [x] Implement index/range checking.
This commit is contained in:
Andreas Rumpf
2023-10-12 23:33:38 +02:00
committed by GitHub
parent d790112ea4
commit 8990626ca9
16 changed files with 281 additions and 101 deletions

View File

@@ -2157,7 +2157,7 @@ proc toHumanStr*(kind: TTypeKind): string =
## strips leading `tk`
result = toHumanStrImpl(kind, 2)
proc skipAddr*(n: PNode): PNode {.inline.} =
proc skipHiddenAddr*(n: PNode): PNode {.inline.} =
(if n.kind == nkHiddenAddr: n[0] else: n)
proc isNewStyleConcept*(n: PNode): bool {.inline.} =

View File

@@ -2279,9 +2279,6 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
else:
binaryArith(p, e, d, m)
proc skipAddr(n: PNode): PNode =
result = if n.kind in {nkAddr, nkHiddenAddr}: n[0] else: n
proc genWasMoved(p: BProc; n: PNode) =
var a: TLoc
let n1 = n[1].skipAddr

View File

@@ -1162,7 +1162,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
var returnStmt: Rope = ""
assert(prc.ast != nil)
var procBody = transformBody(m.g.graph, m.idgen, prc, dontUseCache)
var procBody = transformBody(m.g.graph, m.idgen, prc, {})
if sfInjectDestructors in prc.flags:
procBody = injectDestructorCalls(m.g.graph, m.idgen, prc, procBody)

View File

@@ -2718,7 +2718,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
else:
returnStmt = "return $#;$n" % [a.res]
var transformedBody = transformBody(p.module.graph, p.module.idgen, prc, dontUseCache)
var transformedBody = transformBody(p.module.graph, p.module.idgen, prc, {})
if sfInjectDestructors in prc.flags:
transformedBody = injectDestructorCalls(p.module.graph, p.module.idgen, prc, transformedBody)

View File

@@ -449,7 +449,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
if innerProc:
if s.isIterator: c.somethingToDo = true
if not c.processed.containsOrIncl(s.id):
let body = transformBody(c.graph, c.idgen, s, useCache)
let body = transformBody(c.graph, c.idgen, s, {useCache})
detectCapturedVars(body, s, c)
let ow = s.skipGenericOwner
let innerClosure = innerProc and s.typ.callConv == ccClosure and not s.isIterator
@@ -755,7 +755,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
# echo renderTree(s.getBody, {renderIds})
let oldInContainer = c.inContainer
c.inContainer = 0
var body = transformBody(d.graph, d.idgen, s, dontUseCache)
var body = transformBody(d.graph, d.idgen, s, {})
body = liftCapturedVars(body, s, d, c)
if c.envVars.getOrDefault(s.id).isNil:
s.transformedBody = body
@@ -879,7 +879,7 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType;
fn.typ.callConv = oldCC
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
idgen: IdGenerator, force: bool): PNode =
idgen: IdGenerator; flags: TransformFlags): PNode =
# XXX backend == backendJs does not suffice! The compiletime stuff needs
# the transformation even when compiling to JS ...
@@ -888,7 +888,7 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
if body.kind == nkEmpty or (
g.config.backend == backendJs and not isCompileTime) or
(fn.skipGenericOwner.kind != skModule and not force):
(fn.skipGenericOwner.kind != skModule and force notin flags):
# ignore forward declaration:
result = body

View File

@@ -45,6 +45,7 @@ type
locGen: int
m: ModuleCon
prc: PSym
options: TOptions
proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; module: PSym): ModuleCon =
result = ModuleCon(graph: graph, types: initTypesCon(config), slotGenerator: new(int),
@@ -61,7 +62,9 @@ proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; m
result.nativeUIntId = UInt16Id
proc initProcCon*(m: ModuleCon; prc: PSym; config: ConfigRef): ProcCon =
ProcCon(m: m, sm: initSlotManager({}, m.slotGenerator), prc: prc, config: config)
ProcCon(m: m, sm: initSlotManager({}, m.slotGenerator), prc: prc, config: config,
options: if prc != nil: prc.options
else: config.options)
proc toLineInfo(c: var ProcCon; i: TLineInfo): PackedLineInfo =
var val: LitId
@@ -476,14 +479,21 @@ proc genField(c: var ProcCon; n: PNode; d: var Value) =
d.addImmediateVal toLineInfo(c, n.info), pos
proc genIndex(c: var ProcCon; n: PNode; arr: PType; d: var Value) =
let info = toLineInfo(c, n.info)
if arr.skipTypes(abstractInst).kind == tyArray and
(let x = firstOrd(c.config, arr); x != Zero):
let info = toLineInfo(c, n.info)
buildTyped d, info, Sub, c.m.nativeIntId:
c.gen(n, d)
d.addImmediateVal toLineInfo(c, n.info), toInt(x)
else:
c.gen(n, d)
if optBoundsCheck in c.options:
let idx = move d
build d, info, CheckedIndex:
copyTree d.Tree, idx
let x = toInt64 lengthOrd(c.config, arr)
d.Tree.addIntVal c.m.integers, info, c.m.nativeIntId, x
d.Tree.addLabel info, CheckedGoto, c.exitLabel
proc genNew(c: var ProcCon; n: PNode; needsInit: bool) =
# If in doubt, always follow the blueprint of the C code generator for `mm:orc`.
@@ -586,6 +596,8 @@ proc genBinaryOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) =
let t = typeToIr(c.m.types, n.typ)
template body(target) =
buildTyped target, info, opc, t:
if optOverflowCheck in c.options and opc in {CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedMod}:
c.code.addLabel info, CheckedGoto, c.exitLabel
copyTree target, tmp
copyTree target, tmp2
intoDest d, info, t, body
@@ -688,10 +700,16 @@ proc genUnaryMinus(c: var ProcCon; n: PNode; d: var Value) =
c.freeTemp(tmp)
proc genHigh(c: var ProcCon; n: PNode; d: var Value) =
let subOpr = createMagic(c.m.graph, c.m.idgen, "-", mSubI)
let lenOpr = createMagic(c.m.graph, c.m.idgen, "len", mLengthOpenArray)
let asLenExpr = subOpr.buildCall(lenOpr.buildCall(n[1]), nkIntLit.newIntNode(1))
c.gen asLenExpr, d
let info = toLineInfo(c, n.info)
let t = typeToIr(c.m.types, n.typ)
var x = default(Value)
genArrayLen(c, n, x)
template body(target) =
buildTyped target, info, Sub, t:
copyTree target, x
target.addIntVal(c.m.integers, info, t, 1)
intoDest d, info, t, body
c.freeTemp x
proc genBinaryCp(c: var ProcCon; n: PNode; d: var Value; compilerProc: string) =
let info = toLineInfo(c, n.info)
@@ -1365,6 +1383,81 @@ proc genDefault(c: var ProcCon; n: PNode; d: var Value) =
let m = expandDefault(n.typ, n.info)
gen c, m, d
proc genWasMoved(c: var ProcCon; n: PNode) =
let n1 = n[1].skipAddr
# XXX We need a way to replicate this logic or better yet a better
# solution for injectdestructors.nim:
#if c.withinBlockLeaveActions > 0 and notYetAlive(n1):
var d = c.genx(n1)
assert not isEmpty(d)
let m = expandDefault(n1.typ, n1.info)
gen c, m, d
proc genMove(c: var ProcCon; n: PNode; d: var Value) =
let info = toLineInfo(c, n.info)
let n1 = n[1].skipAddr
var a = c.genx(n1)
if n.len == 4:
# generated by liftdestructors:
let src = c.genx(n[2])
# if ($1.p == $2.p) goto lab1
let lab1 = newLabel(c.labelGen)
let payloadType = seqPayloadPtrType(c.m.types, n1.typ)
buildTyped c.code, info, Select, Bool8Id:
buildTyped c.code, info, Eq, payloadType:
buildTyped c.code, info, FieldAt, payloadType:
copyTree c.code, a
c.code.addImmediateVal info, 1 # (len, p)-pair
buildTyped c.code, info, FieldAt, payloadType:
copyTree c.code, src
c.code.addImmediateVal info, 1 # (len, p)-pair
build c.code, info, SelectPair:
build c.code, info, SelectValue:
c.code.boolVal(info, true)
c.code.gotoLabel info, Goto, lab1
gen(c, n[3])
c.patch n, lab1
buildTyped c.code, info, Asgn, typeToIr(c.m.types, n1.typ):
copyTree c.code, a
copyTree c.code, src
else:
if isEmpty(d): d = getTemp(c, n)
buildTyped c.code, info, Asgn, typeToIr(c.m.types, n1.typ):
copyTree c.code, d
copyTree c.code, a
var op = getAttachedOp(c.m.graph, n.typ, attachedWasMoved)
if op == nil or skipTypes(n1.typ, abstractVar+{tyStatic}).kind in {tyOpenArray, tyVarargs}:
let m = expandDefault(n1.typ, n1.info)
gen c, m, a
else:
var opB = c.genx(newSymNode(op))
buildTyped c.code, info, Call, typeToIr(c.m.types, n.typ):
copyTree c.code, opB
buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.types.g, typeToIr(c.m.types, n1.typ)):
copyTree c.code, a
proc genDestroy(c: var ProcCon; n: PNode) =
let t = n[1].typ.skipTypes(abstractInst)
case t.kind
of tyString:
var unused = default(Value)
genUnaryCp(c, n, unused, "nimDestroyStrV1")
of tySequence:
#[
var a = initLocExpr(c, arg)
linefmt(c, cpsStmts, "if ($1.p && ($1.p->cap & NIM_STRLIT_FLAG) == 0) {$n" &
" #alignedDealloc($1.p, NIM_ALIGNOF($2));$n" &
"}$n",
[rdLoc(a), getTypeDesc(c.module, t.lastSon)])
]#
globalError(c.config, n.info, "not implemented: =destroy for seqs")
else: discard "nothing to do"
proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
case m
of mAnd: c.genAndOr(n, opcFJmp, d)
@@ -1391,9 +1484,9 @@ proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
of mNewString, mNewStringOfCap, mExit: c.genCall(n, d)
of mLengthOpenArray, mLengthArray, mLengthSeq, mLengthStr:
genArrayLen(c, n, d)
of mMulI: genBinaryOp(c, n, d, Mul)
of mDivI: genBinaryOp(c, n, d, Div)
of mModI: genBinaryOp(c, n, d, Mod)
of mMulI: genBinaryOp(c, n, d, CheckedMul)
of mDivI: genBinaryOp(c, n, d, CheckedDiv)
of mModI: genBinaryOp(c, n, d, CheckedMod)
of mAddF64: genBinaryOp(c, n, d, Add)
of mSubF64: genBinaryOp(c, n, d, Sub)
of mMulF64: genBinaryOp(c, n, d, Mul)
@@ -1495,7 +1588,6 @@ proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
localError(c.config, n.info, sizeOfLikeMsg("offsetof"))
of mRunnableExamples:
discard "just ignore any call to runnableExamples"
of mDestroy, mTrace: discard "ignore calls to the default destructor"
of mOf: genOf(c, n, d)
of mAppendStrStr:
unused(c, n, d)
@@ -1522,49 +1614,23 @@ proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
of mConStrStr: genStrConcat(c, n, d)
of mDefault, mZeroDefault:
genDefault c, n, d
of mMove: genMove(c, n, d)
of mWasMoved, mReset:
unused(c, n, d)
genWasMoved(c, n)
of mDestroy: genDestroy(c, n)
#of mAccessEnv: unaryExpr(d, n, d, "$1.ClE_0")
#of mAccessTypeField: genAccessTypeField(c, n, d)
#of mSlice: genSlice(c, n, d)
of mTrace: discard "no code to generate"
else:
# mGCref, mGCunref,
# mGCref, mGCunref: unused by ORC
globalError(c.config, n.info, "cannot generate code for: " & $m)
#[
of mReset:
unused(c, n, d)
var d = c.genx(n[1])
# XXX use ldNullOpcode() here?
c.gABx(n, opcLdNull, d, c.genType(n[1].typ))
c.gABC(n, opcNodeToReg, d, d)
c.gABx(n, ldNullOpcode(n.typ), d, c.genType(n.typ))
of mConStrStr: genVarargsABC(c, n, d, opcConcatStr)
of mRepr: genUnaryABC(c, n, d, opcRepr)
of mSlice:
var
d = c.genx(n[1])
left = c.genIndex(n[2], n[1].typ)
right = c.genIndex(n[3], n[1].typ)
if isEmpty(d): d = c.getTemp(n)
c.gABC(n, opcNodeToReg, d, d)
c.gABC(n, opcSlice, d, left, right)
c.freeTemp(left)
c.freeTemp(right)
c.freeTemp(d)
of mMove:
let arg = n[1]
let a = c.genx(arg)
if isEmpty(d): d = c.getTemp(arg)
gABC(c, arg, whichAsgnOpc(arg, requiresCopy=false), d, a)
c.freeTemp(a)
of mDup:
let arg = n[1]
let a = c.genx(arg)
if isEmpty(d): d = c.getTemp(arg)
gABC(c, arg, whichAsgnOpc(arg, requiresCopy=false), d, a)
c.freeTemp(a)
of mNodeId:
c.genUnaryABC(n, d, opcNodeId)
@@ -1764,6 +1830,63 @@ proc genDeref(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
valueIntoDest c, info, d, n.typ, body
freeTemp c, tmp
proc addAddrOfFirstElem(c: var ProcCon; target: var Tree; info: PackedLineInfo; tmp: Value; typ: PType) =
let arrType = typ.skipTypes(abstractVar)
let elemType = arrayPtrTypeOf(c.m.types.g, typeToIr(c.m.types, arrType.lastSon))
case arrType.kind
of tyString:
let t = typeToIr(c.m.types, typ.lastSon)
target.addImmediateVal info, 0
buildTyped target, info, AddrOf, elemType:
buildTyped target, info, ArrayAt, t:
buildTyped target, info, FieldAt, strPayloadPtrType(c.m.types):
copyTree target, tmp
target.addImmediateVal info, 1 # (len, p)-pair
target.addIntVal c.m.integers, info, c.m.nativeIntId, 0
# len:
target.addImmediateVal info, 1
buildTyped target, info, FieldAt, c.m.nativeIntId:
copyTree target, tmp
target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
of tySequence:
let t = typeToIr(c.m.types, typ.lastSon)
target.addImmediateVal info, 0
buildTyped target, info, AddrOf, elemType:
buildTyped target, info, ArrayAt, t:
buildTyped target, info, FieldAt, seqPayloadPtrType(c.m.types, typ):
copyTree target, tmp
target.addImmediateVal info, 1 # (len, p)-pair
target.addIntVal c.m.integers, info, c.m.nativeIntId, 0
# len:
target.addImmediateVal info, 1
buildTyped target, info, FieldAt, c.m.nativeIntId:
copyTree target, tmp
target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
of tyArray:
let t = typeToIr(c.m.types, typ.lastSon)
target.addImmediateVal info, 0
buildTyped target, info, AddrOf, elemType:
buildTyped target, info, ArrayAt, t:
copyTree target, tmp
target.addIntVal c.m.integers, info, c.m.nativeIntId, 0
target.addImmediateVal info, 1
target.addIntVal(c.m.integers, info, c.m.nativeIntId, toInt lengthOrd(c.config, typ))
else:
raiseAssert "addAddrOfFirstElem: " & typeToString(typ)
proc genToOpenArrayConv(c: var ProcCon; arg: PNode; d: var Value; flags: GenFlags; destType: PType) =
let info = toLineInfo(c, arg.info)
let tmp = c.genx(arg, flags)
let arrType = destType.skipTypes(abstractVar)
template body(target) =
buildTyped target, info, ObjConstr, typeToIr(c.m.types, arrType):
c.addAddrOfFirstElem target, info, tmp, arg.typ
valueIntoDest c, info, d, arrType, body
freeTemp c, tmp
proc genConv(c: var ProcCon; n, arg: PNode; d: var Value; flags: GenFlags; opc: Opcode) =
let targetType = n.typ.skipTypes({tyDistinct})
let argType = arg.typ.skipTypes({tyDistinct})
@@ -1774,6 +1897,11 @@ proc genConv(c: var ProcCon; n, arg: PNode; d: var Value; flags: GenFlags; opc:
gen c, arg, d
return
if opc != Cast and targetType.skipTypes({tyVar, tyLent}).kind in {tyOpenArray, tyVarargs} and
argType.skipTypes({tyVar, tyLent}).kind notin {tyOpenArray, tyVarargs}:
genToOpenArrayConv c, arg, d, flags, n.typ
return
let info = toLineInfo(c, n.info)
let tmp = c.genx(arg, flags)
template body(target) =
@@ -1850,7 +1978,7 @@ proc genVarSection(c: var ProcCon; n: PNode) =
genAsgn2(c, vn, a[2])
else:
if a[2].kind == nkEmpty:
discard "XXX assign default value to location here"
genAsgn2(c, vn, expandDefault(vn.typ, vn.info))
else:
genAsgn2(c, vn, a[2])
@@ -1922,17 +2050,56 @@ proc genNilLit(c: var ProcCon; n: PNode; d: var Value) =
valueIntoDest c, info, d, n.typ, body
proc genRangeCheck(c: var ProcCon; n: PNode; d: var Value) =
# XXX to implement properly
gen c, n[0], d
if optRangeCheck in c.options:
let info = toLineInfo(c, n.info)
let tmp = c.genx n[0]
let a = c.genx n[1]
let b = c.genx n[2]
template body(target) =
buildTyped target, info, CheckedRange, typeToIr(c.m.types, n.typ):
copyTree target, tmp
copyTree target, a
copyTree target, b
target.addLabel info, CheckedGoto, c.exitLabel
valueIntoDest c, info, d, n.typ, body
freeTemp c, tmp
freeTemp c, a
freeTemp c, b
else:
gen c, n[0], d
type
IndexFor = enum
ForSeq, ForStr, ForOpenArray
proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor): Value =
if optBoundsCheck in c.options:
let info = toLineInfo(c, n.info)
result = default(Value)
let idx = genx(c, n)
build result, info, CheckedIndex:
copyTree result.Tree, idx
case kind
of ForSeq, ForStr:
buildTyped result, info, FieldAt, c.m.nativeIntId:
copyTree result.Tree, a
result.addImmediateVal info, 0 # (len, p)-pair
of ForOpenArray:
buildTyped result, info, FieldAt, c.m.nativeIntId:
copyTree result.Tree, a
result.addImmediateVal info, 1 # (p, len)-pair
result.Tree.addLabel info, CheckedGoto, c.exitLabel
freeTemp c, idx
else:
result = genx(c, n)
proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
let arrayKind = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
let info = toLineInfo(c, n.info)
case arrayKind
of tyString:
# XXX implement range check
let a = genx(c, n[0], flags)
let b = genx(c, n[1])
let b = genIndexCheck(c, n[1], a, ForStr)
let t = typeToIr(c.m.types, n.typ)
template body(target) =
buildTyped target, info, ArrayAt, t:
@@ -1966,9 +2133,8 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
freeTemp c, a
of tyOpenArray, tyVarargs:
# XXX implement range check
let a = genx(c, n[0], flags)
let b = genx(c, n[1])
let b = genIndexCheck(c, n[1], a, ForOpenArray)
let t = typeToIr(c.m.types, n.typ)
template body(target) =
buildTyped target, info, ArrayAt, t:
@@ -1981,7 +2147,6 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
freeTemp c, b
freeTemp c, a
of tyArray:
# XXX implement range check
let a = genx(c, n[0], flags)
var b = default(Value)
genIndex(c, n[1], n[0].typ, b)
@@ -1995,7 +2160,7 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
freeTemp c, a
of tySequence:
let a = genx(c, n[0], flags)
let b = genx(c, n[1])
let b = genIndexCheck(c, n[1], a, ForSeq)
let t = typeToIr(c.m.types, n.typ)
template body(target) =
buildTyped target, info, ArrayAt, t:
@@ -2047,7 +2212,7 @@ proc genProc(cOuter: var ProcCon; n: PNode) =
var c = initProcCon(cOuter.m, prc, cOuter.m.graph.config)
genParams(c, prc.typ.n)
let body = transformBody(c.m.graph, c.m.idgen, prc, useCache)
let body = transformBody(c.m.graph, c.m.idgen, prc, {useCache, keepOpenArrayConversions})
let info = toLineInfo(c, body.info)
build c.code, info, ProcDecl:

View File

@@ -66,6 +66,9 @@ type
SetExc,
TestExc,
CheckedRange,
CheckedIndex,
Call,
IndirectCall,
CheckedCall, # call that can raise

View File

@@ -239,6 +239,11 @@ proc ptrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
g.addType t
result = sealType(g, f)
proc arrayPtrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
let f = g.openType AArrayPtrTy
g.addType t
result = sealType(g, f)
proc toString*(dest: var string; g: TypeGraph; i: TypeId) =
case g[i].kind
of VoidTy: dest.add "void"

View File

@@ -459,7 +459,11 @@ proc typeToIr*(c: var TypesCon; t: PType): TypeId =
let a = openType(c.g, LastArrayTy)
c.g.addType(elemType)
result = sealType(c.g, a)
of tyNone, tyEmpty, tyUntyped, tyTyped, tyTypeDesc,
of tyUntyped, tyTyped:
# this avoids a special case for system.echo which is not a generic but
# uses `varargs[typed]`:
result = VoidId
of tyNone, tyEmpty, tyTypeDesc,
tyNil, tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:

View File

@@ -66,7 +66,7 @@ proc mergeBasicBlockInfo(parent: var BasicBlock; this: BasicBlock) {.inline.} =
proc wasMovedTarget(matches: var IntSet; branch: seq[PNode]; moveTarget: PNode): bool =
result = false
for i in 0..<branch.len:
if exprStructuralEquivalent(branch[i][1].skipAddr, moveTarget,
if exprStructuralEquivalent(branch[i][1].skipHiddenAddr, moveTarget,
strictSymEquality = true):
result = true
matches.incl i
@@ -76,7 +76,7 @@ proc intersect(summary: var seq[PNode]; branch: seq[PNode]) =
var i = 0
var matches = initIntSet()
while i < summary.len:
if wasMovedTarget(matches, branch, summary[i][1].skipAddr):
if wasMovedTarget(matches, branch, summary[i][1].skipHiddenAddr):
inc i
else:
summary.del i
@@ -87,7 +87,7 @@ proc intersect(summary: var seq[PNode]; branch: seq[PNode]) =
proc invalidateWasMoved(c: var BasicBlock; x: PNode) =
var i = 0
while i < c.wasMovedLocs.len:
if exprStructuralEquivalent(c.wasMovedLocs[i][1].skipAddr, x,
if exprStructuralEquivalent(c.wasMovedLocs[i][1].skipHiddenAddr, x,
strictSymEquality = true):
c.wasMovedLocs.del i
else:
@@ -96,7 +96,7 @@ proc invalidateWasMoved(c: var BasicBlock; x: PNode) =
proc wasMovedDestroyPair(c: var Con; b: var BasicBlock; d: PNode) =
var i = 0
while i < b.wasMovedLocs.len:
if exprStructuralEquivalent(b.wasMovedLocs[i][1].skipAddr, d[1].skipAddr,
if exprStructuralEquivalent(b.wasMovedLocs[i][1].skipHiddenAddr, d[1].skipHiddenAddr,
strictSymEquality = true):
b.wasMovedLocs[i].flags.incl nfMarkForDeletion
c.somethingTodo = true

View File

@@ -993,9 +993,9 @@ proc trackCall(tracked: PEffects; n: PNode) =
# consider this case: p(out x, x); we want to remark that 'x' is not
# initialized until after the call. Since we do this after we analysed the
# call, this is fine.
initVar(tracked, n[i].skipAddr, false)
initVar(tracked, n[i].skipHiddenAddr, false)
if strictFuncs in tracked.c.features and not tracked.inEnforcedNoSideEffects and
isDangerousLocation(n[i].skipAddr, tracked.owner):
isDangerousLocation(n[i].skipHiddenAddr, tracked.owner):
if sfNoSideEffect in tracked.owner.flags:
localError(tracked.config, n[i].info,
"cannot pass $1 to `var T` parameter within a strict func" % renderTree(n[i]))

View File

@@ -28,10 +28,11 @@ when defined(nimPreviewSlimSystem):
import std/assertions
type
TransformBodyFlag* = enum
dontUseCache, useCache
TransformFlag* = enum
useCache, keepOpenArrayConversions, force
TransformFlags* = set[TransformFlag]
proc transformBody*(g: ModuleGraph; idgen: IdGenerator, prc: PSym, flag: TransformBodyFlag, force = false): PNode
proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flags: TransformFlags): PNode
import closureiters, lambdalifting
@@ -50,9 +51,10 @@ type
module: PSym
transCon: PTransCon # top of a TransCon stack
inlining: int # > 0 if we are in inlining context (copy vars)
isIntroducingNewLocalVars: bool # true if we are in `introducingNewLocalVars` (don't transform yields)
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
deferDetected, tooEarly: bool
isIntroducingNewLocalVars: bool # true if we are in `introducingNewLocalVars` (don't transform yields)
flags: TransformFlags
graph: ModuleGraph
idgen: IdGenerator
@@ -116,7 +118,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
let s = n.sym
if s.typ != nil and s.typ.callConv == ccClosure:
if s.kind in routineKinds:
discard transformBody(c.graph, c.idgen, s, useCache)
discard transformBody(c.graph, c.idgen, s, {useCache}+c.flags)
if s.kind == skIterator:
if c.tooEarly: return n
else: return liftIterSym(c.graph, n, c.idgen, getCurrOwner(c))
@@ -552,11 +554,14 @@ proc transformConv(c: PTransf, n: PNode): PNode =
else:
result = transformSons(c, n)
of tyOpenArray, tyVarargs:
result = transform(c, n[1])
#result = transformSons(c, n)
result.typ = takeType(n.typ, n[1].typ, c.graph, c.idgen)
#echo n.info, " came here and produced ", typeToString(result.typ),
# " from ", typeToString(n.typ), " and ", typeToString(n[1].typ)
if keepOpenArrayConversions in c.flags:
result = transformSons(c, n)
else:
result = transform(c, n[1])
#result = transformSons(c, n)
result.typ = takeType(n.typ, n[1].typ, c.graph, c.idgen)
#echo n.info, " came here and produced ", typeToString(result.typ),
# " from ", typeToString(n.typ), " and ", typeToString(n[1].typ)
of tyCstring:
if source.kind == tyString:
result = newTransNode(nkStringToCString, n, 1)
@@ -774,7 +779,7 @@ proc transformFor(c: PTransf, n: PNode): PNode =
stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg, true))
idNodeTablePut(newC.mapping, formal, temp)
let body = transformBody(c.graph, c.idgen, iter, useCache)
let body = transformBody(c.graph, c.idgen, iter, {useCache}+c.flags)
pushInfoContext(c.graph.config, n.info)
inc(c.inlining)
stmtList.add(transform(c, body))
@@ -1137,13 +1142,8 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
popTransCon(c)
incl(result.flags, nfTransf)
proc openTransf(g: ModuleGraph; module: PSym, filename: string; idgen: IdGenerator): PTransf =
new(result)
result.contSyms = @[]
result.breakSyms = @[]
result.module = module
result.graph = g
result.idgen = idgen
proc openTransf(g: ModuleGraph; module: PSym, filename: string; idgen: IdGenerator; flags: TransformFlags): PTransf =
result = PTransf(module: module, graph: g, idgen: idgen, flags: flags)
proc flattenStmts(n: PNode) =
var goOn = true
@@ -1186,7 +1186,7 @@ template liftDefer(c, root) =
if c.deferDetected:
liftDeferAux(root)
proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flag: TransformBodyFlag, force = false): PNode =
proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flags: TransformFlags): PNode =
assert prc.kind in routineKinds
if prc.transformedBody != nil:
@@ -1195,8 +1195,8 @@ proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flag: Transfo
result = getBody(g, prc)
else:
prc.transformedBody = newNode(nkEmpty) # protects from recursion
var c = openTransf(g, prc.getModule, "", idgen)
result = liftLambdas(g, prc, getBody(g, prc), c.tooEarly, c.idgen, force)
var c = openTransf(g, prc.getModule, "", idgen, flags)
result = liftLambdas(g, prc, getBody(g, prc), c.tooEarly, c.idgen, flags)
result = processTransf(c, result, prc)
liftDefer(c, result)
result = liftLocalsIfRequested(prc, result, g.cache, g.config, c.idgen)
@@ -1206,7 +1206,7 @@ proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flag: Transfo
incl(result.flags, nfTransf)
if flag == useCache or prc.typ.callConv == ccInline:
if useCache in flags or prc.typ.callConv == ccInline:
# genProc for inline procs will be called multiple times from different modules,
# it is important to transform exactly once to get sym ids and locations right
prc.transformedBody = result
@@ -1217,21 +1217,21 @@ proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flag: Transfo
#if prc.name.s == "main":
# echo "transformed into ", renderTree(result, {renderIds})
proc transformStmt*(g: ModuleGraph; idgen: IdGenerator; module: PSym, n: PNode): PNode =
proc transformStmt*(g: ModuleGraph; idgen: IdGenerator; module: PSym, n: PNode; flags: TransformFlags = {}): PNode =
if nfTransf in n.flags:
result = n
else:
var c = openTransf(g, module, "", idgen)
var c = openTransf(g, module, "", idgen, flags)
result = processTransf(c, n, module)
liftDefer(c, result)
#result = liftLambdasForTopLevel(module, result)
incl(result.flags, nfTransf)
proc transformExpr*(g: ModuleGraph; idgen: IdGenerator; module: PSym, n: PNode): PNode =
proc transformExpr*(g: ModuleGraph; idgen: IdGenerator; module: PSym, n: PNode; flags: TransformFlags = {}): PNode =
if nfTransf in n.flags:
result = n
else:
var c = openTransf(g, module, "", idgen)
var c = openTransf(g, module, "", idgen, flags)
result = processTransf(c, n, module)
liftDefer(c, result)
# expressions are not to be injected with destructor calls as that

View File

@@ -234,3 +234,6 @@ proc isRunnableExamples*(n: PNode): bool =
# Templates and generics don't perform symbol lookups.
result = n.kind == nkSym and n.sym.magic == mRunnableExamples or
n.kind == nkIdent and n.ident.id == ord(wRunnableExamples)
proc skipAddr*(n: PNode): PNode {.inline.} =
result = if n.kind in {nkAddr, nkHiddenAddr}: n[0] else: n

View File

@@ -1295,7 +1295,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let ast = a.sym.ast.shallowCopy
for i in 0..<a.sym.ast.len:
ast[i] = a.sym.ast[i]
ast[bodyPos] = transformBody(c.graph, c.idgen, a.sym, useCache, force=true)
ast[bodyPos] = transformBody(c.graph, c.idgen, a.sym, {useCache, force})
ast.copyTree()
of opcSymOwner:
decodeB(rkNode)

View File

@@ -2388,7 +2388,7 @@ proc genProc(c: PCtx; s: PSym): int =
c.procToCodePos[s.id] = result
# thanks to the jmp we can add top level statements easily and also nest
# procs easily:
let body = transformBody(c.graph, c.idgen, s, if isCompileTimeProc(s): dontUseCache else: useCache)
let body = transformBody(c.graph, c.idgen, s, if isCompileTimeProc(s): {} else: {useCache})
let procStart = c.xjmp(body, opcJmp, 0)
var p = PProc(blocks: @[], sym: s)
let oldPrc = c.prc

View File

@@ -206,6 +206,9 @@ proc nimAddStrV1(s: var NimStringV2; src: NimStringV2) {.compilerRtl, inl.} =
prepareAdd(s, src.len)
appendString s, src
proc nimDestroyStrV1(s: NimStringV2) {.compilerRtl, inl.} =
frees(s)
func capacity*(self: string): int {.inline.} =
## Returns the current capacity of the string.
# See https://github.com/nim-lang/RFCs/issues/460