diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2023-10-12 23:33:38 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-12 23:33:38 +0200 |
commit | 8990626ca9715a3687b28331aee4ccf242997aa2 (patch) | |
tree | 792a4d375eb3ad77cb9764001029b56c62c2416b /compiler/nir | |
parent | d790112ea4600c847fed830171333fde308421a3 (diff) | |
download | Nim-8990626ca9715a3687b28331aee4ccf242997aa2.tar.gz |
NIR: progress (#22817)
Done: - [x] Implement conversions to openArray/varargs. - [x] Implement index/range checking.
Diffstat (limited to 'compiler/nir')
-rw-r--r-- | compiler/nir/ast2ir.nim | 277 | ||||
-rw-r--r-- | compiler/nir/nirinsts.nim | 3 | ||||
-rw-r--r-- | compiler/nir/nirtypes.nim | 5 | ||||
-rw-r--r-- | compiler/nir/types2ir.nim | 6 |
4 files changed, 234 insertions, 57 deletions
diff --git a/compiler/nir/ast2ir.nim b/compiler/nir/ast2ir.nim index bc7348be3..fcda145ea 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 f037b4f0e..2c0dc3d11 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 d989397a6..a42feab00 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 6d163c6c7..835bef03c 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: |