diff --git a/compiler/ast.nim b/compiler/ast.nim index 4fe72929f7f8..3017aedcf6e8 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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.} = diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 44d04d7633a3..eca6fa9958a1 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -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 diff --git a/compiler/cgen.nim b/compiler/cgen.nim index adee8f8454b5..a2b2c429ef15 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -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) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 1720de17f899..6b57c097f3b7 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -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) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index ee19eec08147..fdba7ba3d147 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -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 diff --git a/compiler/nir/ast2ir.nim b/compiler/nir/ast2ir.nim index bc7348be3756..fcda145ea41f 100644 --- a/compiler/nir/ast2ir.nim +++ b/compiler/nir/ast2ir.nim @@ -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: diff --git a/compiler/nir/nirinsts.nim b/compiler/nir/nirinsts.nim index f037b4f0e0e8..2c0dc3d1143a 100644 --- a/compiler/nir/nirinsts.nim +++ b/compiler/nir/nirinsts.nim @@ -66,6 +66,9 @@ type SetExc, TestExc, + CheckedRange, + CheckedIndex, + Call, IndirectCall, CheckedCall, # call that can raise diff --git a/compiler/nir/nirtypes.nim b/compiler/nir/nirtypes.nim index d989397a6080..a42feab005c8 100644 --- a/compiler/nir/nirtypes.nim +++ b/compiler/nir/nirtypes.nim @@ -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" diff --git a/compiler/nir/types2ir.nim b/compiler/nir/types2ir.nim index 6d163c6c7c33..835bef03c8c8 100644 --- a/compiler/nir/types2ir.nim +++ b/compiler/nir/types2ir.nim @@ -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: diff --git a/compiler/optimizer.nim b/compiler/optimizer.nim index 56a0039babd0..7e46f3d0b5f4 100644 --- a/compiler/optimizer.nim +++ b/compiler/optimizer.nim @@ -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.. 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 diff --git a/compiler/trees.nim b/compiler/trees.nim index f038fbc1eb3c..e39cbafe6190 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -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 diff --git a/compiler/vm.nim b/compiler/vm.nim index 85c1305e94eb..fd03c4baeb0b 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1295,7 +1295,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let ast = a.sym.ast.shallowCopy for i in 0..