diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2023-10-29 14:47:22 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-29 14:47:22 +0100 |
commit | 0c26d19e228e831393cb5d2c1f43660362d349c9 (patch) | |
tree | 6b989d3175a5332dcd61489e22350f3748b89b09 | |
parent | 94ffc183323c859fc5a395404ac6035ae29cbc5a (diff) | |
download | Nim-0c26d19e228e831393cb5d2c1f43660362d349c9.tar.gz |
NIR: VM + refactorings (#22835)
-rw-r--r-- | compiler/ccgcalls.nim | 14 | ||||
-rw-r--r-- | compiler/ic/rodfiles.nim | 1 | ||||
-rw-r--r-- | compiler/nir/ast2ir.nim | 509 | ||||
-rw-r--r-- | compiler/nir/nir.nim | 55 | ||||
-rw-r--r-- | compiler/nir/nirc.nim | 69 | ||||
-rw-r--r-- | compiler/nir/nirfiles.nim | 73 | ||||
-rw-r--r-- | compiler/nir/nirinsts.nim | 97 | ||||
-rw-r--r-- | compiler/nir/nirtypes.nim | 28 | ||||
-rw-r--r-- | compiler/nir/nirvm.nim | 856 | ||||
-rw-r--r-- | compiler/nir/types2ir.nim | 481 | ||||
-rw-r--r-- | lib/system/ansi_c.nim | 4 |
11 files changed, 1538 insertions, 649 deletions
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 494f3c8c6..ad84be3f9 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -221,7 +221,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) = let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0]) result.add x & ", " & y else: - var a: TLoc = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n) + var a = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n) case skipTypes(a.t, abstractVar+{tyStatic}).kind of tyOpenArray, tyVarargs: if reifiedOpenArray(n): @@ -277,7 +277,7 @@ proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc = genAssignment(p, result, a, {}) proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} = - var a: TLoc = initLocExpr(p, n[0]) + var a = initLocExpr(p, n[0]) appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc]) proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) = @@ -287,7 +287,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: var n = if n.kind != nkHiddenAddr: n else: n[0] openArrayLoc(p, param.typ, n, result) - elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and + elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and (optByRef notin param.options or not p.module.compileToCpp): a = initLocExpr(p, n) if n.kind in {nkCharLit..nkNilLit}: @@ -417,7 +417,7 @@ proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) = proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = # this is a hotspot in the compiler - var op: TLoc = initLocExpr(p, ri[0]) + var op = initLocExpr(p, ri[0]) # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInstOwned) assert(typ.kind == tyProc) @@ -439,7 +439,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)" const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists - var op: TLoc = initLocExpr(p, ri[0]) + var op = initLocExpr(p, ri[0]) # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInstOwned) @@ -672,7 +672,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro result.add(substr(pat, start, i - 1)) proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = - var op: TLoc = initLocExpr(p, ri[0]) + var op = initLocExpr(p, ri[0]) # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInst) assert(typ.kind == tyProc) @@ -716,7 +716,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = # generates a crappy ObjC call - var op: TLoc = initLocExpr(p, ri[0]) + var op = initLocExpr(p, ri[0]) var pl = "[" # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInst) diff --git a/compiler/ic/rodfiles.nim b/compiler/ic/rodfiles.nim index 4968c5924..3505bfdfb 100644 --- a/compiler/ic/rodfiles.nim +++ b/compiler/ic/rodfiles.nim @@ -98,6 +98,7 @@ type backendFlagsSection aliveSymsSection # beware, this is stored in a `.alivesyms` file. sideChannelSection + symnamesSection RodFileError* = enum ok, tooBig, cannotOpen, ioFailure, wrongHeader, wrongSection, configMismatch, diff --git a/compiler/nir/ast2ir.nim b/compiler/nir/ast2ir.nim index 0920f5d8a..b1a90e9bf 100644 --- a/compiler/nir/ast2ir.nim +++ b/compiler/nir/ast2ir.nim @@ -15,22 +15,27 @@ from ".." / lowerings import lowerSwap, lowerTupleUnpacking from ".." / pathutils import customPath import .. / ic / bitabs -import nirtypes, nirinsts, nirlineinfos, nirslots, types2ir +import nirtypes, nirinsts, nirlineinfos, nirslots, types2ir, nirfiles when defined(nimCompilerStacktraceHints): import std/stackframes type ModuleCon* = ref object - man*: LineInfoManager - lit*: Literals - types*: TypesCon + nirm*: ref NirModule + types: TypesCon module*: PSym graph*: ModuleGraph + symnames*: SymNames nativeIntId, nativeUIntId: TypeId + strPayloadId: (TypeId, TypeId) idgen: IdGenerator - processedProcs: HashSet[ItemId] + processedProcs, pendingProcsAsSet: HashSet[ItemId] pendingProcs: seq[PSym] # procs we still need to generate code for + noModularity*: bool + inProc: int + toSymId: Table[ItemId, SymId] + symIdCounter: int32 ProcCon* = object config*: ConfigRef @@ -39,7 +44,7 @@ type lastFileVal: LitId labelGen: int exitLabel: LabelId - code*: Tree + #code*: Tree blocks: seq[(PSym, LabelId)] sm: SlotManager idgen: IdGenerator @@ -47,10 +52,13 @@ type prc: PSym options: TOptions -proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; module: PSym): ModuleCon = - let lit = Literals() # must be shared - result = ModuleCon(graph: graph, types: initTypesCon(config, lit), - idgen: idgen, module: module, lit: lit) +template code(c: ProcCon): Tree = c.m.nirm.code + +proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; module: PSym; + nirm: ref NirModule): ModuleCon = + #let lit = Literals() # must be shared + result = ModuleCon(graph: graph, types: initTypesCon(config), nirm: nirm, + idgen: idgen, module: module) case config.target.intSize of 2: result.nativeIntId = Int16Id @@ -61,10 +69,11 @@ proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; m else: result.nativeIntId = Int64Id result.nativeUIntId = UInt16Id + result.strPayloadId = strPayloadPtrType(result.types, result.nirm.types) proc initProcCon*(m: ModuleCon; prc: PSym; config: ConfigRef): ProcCon = ProcCon(m: m, sm: initSlotManager({}), prc: prc, config: config, - lit: m.lit, idgen: m.idgen, + lit: m.nirm.lit, idgen: m.idgen, options: if prc != nil: prc.options else: config.options) @@ -77,7 +86,7 @@ proc toLineInfo(c: var ProcCon; i: TLineInfo): PackedLineInfo = # remember the entry: c.lastFileKey = i.fileIndex c.lastFileVal = val - result = pack(c.m.man, val, int32 i.line, int32 i.col) + result = pack(c.m.nirm.man, val, int32 i.line, int32 i.col) proc bestEffort(c: ProcCon): TLineInfo = if c.prc != nil: @@ -112,15 +121,41 @@ proc freeTemp(c: var ProcCon; tmp: Value) = if s != SymId(-1): freeTemp(c.sm, s) +proc typeToIr(m: ModuleCon; t: PType): TypeId = + typeToIr(m.types, m.nirm.types, t) + +proc allocTemp(c: var ProcCon; t: TypeId): SymId = + if c.m.noModularity: + result = allocTemp(c.sm, t, c.m.symIdCounter) + else: + result = allocTemp(c.sm, t, c.idgen.symId) + +const + ListSymId = -1 + +proc toSymId(c: var ProcCon; s: PSym): SymId = + if c.m.noModularity: + result = c.m.toSymId.getOrDefault(s.itemId, SymId(-1)) + if result.int < 0: + inc c.m.symIdCounter + result = SymId(c.m.symIdCounter) + c.m.toSymId[s.itemId] = result + when ListSymId != -1: + if result.int == ListSymId or s.name.s == "echoBinSafe": + echo result.int, " is ", s.name.s, " ", c.m.graph.config $ s.info, " ", s.flags + writeStackTrace() + else: + result = SymId(s.itemId.item) + proc getTemp(c: var ProcCon; n: PNode): Value = let info = toLineInfo(c, n.info) - let t = typeToIr(c.m.types, n.typ) - let tmp = allocTemp(c.sm, t, c.idgen.symId) + let t = typeToIr(c.m, n.typ) + let tmp = allocTemp(c, t) c.code.addSummon info, tmp, t result = localToValue(info, tmp) proc getTemp(c: var ProcCon; t: TypeId; info: PackedLineInfo): Value = - let tmp = allocTemp(c.sm, t, c.idgen.symId) + let tmp = allocTemp(c, t) c.code.addSummon info, tmp, t result = localToValue(info, tmp) @@ -274,7 +309,7 @@ proc tempToDest(c: var ProcCon; n: PNode; d: var Value; tmp: Value) = else: let info = toLineInfo(c, n.info) build c.code, info, Asgn: - c.code.addTyped info, typeToIr(c.m.types, n.typ) + c.code.addTyped info, typeToIr(c.m, n.typ) c.code.copyTree d c.code.copyTree tmp freeTemp(c, tmp) @@ -369,7 +404,7 @@ proc genCase(c: var ProcCon; n: PNode; d: var Value) = let info = toLineInfo(c, n.info) withTemp(tmp, n[0]): build c.code, info, Select: - c.code.addTyped info, typeToIr(c.m.types, n[0].typ) + c.code.addTyped info, typeToIr(c.m, n[0].typ) c.gen(n[0], tmp) for i in 1..<n.len: let section = newLabel(c.labelGen) @@ -437,7 +472,7 @@ proc genCall(c: var ProcCon; n: PNode; d: var Value) = else: args.add genx(c, n[i]) - let tb = typeToIr(c.m.types, n.typ) + let tb = typeToIr(c.m, n.typ) if not isEmptyType(n.typ): if isEmpty(d): d = getTemp(c, n) # XXX Handle problematic aliasing here: `a = f_canRaise(a)`. @@ -450,7 +485,7 @@ proc genCall(c: var ProcCon; n: PNode; d: var Value) = proc genRaise(c: var ProcCon; n: PNode) = let info = toLineInfo(c, n.info) - let tb = typeToIr(c.m.types, n[0].typ) + let tb = typeToIr(c.m, n[0].typ) let d = genx(c, n[0]) build c.code, info, SetExc: @@ -494,7 +529,7 @@ proc genTry(c: var ProcCon; n: PNode; d: var Value) = let typ = it[j].typ.skipTypes(abstractPtrs-{tyTypeDesc}) let itinfo = toLineInfo(c, it[j].info) build c.code, itinfo, TestExc: - c.code.addTyped itinfo, typeToIr(c.m.types, typ) + c.code.addTyped itinfo, typeToIr(c.m, typ) if it.len == 1: let itinfo = toLineInfo(c, it.info) build c.code, itinfo, TestExc: @@ -549,26 +584,30 @@ proc genIndex(c: var ProcCon; n: PNode; arr: PType; d: var Value) = d.addIntVal c.lit.numbers, 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`. - let refType = n[1].typ.skipTypes(abstractInstOwned) +proc rawGenNew(c: var ProcCon; d: Value; refType: PType; ninfo: TLineInfo; needsInit: bool) = assert refType.kind == tyRef let baseType = refType.lastSon - let info = toLineInfo(c, n.info) + let info = toLineInfo(c, ninfo) let codegenProc = magicsys.getCompilerProc(c.m.graph, if needsInit: "nimNewObj" else: "nimNewObjUninit") - let x = genx(c, n[1]) - let refTypeIr = typeToIr(c.m.types, refType) + let refTypeIr = typeToIr(c.m, refType) buildTyped c.code, info, Asgn, refTypeIr: - copyTree c.code, x + copyTree c.code, d buildTyped c.code, info, Cast, refTypeIr: buildTyped c.code, info, Call, VoidPtrId: - let theProc = c.genx newSymNode(codegenProc, n.info) + let theProc = c.genx newSymNode(codegenProc, ninfo) copyTree c.code, theProc c.code.addImmediateVal info, int(getSize(c.config, baseType)) c.code.addImmediateVal info, int(getAlign(c.config, baseType)) +proc genNew(c: var ProcCon; n: PNode; needsInit: bool) = + # If in doubt, always follow the blueprint of the C code generator for `mm:orc`. + let refType = n[1].typ.skipTypes(abstractInstOwned) + let d = genx(c, n[1]) + rawGenNew c, d, refType, n.info, needsInit + freeTemp c, d + proc genNewSeqOfCap(c: var ProcCon; n: PNode; d: var Value) = let info = toLineInfo(c, n.info) let seqtype = skipTypes(n.typ, abstractVarRange) @@ -577,15 +616,15 @@ proc genNewSeqOfCap(c: var ProcCon; n: PNode; d: var Value) = if isEmpty(d): d = getTemp(c, n) # $1.len = 0 buildTyped c.code, info, Asgn, c.m.nativeIntId: - buildTyped c.code, info, FieldAt, c.m.nativeIntId: + buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype): copyTree c.code, d c.code.addImmediateVal info, 0 c.code.addImmediateVal info, 0 # $1.p = ($4*) #newSeqPayloadUninit($2, sizeof($3), NIM_ALIGNOF($3)) - let payloadPtr = seqPayloadPtrType(c.m.types, seqtype) + let payloadPtr = seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[0] buildTyped c.code, info, Asgn, payloadPtr: # $1.p - buildTyped c.code, info, FieldAt, payloadPtr: + buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype): copyTree c.code, d c.code.addImmediateVal info, 1 # ($4*) #newSeqPayloadUninit($2, sizeof($3), NIM_ALIGNOF($3)) @@ -602,18 +641,18 @@ proc genNewSeqOfCap(c: var ProcCon; n: PNode; d: var Value) = proc genNewSeqPayload(c: var ProcCon; info: PackedLineInfo; d, b: Value; seqtype: PType) = let baseType = seqtype.lastSon # $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3)) - let payloadPtr = seqPayloadPtrType(c.m.types, seqtype) + let payloadPtr = seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[0] # $1.len = $2 buildTyped c.code, info, Asgn, c.m.nativeIntId: - buildTyped c.code, info, FieldAt, c.m.nativeIntId: + buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype): copyTree c.code, d c.code.addImmediateVal info, 0 copyTree c.code, b buildTyped c.code, info, Asgn, payloadPtr: # $1.p - buildTyped c.code, info, FieldAt, payloadPtr: + buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype): copyTree c.code, d c.code.addImmediateVal info, 1 # ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3)) @@ -651,7 +690,7 @@ template valueIntoDest(c: var ProcCon; info: PackedLineInfo; d: var Value; typ: if isEmpty(d): body(Tree d) else: - buildTyped c.code, info, Asgn, typeToIr(c.m.types, typ): + buildTyped c.code, info, Asgn, typeToIr(c.m, typ): copyTree c.code, d body(c.code) @@ -659,7 +698,7 @@ proc genBinaryOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) = let info = toLineInfo(c, n.info) let tmp = c.genx(n[1]) let tmp2 = c.genx(n[2]) - let t = typeToIr(c.m.types, n.typ) + let t = typeToIr(c.m, n.typ) template body(target) = buildTyped target, info, opc, t: if optOverflowCheck in c.options and opc in {CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedMod}: @@ -674,7 +713,7 @@ proc genCmpOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) = let info = toLineInfo(c, n.info) let tmp = c.genx(n[1]) let tmp2 = c.genx(n[2]) - let t = typeToIr(c.m.types, n[1].typ) + let t = typeToIr(c.m, n[1].typ) template body(target) = buildTyped target, info, opc, t: copyTree target, tmp @@ -686,7 +725,7 @@ proc genCmpOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) = proc genUnaryOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) = let info = toLineInfo(c, n.info) let tmp = c.genx(n[1]) - let t = typeToIr(c.m.types, n.typ) + let t = typeToIr(c.m, n.typ) template body(target) = buildTyped target, info, opc, t: copyTree target, tmp @@ -695,7 +734,7 @@ proc genUnaryOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) = proc genIncDec(c: var ProcCon; n: PNode; opc: Opcode) = let info = toLineInfo(c, n.info) - let t = typeToIr(c.m.types, skipTypes(n[1].typ, abstractVar)) + let t = typeToIr(c.m, skipTypes(n[1].typ, abstractVar)) let d = c.genx(n[1]) let tmp = c.genx(n[2]) @@ -719,7 +758,7 @@ proc genArrayLen(c: var ProcCon; n: PNode; d: var Value) = of tyOpenArray, tyVarargs: let xa = c.genx(a) template body(target) = - buildTyped target, info, FieldAt, c.m.nativeIntId: + buildTyped target, info, FieldAt, typeToIr(c.m, typ): copyTree target, xa target.addImmediateVal info, 1 # (p, len)-pair so len is at index 1 intoDest d, info, c.m.nativeIntId, body @@ -742,7 +781,7 @@ proc genArrayLen(c: var ProcCon; n: PNode; d: var Value) = if isEmpty(d): d = getTemp(c, n) template body(target) = - buildTyped target, info, FieldAt, c.m.nativeIntId: + buildTyped target, info, FieldAt, typeToIr(c.m, typ): copyTree target, xa target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0 intoDest d, info, c.m.nativeIntId, body @@ -756,7 +795,7 @@ proc genArrayLen(c: var ProcCon; n: PNode; d: var Value) = proc genUnaryMinus(c: var ProcCon; n: PNode; d: var Value) = let info = toLineInfo(c, n.info) let tmp = c.genx(n[1]) - let t = typeToIr(c.m.types, n.typ) + let t = typeToIr(c.m, n.typ) template body(target) = buildTyped target, info, Sub, t: # Little hack: This works because we know that `0.0` is all 0 bits: @@ -767,7 +806,7 @@ proc genUnaryMinus(c: var ProcCon; n: PNode; d: var Value) = proc genHigh(c: var ProcCon; n: PNode; d: var Value) = let info = toLineInfo(c, n.info) - let t = typeToIr(c.m.types, n.typ) + let t = typeToIr(c.m, n.typ) var x = default(Value) genArrayLen(c, n, x) template body(target) = @@ -783,7 +822,7 @@ proc genBinaryCp(c: var ProcCon; n: PNode; d: var Value; compilerProc: string) = let xb = c.genx(n[2]) if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n) - let t = typeToIr(c.m.types, n.typ) + let t = typeToIr(c.m, n.typ) template body(target) = buildTyped target, info, Call, t: let codegenProc = magicsys.getCompilerProc(c.m.graph, compilerProc) @@ -802,7 +841,7 @@ proc genUnaryCp(c: var ProcCon; n: PNode; d: var Value; compilerProc: string; ar let xa = c.genx(n[argAt]) if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n) - let t = typeToIr(c.m.types, n.typ) + let t = typeToIr(c.m, n.typ) template body(target) = buildTyped target, info, Call, t: let codegenProc = magicsys.getCompilerProc(c.m.graph, compilerProc) @@ -830,7 +869,7 @@ template sizeOfLikeMsg(name): string = proc genIsNil(c: var ProcCon; n: PNode; d: var Value) = let info = toLineInfo(c, n.info) let tmp = c.genx(n[1]) - let t = typeToIr(c.m.types, n[1].typ) + let t = typeToIr(c.m, n[1].typ) template body(target) = buildTyped target, info, Eq, t: copyTree target, tmp @@ -855,8 +894,8 @@ proc genInBitset(c: var ProcCon; n: PNode; d: var Value) = let a = c.genx(n[1]) let b = c.genx(n[2]) - let t = bitsetBasetype(c.m.types, n[1].typ) - let setType = typeToIr(c.m.types, n[1].typ) + let t = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ) + let setType = typeToIr(c.m, n[1].typ) let mask = case t of UInt8Id: 7 @@ -871,10 +910,10 @@ proc genInBitset(c: var ProcCon; n: PNode; d: var Value) = buildTyped target, info, BoolNot, Bool8Id: buildTyped target, info, Eq, t: buildTyped target, info, BitAnd, t: - if c.m.types.g[setType].kind != ArrayTy: + if c.m.nirm.types[setType].kind != ArrayTy: copyTree target, a else: - buildTyped target, info, ArrayAt, t: + buildTyped target, info, ArrayAt, setType: copyTree target, a buildTyped target, info, BitShr, t: buildTyped target, info, Cast, expansion: @@ -931,19 +970,19 @@ proc genInSet(c: var ProcCon; n: PNode; d: var Value) = proc genCard(c: var ProcCon; n: PNode; d: var Value) = let info = toLineInfo(c, n.info) let a = c.genx(n[1]) - let t = typeToIr(c.m.types, n.typ) + let t = typeToIr(c.m, n.typ) - let setType = typeToIr(c.m.types, n[1].typ) + let setType = typeToIr(c.m, n[1].typ) if isEmpty(d): d = getTemp(c, n) buildTyped c.code, info, Asgn, t: copyTree c.code, d buildTyped c.code, info, Call, t: - if c.m.types.g[setType].kind == ArrayTy: + if c.m.nirm.types[setType].kind == ArrayTy: let codegenProc = magicsys.getCompilerProc(c.m.graph, "cardSet") let theProc = c.genx newSymNode(codegenProc, n.info) copyTree c.code, theProc - buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.types.g, setType): + buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, setType): copyTree c.code, a c.code.addImmediateVal info, int(getSize(c.config, n[1].typ)) elif t == UInt64Id: @@ -963,11 +1002,11 @@ proc genEqSet(c: var ProcCon; n: PNode; d: var Value) = let info = toLineInfo(c, n.info) let a = c.genx(n[1]) let b = c.genx(n[2]) - let t = typeToIr(c.m.types, n.typ) + let t = typeToIr(c.m, n.typ) - let setType = typeToIr(c.m.types, n[1].typ) + let setType = typeToIr(c.m, n[1].typ) - if c.m.types.g[setType].kind == ArrayTy: + if c.m.nirm.types[setType].kind == ArrayTy: if isEmpty(d): d = getTemp(c, n) buildTyped c.code, info, Asgn, t: @@ -977,9 +1016,9 @@ proc genEqSet(c: var ProcCon; n: PNode; d: var Value) = let codegenProc = magicsys.getCompilerProc(c.m.graph, "nimCmpMem") let theProc = c.genx newSymNode(codegenProc, n.info) copyTree c.code, theProc - buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.types.g, setType): + buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, setType): copyTree c.code, a - buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.types.g, setType): + buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, setType): copyTree c.code, b c.code.addImmediateVal info, int(getSize(c.config, n[1].typ)) c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0 @@ -995,7 +1034,7 @@ proc genEqSet(c: var ProcCon; n: PNode; d: var Value) = freeTemp c, a proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: int): (SymId, LabelId, LabelId) = - let tmp = allocTemp(c.sm, c.m.nativeIntId, c.idgen.symId) + let tmp = allocTemp(c, c.m.nativeIntId) c.code.addSummon info, tmp, c.m.nativeIntId buildTyped c.code, info, Asgn, c.m.nativeIntId: c.code.addSymUse info, tmp @@ -1013,7 +1052,7 @@ proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: int): (Sy c.code.gotoLabel info, Goto, result[2] proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: Value): (SymId, LabelId, LabelId) = - let tmp = allocTemp(c.sm, c.m.nativeIntId, c.idgen.symId) + let tmp = allocTemp(c, c.m.nativeIntId) c.code.addSummon info, tmp, c.m.nativeIntId buildTyped c.code, info, Asgn, c.m.nativeIntId: c.code.addSymUse info, tmp @@ -1044,12 +1083,12 @@ proc genLeSet(c: var ProcCon; n: PNode; d: var Value) = let info = toLineInfo(c, n.info) let a = c.genx(n[1]) let b = c.genx(n[2]) - let t = typeToIr(c.m.types, n.typ) + let t = typeToIr(c.m, n.typ) - let setType = typeToIr(c.m.types, n[1].typ) + let setType = typeToIr(c.m, n[1].typ) - if c.m.types.g[setType].kind == ArrayTy: - let elemType = bitsetBasetype(c.m.types, n[1].typ) + if c.m.nirm.types[setType].kind == ArrayTy: + let elemType = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ) if isEmpty(d): d = getTemp(c, n) # "for ($1 = 0; $1 < $2; $1++):" # " $3 = (($4[$1] & ~ $5[$1]) == 0)" @@ -1059,11 +1098,11 @@ proc genLeSet(c: var ProcCon; n: PNode; d: var Value) = copyTree c.code, d buildTyped c.code, info, Eq, elemType: buildTyped c.code, info, BitAnd, elemType: - buildTyped c.code, info, ArrayAt, elemType: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, a c.code.addSymUse info, idx buildTyped c.code, info, BitNot, elemType: - buildTyped c.code, info, ArrayAt, elemType: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, b c.code.addSymUse info, idx c.code.addIntVal c.lit.numbers, info, elemType, 0 @@ -1099,32 +1138,32 @@ proc genBinarySet(c: var ProcCon; n: PNode; d: var Value; m: TMagic) = let info = toLineInfo(c, n.info) let a = c.genx(n[1]) let b = c.genx(n[2]) - let t = typeToIr(c.m.types, n.typ) + let t = typeToIr(c.m, n.typ) - let setType = typeToIr(c.m.types, n[1].typ) + let setType = typeToIr(c.m, n[1].typ) - if c.m.types.g[setType].kind == ArrayTy: - let elemType = bitsetBasetype(c.m.types, n[1].typ) + if c.m.nirm.types[setType].kind == ArrayTy: + let elemType = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ) if isEmpty(d): d = getTemp(c, n) # "for ($1 = 0; $1 < $2; $1++):" # " $3 = (($4[$1] & ~ $5[$1]) == 0)" # " if (!$3) break;" let (idx, backLabel, endLabel) = beginCountLoop(c, info, 0, int(getSize(c.config, n[1].typ))) buildTyped c.code, info, Asgn, elemType: - buildTyped c.code, info, ArrayAt, elemType: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, d c.code.addSymUse info, idx buildTyped c.code, info, (if m == mPlusSet: BitOr else: BitAnd), elemType: - buildTyped c.code, info, ArrayAt, elemType: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, a c.code.addSymUse info, idx if m == mMinusSet: buildTyped c.code, info, BitNot, elemType: - buildTyped c.code, info, ArrayAt, elemType: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, b c.code.addSymUse info, idx else: - buildTyped c.code, info, ArrayAt, elemType: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, b c.code.addSymUse info, idx @@ -1150,9 +1189,9 @@ proc genInclExcl(c: var ProcCon; n: PNode; m: TMagic) = let a = c.genx(n[1]) let b = c.genx(n[2]) - let setType = typeToIr(c.m.types, n[1].typ) + let setType = typeToIr(c.m, n[1].typ) - let t = bitsetBasetype(c.m.types, n[1].typ) + let t = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ) let mask = case t of UInt8Id: 7 @@ -1161,17 +1200,17 @@ proc genInclExcl(c: var ProcCon; n: PNode; m: TMagic) = else: 63 buildTyped c.code, info, Asgn, setType: - if c.m.types.g[setType].kind == ArrayTy: + if c.m.nirm.types[setType].kind == ArrayTy: if m == mIncl: # $1[(NU)($2)>>3] |=(1U<<($2&7U)) - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, a buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: copyTree c.code, b addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitOr, t: - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, a buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: @@ -1184,14 +1223,14 @@ proc genInclExcl(c: var ProcCon; n: PNode; m: TMagic) = c.code.addIntVal c.lit.numbers, info, t, 7 else: # $1[(NU)($2)>>3] &= ~(1U<<($2&7U)) - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, a buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: copyTree c.code, b addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitAnd, t: - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, a buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: @@ -1234,9 +1273,9 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = # nimZeroMem(tmp, sizeof(tmp)); inclRange(tmp, a, b); incl(tmp, c); # incl(tmp, d); incl(tmp, e); inclRange(tmp, f, g); let info = toLineInfo(c, n.info) - let setType = typeToIr(c.m.types, n.typ) + let setType = typeToIr(c.m, n.typ) let size = int(getSize(c.config, n.typ)) - let t = bitsetBasetype(c.m.types, n.typ) + let t = bitsetBasetype(c.m.types, c.m.nirm.types, n.typ) let mask = case t of UInt8Id: 7 @@ -1245,7 +1284,7 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = else: 63 if isEmpty(d): d = getTemp(c, n) - if c.m.types.g[setType].kind != ArrayTy: + if c.m.nirm.types[setType].kind != ArrayTy: buildTyped c.code, info, Asgn, setType: copyTree c.code, d c.code.addIntVal c.lit.numbers, info, t, 0 @@ -1300,14 +1339,14 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = let (idx, backLabel, endLabel) = beginCountLoop(c, info, a, b) buildTyped c.code, info, Asgn, t: - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, d buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: c.code.addSymUse info, idx addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitOr, t: - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, d buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: @@ -1327,14 +1366,14 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = let a = genx(c, it) # $1[(NU)($2)>>3] |=(1U<<($2&7U)) buildTyped c.code, info, Asgn, t: - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, d buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: copyTree c.code, a addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitOr, t: - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, d buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: @@ -1350,16 +1389,16 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = proc genSetConstr(c: var ProcCon; n: PNode; d: var Value) = if isDeepConstExpr(n): let info = toLineInfo(c, n.info) - let setType = typeToIr(c.m.types, n.typ) + let setType = typeToIr(c.m, n.typ) let size = int(getSize(c.config, n.typ)) let cs = toBitSet(c.config, n) - if c.m.types.g[setType].kind != ArrayTy: + if c.m.nirm.types[setType].kind != ArrayTy: template body(target) = target.addIntVal c.lit.numbers, info, setType, cast[BiggestInt](bitSetToWord(cs, size)) intoDest d, info, setType, body else: - let t = bitsetBasetype(c.m.types, n.typ) + let t = bitsetBasetype(c.m.types, c.m.nirm.types, n.typ) template body(target) = buildTyped target, info, ArrayConstr, setType: for i in 0..high(cs): @@ -1387,32 +1426,36 @@ proc genStrConcat(c: var ProcCon; n: PNode; d: var Value) = # asgn(s, tmp0); # } var args: seq[Value] = @[] + var argsRuntimeLen: seq[Value] = @[] + var precomputedLen = 0 for i in 1 ..< n.len: let it = n[i] + args.add genx(c, it) if skipTypes(it.typ, abstractVarRange).kind == tyChar: inc precomputedLen elif it.kind in {nkStrLit..nkTripleStrLit}: inc precomputedLen, it.strVal.len - args.add genx(c, it) + else: + argsRuntimeLen.add args[^1] # generate length computation: - var tmpLen = allocTemp(c.sm, c.m.nativeIntId, c.idgen.symId) + var tmpLen = allocTemp(c, c.m.nativeIntId) buildTyped c.code, info, Asgn, c.m.nativeIntId: c.code.addSymUse info, tmpLen c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, precomputedLen - for a in mitems(args): + for a in mitems(argsRuntimeLen): buildTyped c.code, info, Asgn, c.m.nativeIntId: c.code.addSymUse info, tmpLen buildTyped c.code, info, CheckedAdd, c.m.nativeIntId: c.code.addSymUse info, tmpLen - buildTyped c.code, info, FieldAt, c.m.nativeIntId: + buildTyped c.code, info, FieldAt, typeToIr(c.m, n.typ): copyTree c.code, a c.code.addImmediateVal info, 0 # (len, p)-pair so len is at index 0 var tmpStr = getTemp(c, n) # ^ because of aliasing, we always go through a temporary - let t = typeToIr(c.m.types, n.typ) + let t = typeToIr(c.m, n.typ) buildTyped c.code, info, Asgn, t: copyTree c.code, tmpStr buildTyped c.code, info, Call, t: @@ -1432,7 +1475,7 @@ proc genStrConcat(c: var ProcCon; n: PNode; d: var Value) = #assert codegenProc != nil, $n & " " & (c.m.graph.config $ n.info) let theProc = c.genx newSymNode(codegenProc, n.info) copyTree c.code, theProc - buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.types.g, t): + buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, t): copyTree c.code, tmpStr copyTree c.code, args[i-1] freeTemp c, args[i-1] @@ -1469,13 +1512,14 @@ proc genMove(c: var ProcCon; n: PNode; d: var Value) = # if ($1.p == $2.p) goto lab1 let lab1 = newLabel(c.labelGen) - let payloadType = seqPayloadPtrType(c.m.types, n1.typ) + let n1t = typeToIr(c.m, n1.typ) + let payloadType = seqPayloadPtrType(c.m.types, c.m.nirm.types, n1.typ)[0] buildTyped c.code, info, Select, Bool8Id: buildTyped c.code, info, Eq, payloadType: - buildTyped c.code, info, FieldAt, payloadType: + buildTyped c.code, info, FieldAt, n1t: copyTree c.code, a c.code.addImmediateVal info, 1 # (len, p)-pair - buildTyped c.code, info, FieldAt, payloadType: + buildTyped c.code, info, FieldAt, n1t: copyTree c.code, src c.code.addImmediateVal info, 1 # (len, p)-pair @@ -1487,13 +1531,13 @@ proc genMove(c: var ProcCon; n: PNode; d: var Value) = gen(c, n[3]) c.patch n, lab1 - buildTyped c.code, info, Asgn, typeToIr(c.m.types, n1.typ): + buildTyped c.code, info, Asgn, typeToIr(c.m, 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): + buildTyped c.code, info, Asgn, typeToIr(c.m, n1.typ): copyTree c.code, d copyTree c.code, a var op = getAttachedOp(c.m.graph, n.typ, attachedWasMoved) @@ -1502,9 +1546,9 @@ proc genMove(c: var ProcCon; n: PNode; d: var Value) = gen c, m, a else: var opB = c.genx(newSymNode(op)) - buildTyped c.code, info, Call, typeToIr(c.m.types, n.typ): + buildTyped c.code, info, Call, typeToIr(c.m, n.typ): copyTree c.code, opB - buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.types.g, typeToIr(c.m.types, n1.typ)): + buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, typeToIr(c.m, n1.typ)): copyTree c.code, a template fieldAt(x: Value; i: int; t: TypeId): Tree = @@ -1542,13 +1586,13 @@ proc genDestroySeq(c: var ProcCon; n: PNode; t: PType) = let x = c.genx(n[1]) let baseType = t.lastSon - let seqType = seqPayloadPtrType(c.m.types, t) + let seqType = typeToIr(c.m, t) let p = fieldAt(x, 0, seqType) # if $1.p != nil and ($1.p.cap and NIM_STRLIT_FLAG) == 0: # alignedDealloc($1.p, NIM_ALIGNOF($2)) buildIfNot p.eqNil(seqType): - buildIf fieldAt(Value(p), 0, c.m.nativeIntId).bitOp(BitAnd, 0).eqZero(): + buildIf fieldAt(Value(p), 0, seqPayloadPtrType(c.m.types, c.m.nirm.types, t)[0]).bitOp(BitAnd, 0).eqZero(): let codegenProc = getCompilerProc(c.m.graph, "alignedDealloc") buildTyped c.code, info, Call, VoidId: let theProc = c.genx newSymNode(codegenProc, n.info) @@ -1572,7 +1616,7 @@ type IndexFor = enum ForSeq, ForStr, ForOpenArray, ForArray -proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor; arr: PType = nil): Value = +proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor; arr: PType): Value = if optBoundsCheck in c.options: let info = toLineInfo(c, n.info) result = default(Value) @@ -1581,11 +1625,11 @@ proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor; arr: PTyp copyTree result.Tree, idx case kind of ForSeq, ForStr: - buildTyped result, info, FieldAt, c.m.nativeIntId: + buildTyped result, info, FieldAt, typeToIr(c.m, arr): copyTree result.Tree, a result.addImmediateVal info, 0 # (len, p)-pair of ForOpenArray: - buildTyped result, info, FieldAt, c.m.nativeIntId: + buildTyped result, info, FieldAt, typeToIr(c.m, arr): copyTree result.Tree, a result.addImmediateVal info, 1 # (p, len)-pair of ForArray: @@ -1598,22 +1642,21 @@ proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor; arr: PTyp proc addSliceFields(c: var ProcCon; target: var Tree; info: PackedLineInfo; x: Value; n: PNode; arrType: PType) = - let elemType = arrayPtrTypeOf(c.m.types.g, typeToIr(c.m.types, arrType.lastSon)) + let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.lastSon)) case arrType.kind of tyString, tySequence: - let t = typeToIr(c.m.types, arrType.lastSon) let checkKind = if arrType.kind == tyString: ForStr else: ForSeq - let pay = if checkKind == ForStr: strPayloadPtrType(c.m.types) - else: seqPayloadPtrType(c.m.types, arrType) + let pay = if checkKind == ForStr: c.m.strPayloadId + else: seqPayloadPtrType(c.m.types, c.m.nirm.types, arrType) - let y = genIndexCheck(c, n[2], x, checkKind) - let z = genIndexCheck(c, n[3], x, checkKind) + let y = genIndexCheck(c, n[2], x, checkKind, arrType) + let z = genIndexCheck(c, n[3], x, checkKind, arrType) - buildTyped target, info, ObjConstr, typeToIr(c.m.types, n.typ): + buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ): target.addImmediateVal info, 0 buildTyped target, info, AddrOf, elemType: - buildTyped target, info, ArrayAt, t: - buildTyped target, info, FieldAt, pay: + buildTyped target, info, ArrayAt, pay[1]: + buildTyped target, info, FieldAt, typeToIr(c.m, arrType): copyTree target, x target.addImmediateVal info, 1 # (len, p)-pair copyTree target, y @@ -1628,19 +1671,16 @@ proc addSliceFields(c: var ProcCon; target: var Tree; info: PackedLineInfo; freeTemp c, z freeTemp c, y - of tyArray, tyOpenArray: - let t = typeToIr(c.m.types, arrType.lastSon) + of tyArray: # XXX This evaluates the index check for `y` twice. # This check is also still insufficient for non-zero based arrays. - let checkKind = if arrType.kind == tyArray: ForArray else: ForOpenArray - - let y = genIndexCheck(c, n[2], x, checkKind, arrType) - let z = genIndexCheck(c, n[3], x, checkKind, arrType) + let y = genIndexCheck(c, n[2], x, ForArray, arrType) + let z = genIndexCheck(c, n[3], x, ForArray, arrType) - buildTyped target, info, ObjConstr, typeToIr(c.m.types, n.typ): + buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ): target.addImmediateVal info, 0 buildTyped target, info, AddrOf, elemType: - buildTyped target, info, ArrayAt, t: + buildTyped target, info, ArrayAt, typeToIr(c.m, arrType): copyTree target, x copyTree target, y @@ -1653,6 +1693,30 @@ proc addSliceFields(c: var ProcCon; target: var Tree; info: PackedLineInfo; freeTemp c, z freeTemp c, y + of tyOpenArray: + # XXX This evaluates the index check for `y` twice. + let y = genIndexCheck(c, n[2], x, ForOpenArray, arrType) + let z = genIndexCheck(c, n[3], x, ForOpenArray, arrType) + let pay = openArrayPayloadType(c.m.types, c.m.nirm.types, arrType) + + buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ): + target.addImmediateVal info, 0 + buildTyped target, info, AddrOf, elemType: + buildTyped target, info, ArrayAt, pay: + buildTyped target, info, FieldAt, typeToIr(c.m, arrType): + copyTree target, x + target.addImmediateVal info, 0 # (p, len)-pair + copyTree target, y + + target.addImmediateVal info, 1 + buildTyped target, info, Add, c.m.nativeIntId: + buildTyped target, info, Sub, c.m.nativeIntId: + copyTree target, z + copyTree target, y + target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1 + + freeTemp c, z + freeTemp c, y else: raiseAssert "addSliceFields: " & typeToString(arrType) @@ -1875,7 +1939,7 @@ proc genAddr(c: var ProcCon; n: PNode; d: var Value, flags: GenFlags) = let info = toLineInfo(c, n.info) let tmp = c.genx(n[0], flags) template body(target) = - buildTyped target, info, AddrOf, typeToIr(c.m.types, n.typ): + buildTyped target, info, AddrOf, typeToIr(c.m, n.typ): copyTree target, tmp valueIntoDest c, info, d, n.typ, body @@ -1885,7 +1949,7 @@ proc genDeref(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = let info = toLineInfo(c, n.info) let tmp = c.genx(n[0], flags) template body(target) = - buildTyped target, info, Load, typeToIr(c.m.types, n.typ): + buildTyped target, info, Load, typeToIr(c.m, n.typ): copyTree target, tmp valueIntoDest c, info, d, n.typ, body @@ -1893,47 +1957,47 @@ proc genDeref(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = 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)) + let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.lastSon)) case arrType.kind of tyString: - let t = typeToIr(c.m.types, typ.lastSon) + let t = typeToIr(c.m, typ) target.addImmediateVal info, 0 buildTyped target, info, AddrOf, elemType: - buildTyped target, info, ArrayAt, t: - buildTyped target, info, FieldAt, strPayloadPtrType(c.m.types): + buildTyped target, info, ArrayAt, c.m.strPayloadId[1]: + buildTyped target, info, FieldAt, typeToIr(c.m, arrType): copyTree target, tmp target.addImmediateVal info, 1 # (len, p)-pair target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0 # len: target.addImmediateVal info, 1 - buildTyped target, info, FieldAt, c.m.nativeIntId: + buildTyped target, info, FieldAt, typeToIr(c.m, arrType): 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) + let t = typeToIr(c.m, typ) target.addImmediateVal info, 0 buildTyped target, info, AddrOf, elemType: - buildTyped target, info, ArrayAt, t: - buildTyped target, info, FieldAt, seqPayloadPtrType(c.m.types, typ): + buildTyped target, info, ArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, typ)[1]: + buildTyped target, info, FieldAt, typeToIr(c.m, arrType): copyTree target, tmp target.addImmediateVal info, 1 # (len, p)-pair target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0 # len: target.addImmediateVal info, 1 - buildTyped target, info, FieldAt, c.m.nativeIntId: + buildTyped target, info, FieldAt, typeToIr(c.m, arrType): 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) + let t = typeToIr(c.m, arrType) target.addImmediateVal info, 0 buildTyped target, info, AddrOf, elemType: buildTyped target, info, ArrayAt, t: copyTree target, tmp target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0 target.addImmediateVal info, 1 - target.addIntVal(c.lit.numbers, info, c.m.nativeIntId, toInt lengthOrd(c.config, typ)) + target.addIntVal(c.lit.numbers, info, c.m.nativeIntId, toInt lengthOrd(c.config, arrType)) else: raiseAssert "addAddrOfFirstElem: " & typeToString(typ) @@ -1942,7 +2006,7 @@ proc genToOpenArrayConv(c: var ProcCon; arg: PNode; d: var Value; flags: GenFlag let tmp = c.genx(arg, flags) let arrType = destType.skipTypes(abstractVar) template body(target) = - buildTyped target, info, ObjConstr, typeToIr(c.m.types, arrType): + buildTyped target, info, ObjConstr, typeToIr(c.m, arrType): c.addAddrOfFirstElem target, info, tmp, arg.typ valueIntoDest c, info, d, arrType, body @@ -1966,7 +2030,7 @@ proc genConv(c: var ProcCon; n, arg: PNode; d: var Value; flags: GenFlags; opc: let info = toLineInfo(c, n.info) let tmp = c.genx(arg, flags) template body(target) = - buildTyped target, info, opc, typeToIr(c.m.types, n.typ): + buildTyped target, info, opc, typeToIr(c.m, n.typ): if opc == CheckedObjConv: target.addLabel info, CheckedGoto, c.exitLabel copyTree target, tmp @@ -1974,11 +2038,11 @@ proc genConv(c: var ProcCon; n, arg: PNode; d: var Value; flags: GenFlags; opc: valueIntoDest c, info, d, n.typ, body freeTemp c, tmp -proc genObjOrTupleConstr(c: var ProcCon; n: PNode, d: var Value) = +proc genObjOrTupleConstr(c: var ProcCon; n: PNode; d: var Value; t: PType) = # XXX x = (x.old, 22) produces wrong code ... stupid self assignments let info = toLineInfo(c, n.info) template body(target) = - buildTyped target, info, ObjConstr, typeToIr(c.m.types, n.typ): + buildTyped target, info, ObjConstr, typeToIr(c.m, t): for i in ord(n.kind == nkObjConstr)..<n.len: let it = n[i] if it.kind == nkExprColonExpr: @@ -1992,7 +2056,23 @@ proc genObjOrTupleConstr(c: var ProcCon; n: PNode, d: var Value) = copyTree target, tmp c.freeTemp(tmp) - valueIntoDest c, info, d, n.typ, body + if isException(t): + target.addImmediateVal info, 1 # "name" field is at position after the "parent". See system.nim + target.addStrVal c.lit.strings, info, t.skipTypes(abstractInst).sym.name.s + + valueIntoDest c, info, d, t, body + +proc genRefObjConstr(c: var ProcCon; n: PNode; d: var Value) = + if isEmpty(d): d = getTemp(c, n) + let info = toLineInfo(c, n.info) + let refType = n.typ.skipTypes(abstractInstOwned) + let objType = refType.lastSon + + rawGenNew(c, d, refType, n.info, needsInit = nfAllFieldsSet notin n.flags) + var deref = default(Value) + deref.buildTyped info, Load, typeToIr(c.m, objType): + deref.Tree.copyTree d + genObjOrTupleConstr c, n, deref, objType proc genSeqConstr(c: var ProcCon; n: PNode; d: var Value) = if isEmpty(d): d = getTemp(c, n) @@ -2008,8 +2088,8 @@ proc genSeqConstr(c: var ProcCon; n: PNode; d: var Value) = for i in 0..<n.len: var dd = default(Value) - buildTyped dd, info, ArrayAt, typeToIr(c.m.types, seqtype): - buildTyped dd, info, FieldAt, seqPayloadPtrType(c.m.types, seqtype): + buildTyped dd, info, ArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[1]: + buildTyped dd, info, FieldAt, typeToIr(c.m, seqtype): copyTree Tree(dd), d dd.addIntVal c.lit.numbers, info, c.m.nativeIntId, i gen(c, n[i], dd) @@ -2024,7 +2104,7 @@ proc genArrayConstr(c: var ProcCon; n: PNode, d: var Value) = let info = toLineInfo(c, n.info) template body(target) = - buildTyped target, info, ArrayConstr, typeToIr(c.m.types, n.typ): + buildTyped target, info, ArrayConstr, typeToIr(c.m, n.typ): for i in 0..<n.len: let tmp = c.genx(n[i]) copyTree target, tmp @@ -2056,9 +2136,11 @@ proc genVarSection(c: var ProcCon; n: PNode) = opc = SummonGlobal else: opc = Summon - let t = typeToIr(c.m.types, s.typ) + let t = typeToIr(c.m, s.typ) #assert t.int >= 0, typeToString(s.typ) & (c.config $ n.info) - c.code.addSummon toLineInfo(c, a.info), SymId(s.itemId.item), t, opc + let symId = toSymId(c, s) + c.code.addSummon toLineInfo(c, a.info), symId, t, opc + c.m.symnames[symId] = c.lit.strings.getOrIncl(s.name.s) if a[2].kind != nkEmpty: genAsgn2(c, vn, a[2]) else: @@ -2081,10 +2163,13 @@ proc irModule(c: var ProcCon; owner: PSym): string = #if owner == c.m.module: "" else: customPath(toFullPath(c.config, owner.info)) +proc fromForeignModule(c: ProcCon; s: PSym): bool {.inline.} = + result = ast.originatingModule(s) != c.m.module and not c.m.noModularity + proc genRdVar(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = let info = toLineInfo(c, n.info) let s = n.sym - if ast.originatingModule(s) != c.m.module: + if fromForeignModule(c, s): template body(target) = build target, info, ModuleSymUse: target.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(s)) @@ -2093,7 +2178,7 @@ proc genRdVar(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = valueIntoDest c, info, d, s.typ, body else: template body(target) = - target.addSymUse info, SymId(s.itemId.item) + target.addSymUse info, toSymId(c, s) valueIntoDest c, info, d, s.typ, body proc genSym(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = @@ -2102,16 +2187,17 @@ proc genSym(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = of skVar, skForVar, skTemp, skLet, skResult, skParam, skConst: genRdVar(c, n, d, flags) of skProc, skFunc, skConverter, skMethod, skIterator: - if ast.originatingModule(s) == c.m.module: + if not fromForeignModule(c, s): # anon and generic procs have no AST so we need to remember not to forget # to emit these: - if not c.m.processedProcs.containsOrIncl(s.itemId): - c.m.pendingProcs.add s + if not c.m.processedProcs.contains(s.itemId): + if not c.m.pendingProcsAsSet.containsOrIncl(s.itemId): + c.m.pendingProcs.add s genRdVar(c, n, d, flags) of skEnumField: let info = toLineInfo(c, n.info) template body(target) = - target.addIntVal c.lit.numbers, info, typeToIr(c.m.types, n.typ), s.position + target.addIntVal c.lit.numbers, info, typeToIr(c.m, n.typ), s.position valueIntoDest c, info, d, n.typ, body else: localError(c.config, n.info, "cannot generate code for: " & s.name.s) @@ -2119,7 +2205,7 @@ proc genSym(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = proc genNumericLit(c: var ProcCon; n: PNode; d: var Value; bits: int64) = let info = toLineInfo(c, n.info) template body(target) = - target.addIntVal c.lit.numbers, info, typeToIr(c.m.types, n.typ), bits + target.addIntVal c.lit.numbers, info, typeToIr(c.m, n.typ), bits valueIntoDest c, info, d, n.typ, body proc genStringLit(c: var ProcCon; n: PNode; d: var Value) = @@ -2131,7 +2217,7 @@ proc genStringLit(c: var ProcCon; n: PNode; d: var Value) = proc genNilLit(c: var ProcCon; n: PNode; d: var Value) = let info = toLineInfo(c, n.info) template body(target) = - target.addNilVal info, typeToIr(c.m.types, n.typ) + target.addNilVal info, typeToIr(c.m, n.typ) valueIntoDest c, info, d, n.typ, body proc genRangeCheck(c: var ProcCon; n: PNode; d: var Value) = @@ -2141,7 +2227,7 @@ proc genRangeCheck(c: var ProcCon; n: PNode; d: var Value) = 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): + buildTyped target, info, CheckedRange, typeToIr(c.m, n.typ): copyTree target, tmp copyTree target, a copyTree target, b @@ -2154,16 +2240,17 @@ proc genRangeCheck(c: var ProcCon; n: PNode; d: var Value) = gen c, n[0], d proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = - let arrayKind = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind + let arrayType = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}) + let arrayKind = arrayType.kind let info = toLineInfo(c, n.info) case arrayKind of tyString: let a = genx(c, n[0], flags) - let b = genIndexCheck(c, n[1], a, ForStr) - let t = typeToIr(c.m.types, n.typ) + let b = genIndexCheck(c, n[1], a, ForStr, arrayType) + let t = typeToIr(c.m, n.typ) template body(target) = - buildTyped target, info, ArrayAt, t: - buildTyped target, info, FieldAt, strPayloadPtrType(c.m.types): + buildTyped target, info, ArrayAt, c.m.strPayloadId[1]: + buildTyped target, info, FieldAt, typeToIr(c.m, arrayType): copyTree target, a target.addImmediateVal info, 1 # (len, p)-pair copyTree target, b @@ -2175,7 +2262,7 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = let a = genx(c, n[0], flags) let b = genx(c, n[1]) template body(target) = - buildTyped target, info, ArrayAt, typeToIr(c.m.types, n.typ): + buildTyped target, info, ArrayAt, typeToIr(c.m, arrayType): copyTree target, a copyTree target, b valueIntoDest c, info, d, n.typ, body @@ -2186,7 +2273,7 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = let a = genx(c, n[0], flags) let b = int n[1].intVal template body(target) = - buildTyped target, info, FieldAt, typeToIr(c.m.types, n.typ): + buildTyped target, info, FieldAt, typeToIr(c.m, arrayType): copyTree target, a target.addImmediateVal info, b valueIntoDest c, info, d, n.typ, body @@ -2194,11 +2281,11 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = freeTemp c, a of tyOpenArray, tyVarargs: let a = genx(c, n[0], flags) - let b = genIndexCheck(c, n[1], a, ForOpenArray) - let t = typeToIr(c.m.types, n.typ) + let b = genIndexCheck(c, n[1], a, ForOpenArray, arrayType) + let t = typeToIr(c.m, n.typ) template body(target) = - buildTyped target, info, ArrayAt, t: - buildTyped target, info, FieldAt, openArrayPayloadType(c.m.types, n[0].typ): + buildTyped target, info, ArrayAt, openArrayPayloadType(c.m.types, c.m.nirm.types, n[0].typ): + buildTyped target, info, FieldAt, typeToIr(c.m, arrayType): copyTree target, a target.addImmediateVal info, 0 # (p, len)-pair copyTree target, b @@ -2212,7 +2299,7 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = genIndex(c, n[1], n[0].typ, b) template body(target) = - buildTyped target, info, ArrayAt, typeToIr(c.m.types, n.typ): + buildTyped target, info, ArrayAt, typeToIr(c.m, arrayType): copyTree target, a copyTree target, b valueIntoDest c, info, d, n.typ, body @@ -2220,11 +2307,11 @@ 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 = genIndexCheck(c, n[1], a, ForSeq) - let t = typeToIr(c.m.types, n.typ) + let b = genIndexCheck(c, n[1], a, ForSeq, arrayType) + let t = typeToIr(c.m, n.typ) template body(target) = - buildTyped target, info, ArrayAt, t: - buildTyped target, info, FieldAt, seqPayloadPtrType(c.m.types, n[0].typ): + buildTyped target, info, ArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, n[0].typ)[1]: + buildTyped target, info, FieldAt, t: copyTree target, a target.addImmediateVal info, 1 # (len, p)-pair copyTree target, b @@ -2239,20 +2326,28 @@ proc genObjAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = let a = genx(c, n[0], flags) template body(target) = - buildTyped target, info, FieldAt, typeToIr(c.m.types, n.typ): + buildTyped target, info, FieldAt, typeToIr(c.m, n[0].typ): copyTree target, a genField c, n[1], Value(target) valueIntoDest c, info, d, n.typ, body freeTemp c, a -proc genParams(c: var ProcCon; params: PNode) = +proc genParams(c: var ProcCon; params: PNode; prc: PSym) = + if params.len > 0 and resultPos < prc.ast.len: + let resNode = prc.ast[resultPos] + let res = resNode.sym # get result symbol + c.code.addSummon toLineInfo(c, res.info), toSymId(c, res), + typeToIr(c.m, res.typ), SummonResult + for i in 1..<params.len: let s = params[i].sym if not isCompileTimeOnly(s.typ): - let t = typeToIr(c.m.types, s.typ) + let t = typeToIr(c.m, s.typ) assert t.int != -1, typeToString(s.typ) - c.code.addSummon toLineInfo(c, params[i].info), SymId(s.itemId.item), t, SummonParam + let symId = toSymId(c, s) + c.code.addSummon toLineInfo(c, params[i].info), symId, t, SummonParam + c.m.symnames[symId] = c.lit.strings.getOrIncl(s.name.s) proc addCallConv(c: var ProcCon; info: PackedLineInfo; callConv: TCallingConvention) = template ann(s: untyped) = c.code.addPragmaId info, s @@ -2270,6 +2365,12 @@ proc addCallConv(c: var ProcCon; info: PackedLineInfo; callConv: TCallingConvent proc genProc(cOuter: var ProcCon; prc: PSym) = if cOuter.m.processedProcs.containsOrIncl(prc.itemId): return + #assert cOuter.m.inProc == 0, " in nested proc! " & prc.name.s + if cOuter.m.inProc > 0: + if not cOuter.m.pendingProcsAsSet.containsOrIncl(prc.itemId): + cOuter.m.pendingProcs.add prc + return + inc cOuter.m.inProc var c = initProcCon(cOuter.m, prc, cOuter.m.graph.config) @@ -2277,8 +2378,14 @@ proc genProc(cOuter: var ProcCon; prc: PSym) = let info = toLineInfo(c, body.info) build c.code, info, ProcDecl: - addSymDef c.code, info, SymId(prc.itemId.item) + let symId = toSymId(c, prc) + addSymDef c.code, info, symId + c.m.symnames[symId] = c.lit.strings.getOrIncl(prc.name.s) addCallConv c, info, prc.typ.callConv + if sfCompilerProc in prc.flags: + build c.code, info, PragmaPair: + c.code.addPragmaId info, CoreName + c.code.addStrVal c.lit.strings, info, prc.name.s if {sfImportc, sfExportc} * prc.flags != {}: build c.code, info, PragmaPair: c.code.addPragmaId info, ExternName @@ -2302,18 +2409,35 @@ proc genProc(cOuter: var ProcCon; prc: PSym) = else: c.code.addPragmaId info, ObjExport - genParams(c, prc.typ.n) + genParams(c, prc.typ.n, prc) gen(c, body) patch c, body, c.exitLabel - copyTree cOuter.code, c.code + #copyTree cOuter.code, c.code + dec cOuter.m.inProc proc genProc(cOuter: var ProcCon; n: PNode) = if n.len == 0 or n[namePos].kind != nkSym: return let prc = n[namePos].sym - if isGenericRoutineStrict(prc) or isCompileTimeProc(prc): return + if isGenericRoutineStrict(prc) or isCompileTimeProc(prc) or sfForward in prc.flags: return genProc cOuter, prc +proc genClosureCall(c: var ProcCon; n: PNode; d: var Value) = + let typ = skipTypes(n[0].typ, abstractInstOwned) + if tfIterator in typ.flags: + const PatIter = "$1.ClP_0($3, $1.ClE_0)" # we know the env exists + + else: + const PatProc = "$1.ClE_0? $1.ClP_0($3, $1.ClE_0):(($4)($1.ClP_0))($2)" + + +proc genComplexCall(c: var ProcCon; n: PNode; d: var Value) = + if n[0].typ != nil and n[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure: + # XXX genClosureCall p, n, d + genCall c, n, d + else: + genCall c, n, d + proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = when defined(nimCompilerStacktraceHints): setFrameMsg c.config$n.info & " " & $n.kind & " " & $flags @@ -2328,11 +2452,9 @@ proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = localError(c.config, n.info, "cannot call method " & s.name.s & " at compile time") else: - genCall(c, n, d) - clearDest(c, n, d) + genComplexCall(c, n, d) else: - genCall(c, n, d) - clearDest(c, n, d) + genComplexCall(c, n, d) of nkCharLit..nkInt64Lit, nkUIntLit..nkUInt64Lit: genNumericLit(c, n, d, n.intVal) of nkFloatLit..nkFloat128Lit: @@ -2401,8 +2523,13 @@ proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = of nkCStringToString: convCStrToStr(c, n, d) of nkBracket: genArrayConstr(c, n, d) of nkCurly: genSetConstr(c, n, d) - of nkObjConstr, nkPar, nkClosure, nkTupleConstr: - genObjOrTupleConstr(c, n, d) + of nkObjConstr: + if n.typ.skipTypes(abstractInstOwned).kind == tyRef: + genRefObjConstr(c, n, d) + else: + genObjOrTupleConstr(c, n, d, n.typ) + of nkPar, nkClosure, nkTupleConstr: + genObjOrTupleConstr(c, n, d, n.typ) of nkCast: genConv(c, n, n[1], d, flags, Cast) of nkComesFrom: @@ -2419,8 +2546,8 @@ proc genPendingProcs(c: var ProcCon) = for v in procs: genProc(c, v) -proc genStmt*(c: var ProcCon; n: PNode): int = - result = c.code.len +proc genStmt*(c: var ProcCon; n: PNode): NodePos = + result = NodePos c.code.len var d = default(Value) c.gen(n, d) unused c, n, d diff --git a/compiler/nir/nir.nim b/compiler/nir/nir.nim index 0669bc222..c4fb5322d 100644 --- a/compiler/nir/nir.nim +++ b/compiler/nir/nir.nim @@ -12,8 +12,9 @@ from os import addFileExt, `/`, createDir +import std / assertions import ".." / [ast, modulegraphs, renderer, transf, options, msgs, lineinfos] -import nirtypes, nirinsts, ast2ir, nirlineinfos +import nirtypes, nirinsts, ast2ir, nirlineinfos, nirfiles, nirvm import ".." / ic / [rodfiles, bitabs] @@ -22,13 +23,18 @@ type m: ModuleCon c: ProcCon oldErrorCount: int + bytecode: Bytecode proc newCtx*(module: PSym; g: ModuleGraph; idgen: IdGenerator): PCtx = - let m = initModuleCon(g, g.config, idgen, module) - PCtx(m: m, c: initProcCon(m, nil, g.config), idgen: idgen) + var lit = Literals() + var nirm = (ref NirModule)(types: initTypeGraph(lit), lit: lit) + var m = initModuleCon(g, g.config, idgen, module, nirm) + m.noModularity = true + PCtx(m: m, c: initProcCon(m, nil, g.config), idgen: idgen, bytecode: initBytecode(nirm)) proc refresh*(c: PCtx; module: PSym; idgen: IdGenerator) = - c.m = initModuleCon(c.m.graph, c.m.graph.config, idgen, module) + #c.m = initModuleCon(c.m.graph, c.m.graph.config, idgen, module, c.m.nirm) + #c.m.noModularity = true c.c = initProcCon(c.m, nil, c.m.graph.config) c.idgen = idgen @@ -46,14 +52,13 @@ proc setupNirReplGen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPa proc evalStmt(c: PCtx; n: PNode) = let n = transformExpr(c.m.graph, c.idgen, c.m.module, n) let pc = genStmt(c.c, n) - - var res = "" - if pc < c.c.code.len: - toString c.c.code, NodePos(pc), c.m.lit.strings, c.m.lit.numbers, res + #var res = "" + #toString c.m.nirm.code, NodePos(pc), c.m.nirm.lit.strings, c.m.nirm.lit.numbers, c.m.symnames, res #res.add "\n--------------------------\n" #toString res, c.m.types.g - echo res - + if pc.int < c.m.nirm.code.len: + execCode c.bytecode, c.m.nirm.code, pc + #echo res proc runCode*(c: PPassContext; n: PNode): PNode = let c = PCtx(c) @@ -71,7 +76,9 @@ type c: ProcCon proc openNirBackend*(g: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = - let m = initModuleCon(g, g.config, idgen, module) + var lit = Literals() + var nirm = (ref NirModule)(types: initTypeGraph(lit), lit: lit) + let m = initModuleCon(g, g.config, idgen, module, nirm) NirPassContext(m: m, c: initProcCon(m, nil, g.config), idgen: idgen) proc gen(c: NirPassContext; n: PNode) = @@ -89,27 +96,9 @@ proc closeNirBackend*(c: PPassContext; finalNode: PNode) = let nimcache = getNimcacheDir(c.c.config).string createDir nimcache let outp = nimcache / c.m.module.name.s.addFileExt("nir") - var r = rodfiles.create(outp) + #c.m.nirm.code = move c.c.code try: - r.storeHeader(nirCookie) - r.storeSection stringsSection - r.store c.m.lit.strings - - r.storeSection numbersSection - r.store c.m.lit.numbers - - r.storeSection bodiesSection - r.store c.c.code - - r.storeSection typesSection - r.store c.m.types.g - - r.storeSection sideChannelSection - r.store c.m.man - - finally: - r.close() - if r.err != ok: - rawMessage(c.c.config, errFatal, "serialization failed: " & outp) - else: + store c.m.nirm[], outp echo "created: ", outp + except IOError: + rawMessage(c.c.config, errFatal, "serialization failed: " & outp) diff --git a/compiler/nir/nirc.nim b/compiler/nir/nirc.nim index 3d8c8e6ff..363507ca6 100644 --- a/compiler/nir/nirc.nim +++ b/compiler/nir/nirc.nim @@ -10,41 +10,46 @@ ## Nir Compiler. Currently only supports a "view" command. import ".." / ic / [bitabs, rodfiles] -import nirinsts, nirtypes, nirlineinfos +import nirinsts, nirtypes, nirlineinfos, nirfiles #, nir2gcc proc view(filename: string) = - var lit = Literals() - - var r = rodfiles.open(filename) - var code = default Tree - var man = default LineInfoManager - var types = initTypeGraph(lit) - try: - r.loadHeader(nirCookie) - r.loadSection stringsSection - r.load lit.strings - - r.loadSection numbersSection - r.load lit.numbers - - r.loadSection bodiesSection - r.load code - - r.loadSection typesSection - r.load types - - r.loadSection sideChannelSection - r.load man - - finally: - r.close() - + let m = load(filename) var res = "" - allTreesToString code, lit.strings, lit.numbers, res + allTreesToString m.code, m.lit.strings, m.lit.numbers, m.symnames, res res.add "\n# TYPES\n" - nirtypes.toString res, types + nirtypes.toString res, m.types echo res -import std / os - -view paramStr(1) +proc libgcc(filename: string) = + let m = load(filename) + #gcc m, filename + +import std / [syncio, parseopt] + +proc writeHelp = + echo """Usage: nirc view|gcc <file.nir>""" + quit 0 + +proc main = + var inp = "" + var cmd = "" + for kind, key, val in getopt(): + case kind + of cmdArgument: + if cmd.len == 0: cmd = key + elif inp.len == 0: inp = key + else: quit "Error: too many arguments" + of cmdLongOption, cmdShortOption: + case key + of "help", "h": writeHelp() + of "version", "v": stdout.write "1.0\n" + of cmdEnd: discard + if inp.len == 0: + quit "Error: no input file specified" + case cmd + of "", "view": + view inp + of "gcc": + libgcc inp + +main() diff --git a/compiler/nir/nirfiles.nim b/compiler/nir/nirfiles.nim new file mode 100644 index 000000000..f6c73178b --- /dev/null +++ b/compiler/nir/nirfiles.nim @@ -0,0 +1,73 @@ +# +# +# The Nim Compiler +# (c) Copyright 2023 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import ".." / ic / [bitabs, rodfiles] +import nirinsts, nirtypes, nirlineinfos + +type + NirModule* = object + code*: Tree + man*: LineInfoManager + types*: TypeGraph + lit*: Literals + symnames*: SymNames + +proc load*(filename: string): NirModule = + let lit = Literals() + result = NirModule(lit: lit, types: initTypeGraph(lit)) + var r = rodfiles.open(filename) + try: + r.loadHeader(nirCookie) + r.loadSection stringsSection + r.load result.lit.strings + + r.loadSection numbersSection + r.load result.lit.numbers + + r.loadSection bodiesSection + r.load result.code + + r.loadSection typesSection + r.load result.types + + r.loadSection sideChannelSection + r.load result.man + + r.loadSection symnamesSection + r.load result.symnames + + finally: + r.close() + +proc store*(m: NirModule; outp: string) = + var r = rodfiles.create(outp) + try: + r.storeHeader(nirCookie) + r.storeSection stringsSection + r.store m.lit.strings + + r.storeSection numbersSection + r.store m.lit.numbers + + r.storeSection bodiesSection + r.store m.code + + r.storeSection typesSection + r.store m.types + + r.storeSection sideChannelSection + r.store m.man + + r.storeSection symnamesSection + r.store m.symnames + + finally: + r.close() + if r.err != ok: + raise newException(IOError, "could store into: " & outp) diff --git a/compiler/nir/nirinsts.nim b/compiler/nir/nirinsts.nim index d95cd061d..7b281e876 100644 --- a/compiler/nir/nirinsts.nim +++ b/compiler/nir/nirinsts.nim @@ -57,6 +57,7 @@ type SummonGlobal, SummonThreadLocal, Summon, # x = Summon Typed <Type ID>; x begins to live + SummonResult, SummonParam, SummonConst, Kill, # `Kill x`: scope end for `x` @@ -110,6 +111,7 @@ type type PragmaKey* = enum FastCall, StdCall, CDeclCall, SafeCall, SysCall, InlineCall, NoinlineCall, ThisCall, NoCall, + CoreName, ExternName, HeaderImport, DllImport, @@ -167,7 +169,7 @@ const type Instr* = object # 8 bytes x: uint32 - info: PackedLineInfo + info*: PackedLineInfo template kind*(n: Instr): Opcode = Opcode(n.x and OpcodeMask) template operand(n: Instr): uint32 = (n.x shr OpcodeBits) @@ -234,6 +236,10 @@ proc nextChild(tree: Tree; pos: var int) {.inline.} = else: inc pos +proc next*(tree: Tree; pos: var NodePos) {.inline.} = nextChild tree, int(pos) + +template firstSon*(n: NodePos): NodePos = NodePos(n.int+1) + iterator sons*(tree: Tree; n: NodePos): NodePos = var pos = n.int assert tree.nodes[pos].kind > LastAtomicValue @@ -243,6 +249,16 @@ iterator sons*(tree: Tree; n: NodePos): NodePos = yield NodePos pos nextChild tree, pos +iterator sonsFrom1*(tree: Tree; n: NodePos): NodePos = + var pos = n.int + assert tree.nodes[pos].kind > LastAtomicValue + let last = pos + tree.nodes[pos].rawSpan + inc pos + nextChild tree, pos + while pos < last: + yield NodePos pos + nextChild tree, pos + template `[]`*(t: Tree; n: NodePos): Instr = t.nodes[n.int] proc span(tree: Tree; pos: int): int {.inline.} = @@ -257,9 +273,46 @@ proc copyTree*(dest: var Tree; src: Tree) = for i in 0..<L: dest.nodes[d+i] = src.nodes[pos+i] +proc sons2*(tree: Tree; n: NodePos): (NodePos, NodePos) = + assert(not isAtom(tree, n.int)) + let a = n.int+1 + let b = a + span(tree, a) + result = (NodePos a, NodePos b) + +proc sons3*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos) = + assert(not isAtom(tree, n.int)) + let a = n.int+1 + let b = a + span(tree, a) + let c = b + span(tree, b) + result = (NodePos a, NodePos b, NodePos c) + +proc typeId*(ins: Instr): TypeId {.inline.} = + assert ins.kind == Typed + result = TypeId(ins.operand) + +proc symId*(ins: Instr): SymId {.inline.} = + assert ins.kind in {SymUse, SymDef} + result = SymId(ins.operand) + +proc immediateVal*(ins: Instr): int {.inline.} = + assert ins.kind == ImmediateVal + result = cast[int](ins.operand) + +proc litId*(ins: Instr): LitId {.inline.} = + assert ins.kind in {StrVal, IntVal} + result = LitId(ins.operand) + + type LabelId* = distinct int +proc `==`*(a, b: LabelId): bool {.borrow.} +proc hash*(a: LabelId): Hash {.borrow.} + +proc label*(ins: Instr): LabelId {.inline.} = + assert ins.kind in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto} + result = LabelId(ins.operand) + proc newLabel*(labelGen: var int): LabelId {.inline.} = result = LabelId labelGen inc labelGen @@ -297,7 +350,7 @@ proc addTyped*(t: var Tree; info: PackedLineInfo; typ: TypeId) {.inline.} = proc addSummon*(t: var Tree; info: PackedLineInfo; s: SymId; typ: TypeId; opc = Summon) {.inline.} = assert typ.int >= 0 - assert opc in {Summon, SummonConst, SummonGlobal, SummonThreadLocal, SummonParam} + assert opc in {Summon, SummonConst, SummonGlobal, SummonThreadLocal, SummonParam, SummonResult} let x = prepare(t, info, opc) t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info) t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info) @@ -345,7 +398,32 @@ proc escapeToNimLit(s: string; result: var string) = result.add c result.add '"' +type + SymNames* = object + s: seq[LitId] + +proc `[]=`*(t: var SymNames; key: SymId; val: LitId) = + let k = int(key) + if k >= t.s.len: t.s.setLen k+1 + t.s[k] = val + +proc `[]`*(t: SymNames; key: SymId): LitId = + let k = int(key) + if k < t.s.len: result = t.s[k] + else: result = LitId(0) + +template localName(s: SymId): string = + let name = names[s] + if name != LitId(0): + strings[name] + else: + $s.int + +proc store*(r: var RodFile; t: SymNames) = storeSeq(r, t.s) +proc load*(r: var RodFile; t: var SymNames) = loadSeq(r, t.s) + proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTable[int64]; + names: SymNames; r: var string; nesting = 0) = if r.len > 0 and r[r.len-1] notin {' ', '\n', '(', '[', '{'}: r.add ' ' @@ -361,10 +439,10 @@ proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTabl escapeToNimLit(strings[LitId t[pos].operand], r) of SymDef: r.add "SymDef " - r.add $t[pos].operand + r.add localName(SymId t[pos].operand) of SymUse: r.add "SymUse " - r.add $t[pos].operand + r.add localName(SymId t[pos].operand) of PragmaId: r.add $cast[PragmaKey](t[pos].operand) of Typed: @@ -374,7 +452,11 @@ proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTabl of NilVal: r.add "NilVal" of Label: - r.add "L" + # undo the nesting: + var spaces = r.len-1 + while spaces >= 0 and r[spaces] == ' ': dec spaces + r.setLen spaces+1 + r.add "\n L" r.add $t[pos].operand of Goto, CheckedGoto, LoopLabel, GotoLoop: r.add $t[pos].kind @@ -385,16 +467,17 @@ proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTabl r.add "{\n" for i in 0..<(nesting+1)*2: r.add ' ' for p in sons(t, pos): - toString t, p, strings, integers, r, nesting+1 + toString t, p, strings, integers, names, r, nesting+1 r.add "\n" for i in 0..<nesting*2: r.add ' ' r.add "}" proc allTreesToString*(t: Tree; strings: BiTable[string]; integers: BiTable[int64]; + names: SymNames; r: var string) = var i = 0 while i < t.len: - toString t, NodePos(i), strings, integers, r + toString t, NodePos(i), strings, integers, names, r nextChild t, i type diff --git a/compiler/nir/nirtypes.nim b/compiler/nir/nirtypes.nim index e07f1395d..d1c7c6084 100644 --- a/compiler/nir/nirtypes.nim +++ b/compiler/nir/nirtypes.nim @@ -42,6 +42,11 @@ type template kind*(n: TypeNode): NirTypeKind = NirTypeKind(n.x and TypeKindMask) template operand(n: TypeNode): uint32 = (n.x shr TypeKindBits) +proc integralBits*(n: TypeNode): int {.inline.} = + # Number of bits in the IntTy, etc. Only valid for integral types. + assert n.kind in {IntTy, UIntTy, FloatTy, BoolTy, CharTy} + result = int(n.operand) + template toX(k: NirTypeKind; operand: uint32): uint32 = uint32(k) or (operand shl TypeKindBits) @@ -150,6 +155,10 @@ proc elementType*(tree: TypeGraph; n: TypeId): TypeId {.inline.} = assert tree[n].kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ArrayTy, LastArrayTy} result = TypeId(n.int+1) +proc litId*(n: TypeNode): LitId {.inline.} = + assert n.kind in {NameVal, IntVal, SizeVal, AlignVal, OffsetVal, AnnotationVal, ObjectTy, UnionTy} + result = LitId(n.operand) + proc kind*(tree: TypeGraph; n: TypeId): NirTypeKind {.inline.} = tree[n].kind proc span(tree: TypeGraph; pos: int): int {.inline.} = @@ -170,7 +179,8 @@ proc sons3(tree: TypeGraph; n: TypeId): (TypeId, TypeId, TypeId) = proc arrayLen*(tree: TypeGraph; n: TypeId): BiggestInt = assert tree[n].kind == ArrayTy - result = tree.lit.numbers[LitId tree[n].operand] + let (_, b) = sons2(tree, n) + result = tree.lit.numbers[LitId tree[b].operand] proc openType*(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos = assert kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, @@ -227,6 +237,10 @@ proc addNominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string) = assert kind in {ObjectTy, UnionTy} tree.nodes.add TypeNode(x: toX(kind, tree.lit.strings.getOrIncl(name))) +proc getTypeTag*(tree: TypeGraph; t: TypeId): string = + assert tree[t].kind in {ObjectTy, UnionTy} + result = tree.lit.strings[LitId tree[t].operand] + proc addVarargs*(tree: var TypeGraph) = tree.nodes.add TypeNode(x: toX(VarargsTy, 0'u32)) @@ -237,7 +251,7 @@ proc getFloat128Type*(tree: var TypeGraph): TypeId = proc addBuiltinType*(g: var TypeGraph; id: TypeId) = g.nodes.add g[id] -template firstSon(n: TypeId): TypeId = TypeId(n.int+1) +template firstSon*(n: TypeId): TypeId = TypeId(n.int+1) proc addType*(g: var TypeGraph; t: TypeId) = # We cannot simply copy `*Decl` nodes. We have to introduce `*Ty` nodes instead: @@ -360,7 +374,9 @@ proc toString*(dest: var string; g: TypeGraph; i: TypeId) = dest.add g.lit.strings[LitId g[i].operand] of ProcTy: dest.add "proc[" - for t in sons(g, i): toString(dest, g, t) + for t in sons(g, i): + dest.add ' ' + toString(dest, g, t) dest.add "]" of ObjectDecl: dest.add "object[" @@ -399,6 +415,12 @@ proc toString*(dest: var string; g: TypeGraph) = dest.add '\n' nextChild g, i +iterator allTypes*(g: TypeGraph; start = 0): TypeId = + var i = start + while i < g.len: + yield TypeId i + nextChild g, i + proc `$`(g: TypeGraph): string = result = "" toString(result, g) diff --git a/compiler/nir/nirvm.nim b/compiler/nir/nirvm.nim index dcb5ded6f..b58f48272 100644 --- a/compiler/nir/nirvm.nim +++ b/compiler/nir/nirvm.nim @@ -15,9 +15,9 @@ We also split the instruction stream into separate (code, debug) seqs while we're at it. ]## -import std / [tables, intsets] +import std / [syncio, assertions, tables, intsets] import ".." / ic / bitabs -import nirinsts, nirtypes +import nirinsts, nirtypes, nirfiles, nirlineinfos type OpcodeM = enum @@ -25,15 +25,14 @@ type IntValM, StrValM, LoadLocalM, # with local ID + LoadGlobalM, + LoadProcM, TypedM, # with type ID PragmaIdM, # with Pragma ID, possible values: see PragmaKey enum NilValM, GotoM, CheckedGotoM, # last atom - LoadProcM, - LoadGlobalM, # `"module".x` - ArrayConstrM, ObjConstrM, RetM, @@ -44,18 +43,16 @@ type SelectListM, # (values...) SelectValueM, # (value) SelectRangeM, # (valueA..valueB) - SummonGlobalM, - SummonThreadLocalM, - SummonM, # x = Summon Typed <Type ID>; x begins to live + AllocLocals, SummonParamM, AddrOfM, - ArrayAtM, # addr(a[i]) + ArrayAtM, # (elemSize, addr(a), i) FieldAtM, # addr(obj.field) LoadM, # a[] - StoreM, # a[] = b AsgnM, # a = b + StoreM, # a[] = b SetExcM, TestExcM, @@ -63,9 +60,7 @@ type CheckedIndexM, CallM, - IndirectCallM, CheckedCallM, # call that can raise - CheckedIndirectCallM, # call that can raise CheckedAddM, # with overflow checking etc. CheckedSubM, CheckedMulM, @@ -103,8 +98,8 @@ const type Instr = distinct uint32 -template kind(n: Instr): OpcodeM = OpcodeM(n and OpcodeMask) -template operand(n: Instr): uint32 = (n shr OpcodeBits) +template kind(n: Instr): OpcodeM = OpcodeM(n.uint32 and OpcodeMask) +template operand(n: Instr): uint32 = (n.uint32 shr OpcodeBits) template toIns(k: OpcodeM; operand: uint32): Instr = Instr(uint32(k) or (operand shl OpcodeBits)) @@ -112,24 +107,108 @@ template toIns(k: OpcodeM; operand: uint32): Instr = template toIns(k: OpcodeM; operand: LitId): Instr = Instr(uint32(k) or (operand.uint32 shl OpcodeBits)) +const + GlobalsSize = 1024*24 + type PatchPos = distinct int CodePos = distinct int - Unit = ref object ## a NIR module + Bytecode* = object + code: seq[Instr] + debug: seq[PackedLineInfo] + m: ref NirModule procs: Table[SymId, CodePos] globals: Table[SymId, uint32] - integers: BiTable[int64] - strings: BiTable[string] - globalsGen: uint32 + globalData: pointer + globalsAddr: uint32 + typeImpls: Table[string, TypeId] + offsets: Table[TypeId, seq[(int, TypeId)]] + sizes: Table[TypeId, (int, int)] # (size, alignment) + oldTypeLen: int + procUsagesToPatch: Table[SymId, seq[CodePos]] Universe* = object ## all units: For interpretation we need that - units: Table[string, Unit] + units: seq[Bytecode] + unitNames: Table[string, int] + current: int - Bytecode = object - code: seq[Instr] - debug: seq[PackedLineInfo] - u: Unit +proc initBytecode*(m: ref NirModule): Bytecode = Bytecode(m: m, globalData: alloc0(GlobalsSize)) + +proc debug(bc: Bytecode; t: TypeId) = + var buf = "" + toString buf, bc.m.types, t + echo buf + +proc debug(bc: Bytecode; info: PackedLineInfo) = + let (litId, line, col) = bc.m.man.unpack(info) + echo bc.m.lit.strings[litId], ":", line, ":", col + +template `[]`(t: seq[Instr]; n: CodePos): Instr = t[n.int] + +proc traverseObject(b: var Bytecode; t, offsetKey: TypeId) = + var size = -1 + var align = -1 + for x in sons(b.m.types, t): + case b.m.types[x].kind + of FieldDecl: + var offset = -1 + for y in sons(b.m.types, x): + if b.m.types[y].kind == OffsetVal: + offset = b.m.lit.numbers[b.m.types[y].litId] + break + b.offsets.mgetOrPut(offsetKey, @[]).add (offset, x.firstSon) + of SizeVal: + size = b.m.lit.numbers[b.m.types[x].litId] + of AlignVal: + align = b.m.lit.numbers[b.m.types[x].litId] + of ObjectTy: + # inheritance + let impl = b.typeImpls.getOrDefault(b.m.lit.strings[b.m.types[x].litId]) + assert impl.int > 0 + traverseObject b, impl, offsetKey + else: discard + if t == offsetKey: + b.sizes[t] = (size, align) + +proc computeSize(b: var Bytecode; t: TypeId): (int, int) = + case b.m.types[t].kind + of ObjectDecl, UnionDecl: + result = b.sizes[t] + of ObjectTy, UnionTy: + let impl = b.typeImpls[b.m.lit.strings[b.m.types[t].litId]] + result = computeSize(b, impl) + of IntTy, UIntTy, FloatTy, BoolTy, CharTy: + let s = b.m.types[t].integralBits div 8 + result = (s, s) + of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ProcTy: + result = (sizeof(pointer), sizeof(pointer)) + of ArrayTy: + let e = elementType(b.m.types, t) + let n = arrayLen(b.m.types, t) + let inner = computeSize(b, e) + result = (inner[0] * n.int, inner[1]) + else: + result = (0, 0) + +proc computeElemSize(b: var Bytecode; t: TypeId): int = + case b.m.types[t].kind + of ArrayTy, APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, LastArrayTy: + result = computeSize(b, elementType(b.m.types, t))[0] + else: + raiseAssert "not an array type" + +proc traverseTypes(b: var Bytecode) = + for t in allTypes(b.m.types, b.oldTypeLen): + if b.m.types[t].kind in {ObjectDecl, UnionDecl}: + assert b.m.types[t.firstSon].kind == NameVal + b.typeImpls[b.m.lit.strings[b.m.types[t.firstSon].litId]] = t + + for t in allTypes(b.m.types, b.oldTypeLen): + if b.m.types[t].kind in {ObjectDecl, UnionDecl}: + assert b.m.types[t.firstSon].kind == NameVal + traverseObject b, t, t + b.oldTypeLen = b.m.types.len const InvalidPatchPos* = PatchPos(-1) @@ -146,7 +225,7 @@ proc add(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; raw: uint32) = bc.debug.add info proc add(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; lit: LitId) = - add bc, info, kind, uint(lit) + add bc, info, kind, uint32(lit) proc isAtom(bc: Bytecode; pos: int): bool {.inline.} = bc.code[pos].kind <= LastAtomicValue proc isAtom(bc: Bytecode; pos: CodePos): bool {.inline.} = bc.code[pos.int].kind <= LastAtomicValue @@ -175,6 +254,8 @@ proc nextChild(bc: Bytecode; pos: var int) {.inline.} = else: inc pos +proc next(bc: Bytecode; pos: var CodePos) {.inline.} = nextChild bc, int(pos) + iterator sons(bc: Bytecode; n: CodePos): CodePos = var pos = n.int assert bc.code[pos].kind > LastAtomicValue @@ -184,88 +265,175 @@ iterator sons(bc: Bytecode; n: CodePos): CodePos = yield CodePos pos nextChild bc, pos -template `[]`*(t: Bytecode; n: CodePos): Instr = t.code[n.int] +iterator sonsFrom1(bc: Bytecode; n: CodePos): CodePos = + var pos = n.int + assert bc.code[pos].kind > LastAtomicValue + let last = pos + bc.code[pos].rawSpan + inc pos + nextChild bc, pos + while pos < last: + yield CodePos pos + nextChild bc, pos + +iterator sonsFrom2(bc: Bytecode; n: CodePos): CodePos = + var pos = n.int + assert bc.code[pos].kind > LastAtomicValue + let last = pos + bc.code[pos].rawSpan + inc pos + nextChild bc, pos + nextChild bc, pos + while pos < last: + yield CodePos pos + nextChild bc, pos + +template firstSon(n: CodePos): CodePos = CodePos(n.int+1) + +template `[]`(t: Bytecode; n: CodePos): Instr = t.code[n.int] proc span(bc: Bytecode; pos: int): int {.inline.} = if bc.code[pos].kind <= LastAtomicValue: 1 else: int(bc.code[pos].operand) +iterator triples*(bc: Bytecode; n: CodePos): (uint32, int, CodePos) = + var pos = n.int + assert bc.code[pos].kind > LastAtomicValue + let last = pos + bc.code[pos].rawSpan + inc pos + while pos < last: + let offset = bc.code[pos].operand + nextChild bc, pos + let size = bc.code[pos].operand.int + nextChild bc, pos + let val = CodePos pos + yield (offset, size, val) + nextChild bc, pos + type Preprocessing = object + u: ref Universe known: Table[LabelId, CodePos] toPatch: Table[LabelId, seq[CodePos]] locals: Table[SymId, uint32] - c: Bytecode # to be moved out - thisModule: LitId + thisModule: uint32 + localsAddr: uint32 markedWithLabel: IntSet -proc genGoto(c: var Preprocessing; lab: LabelId; opc: OpcodeM) = +proc align(address, alignment: uint32): uint32 = + result = (address + (alignment - 1'u32)) and not (alignment - 1'u32) + +proc genGoto(c: var Preprocessing; bc: var Bytecode; info: PackedLineInfo; lab: LabelId; opc: OpcodeM) = let dest = c.known.getOrDefault(lab, CodePos(-1)) if dest.int >= 0: - c.bc.add info, opc, uint32 dest + bc.add info, opc, uint32 dest else: - let here = CodePos(c.bc.code.len) + let here = CodePos(bc.code.len) c.toPatch.mgetOrPut(lab, @[]).add here - c.bc.add info, opc, 1u32 # will be patched once we traversed the label + bc.add info, opc, 1u32 # will be patched once we traversed the label + +type + AddrMode = enum + InDotExpr, WantAddr + +template maybeDeref(doDeref: bool; body: untyped) = + var pos = PatchPos(-1) + if doDeref: + pos = prepare(bc, info, LoadM) + bc.add info, TypedM, 0'u32 + body + if doDeref: + patch(bc, pos) + +const + ForwardedProc = 10_000_000'u32 -proc preprocess(c: var Preprocessing; u: var Universe; t: Tree; n: NodePos) = +proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; flags: set[AddrMode]) = let info = t[n].info template recurse(opc) = - build c.bc, info, opc: - for c in sons(t, n): preprocess(c, u, t, c) + build bc, info, opc: + for ch in sons(t, n): preprocess(c, bc, t, ch, {WantAddr}) case t[n].kind of Nop: discard "don't use Nop" of ImmediateVal: - c.bc.add info, ImmediateValM, t[n].rawOperand + bc.add info, ImmediateValM, t[n].rawOperand of IntVal: - c.bc.add info, IntValM, t[n].rawOperand + bc.add info, IntValM, t[n].rawOperand of StrVal: - c.bc.add info, StrValM, t[n].rawOperand + bc.add info, StrValM, t[n].rawOperand of SymDef: - assert false, "SymDef outside of declaration context" + discard "happens for proc decls. Don't copy the node as we don't need it" of SymUse: let s = t[n].symId if c.locals.hasKey(s): - c.bc.add info, LoadLocalM, c.locals[s] - elif c.bc.u.procs.hasKey(s): - build c.bc, info, LoadProcM: - c.bc.add info, StrValM, thisModule - c.bc.add info, LoadLocalM, uint32 c.bc.u.procs[s] - elif c.bc.u.globals.hasKey(s): - build c.bc, info, LoadGlobalM: - c.bc.add info, StrValM, thisModule - c.bc.add info, LoadLocalM, uint32 s + maybeDeref(WantAddr notin flags): + bc.add info, LoadLocalM, c.locals[s] + elif bc.procs.hasKey(s): + bc.add info, LoadProcM, uint32 bc.procs[s] + elif bc.globals.hasKey(s): + maybeDeref(WantAddr notin flags): + bc.add info, LoadGlobalM, uint32 s else: - assert false, "don't understand SymUse ID" + let here = CodePos(bc.code.len) + bc.add info, LoadProcM, ForwardedProc + uint32(s) + bc.procUsagesToPatch.mgetOrPut(s, @[]).add here + #raiseAssert "don't understand SymUse ID " & $int(s) of ModuleSymUse: - let moduleName {.cursor.} = c.bc.u.strings[t[n.firstSon].litId] - let unit = u.units.getOrDefault(moduleName) + when false: + let (x, y) = sons2(t, n) + let unit = c.u.unitNames.getOrDefault(bc.m.lit.strings[t[x].litId], -1) + let s = t[y].symId + if c.u.units[unit].procs.hasKey(s): + bc.add info, LoadProcM, uint32 c.u.units[unit].procs[s] + elif bc.globals.hasKey(s): + maybeDeref(WantAddr notin flags): + build bc, info, LoadGlobalM: + bc.add info, ImmediateValM, uint32 unit + bc.add info, LoadLocalM, uint32 s + else: + raiseAssert "don't understand ModuleSymUse ID" + raiseAssert "don't understand ModuleSymUse ID" of Typed: - c.bc.add info, TypedM, t[n].rawOperand + bc.add info, TypedM, t[n].rawOperand of PragmaId: - c.bc.add info, TypedM, t[n].rawOperand + bc.add info, PragmaIdM, t[n].rawOperand of NilVal: - c.bc.add info, NilValM, t[n].rawOperand + bc.add info, NilValM, t[n].rawOperand of LoopLabel, Label: let lab = t[n].label - let here = CodePos(c.bc.code.len-1) + let here = CodePos(bc.code.len-1) c.known[lab] = here - var p: seq[CodePos] + var p: seq[CodePos] = @[] if c.toPatch.take(lab, p): - for x in p: c.bc.code[x] = toIns(c.bc.code[x].kind, here) + for x in p: (bc.code[x]) = toIns(bc.code[x].kind, uint32 here) c.markedWithLabel.incl here.int # for toString() of Goto, GotoLoop: - c.genGoto(t[n].label, GotoM) + c.genGoto(bc, info, t[n].label, GotoM) of CheckedGoto: - c.genGoto(t[n].label, CheckedGotoM) + c.genGoto(bc, info, t[n].label, CheckedGotoM) of ArrayConstr: - recurse ArrayConstrM + let typ = t[n.firstSon].typeId + let s = computeElemSize(bc, typ) + build bc, info, ArrayConstrM: + bc.add info, ImmediateValM, uint32 s + for ch in sonsFrom1(t, n): + preprocess(c, bc, t, ch, {WantAddr}) of ObjConstr: - recurse ObjConstrM + var i = 0 + let typ = t[n.firstSon].typeId + build bc, info, ObjConstrM: + for ch in sons(t, n): + if i > 0: + if (i mod 2) == 1: + let (offset, typ) = bc.offsets[typ][t[ch].immediateVal] + let size = computeSize(bc, typ)[0] + bc.add info, ImmediateValM, uint32(offset) + bc.add info, ImmediateValM, uint32(size) + else: + preprocess(c, bc, t, ch, {WantAddr}) + inc i of Ret: recurse RetM of Yld: @@ -281,25 +449,120 @@ proc preprocess(c: var Preprocessing; u: var Universe; t: Tree; n: NodePos) = of SelectRange: recurse SelectRangeM of SummonGlobal, SummonThreadLocal, SummonConst: - #let s = - discard "xxx" - of Summon, SummonParam: - # x = Summon Typed <Type ID>; x begins to live - discard "xxx" + let (typ, sym) = sons2(t, n) + + let s = t[sym].symId + let tid = t[typ].typeId + let (size, alignment) = computeSize(bc, tid) + + let global = align(bc.globalsAddr, uint32 alignment) + bc.globals[s] = global + bc.globalsAddr += uint32 size + assert bc.globalsAddr < GlobalsSize + + of Summon: + let (typ, sym) = sons2(t, n) + + let s = t[sym].symId + let tid = t[typ].typeId + let (size, alignment) = computeSize(bc, tid) + + let local = align(c.localsAddr, uint32 alignment) + c.locals[s] = local + c.localsAddr += uint32 size + # allocation is combined into the frame allocation so there is no + # instruction to emit + of SummonParam, SummonResult: + let (typ, sym) = sons2(t, n) + + let s = t[sym].symId + let tid = t[typ].typeId + let (size, alignment) = computeSize(bc, tid) + + let local = align(c.localsAddr, uint32 alignment) + c.locals[s] = local + c.localsAddr += uint32 size + bc.add info, SummonParamM, local + bc.add info, ImmediateValM, uint32 size of Kill: discard "we don't care about Kill instructions" of AddrOf: - recurse AddrOfM + let (_, arg) = sons2(t, n) + preprocess(c, bc, t, arg, {WantAddr}) + # the address of x is what the VM works with all the time so there is + # nothing to compute. of ArrayAt: - recurse ArrayAtM + let (arrayType, a, i) = sons3(t, n) + let tid = t[arrayType].typeId + let size = uint32 computeElemSize(bc, tid) + if t[a].kind == Load: + let (_, arg) = sons2(t, a) + build bc, info, LoadM: + bc.add info, ImmediateValM, size + build bc, info, ArrayAtM: + bc.add info, ImmediateValM, size + preprocess(c, bc, t, arg, {WantAddr}) + preprocess(c, bc, t, i, {WantAddr}) + else: + build bc, info, ArrayAtM: + bc.add info, ImmediateValM, size + preprocess(c, bc, t, a, {WantAddr}) + preprocess(c, bc, t, i, {WantAddr}) of FieldAt: - recurse FieldAtM + # a[] conceptually loads a block of size of T. But when applied to an object selector + # only a subset of the data is really requested so `(a[] : T).field` + # becomes `(a+offset(field))[] : T_Field` + # And now if this is paired with `addr` the deref disappears, as usual: `addr x.field[]` + # is `(x+offset(field))`. + let (typ, a, b) = sons3(t, n) + if t[a].kind == Load: + let (_, arg) = sons2(t, a) + build bc, info, LoadM: + bc.add info, ImmediateValM, uint32 computeSize(bc, t[typ].typeId)[0] + let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0] + build bc, info, FieldAtM: + preprocess(c, bc, t, arg, flags+{WantAddr}) + bc.add info, ImmediateValM, uint32(offset) + else: + let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0] + build bc, info, FieldAtM: + preprocess(c, bc, t, a, flags+{WantAddr}) + bc.add info, ImmediateValM, uint32(offset) of Load: - recurse LoadM + let (elemType, a) = sons2(t, n) + let tid = t[elemType].typeId + build bc, info, LoadM: + bc.add info, ImmediateValM, uint32 computeSize(bc, tid)[0] + preprocess(c, bc, t, a, {}) + of Store: - recurse StoreM + raiseAssert "Assumption was that Store is unused!" of Asgn: - recurse AsgnM + let (elemType, dest, src) = sons3(t, n) + let tid = t[elemType].typeId + if t[src].kind in {Call, IndirectCall}: + # No support for return values, these are mapped to `var T` parameters! + build bc, info, CallM: + preprocess(c, bc, t, dest, {WantAddr}) + for ch in sons(t, src): preprocess(c, bc, t, ch, {WantAddr}) + elif t[src].kind in {CheckedCall, CheckedIndirectCall}: + build bc, info, CheckedCallM: + preprocess(c, bc, t, src.firstSon, {WantAddr}) + preprocess(c, bc, t, dest, {WantAddr}) + for ch in sonsFrom1(t, src): preprocess(c, bc, t, ch, {WantAddr}) + elif t[dest].kind == Load: + let (typ, a) = sons2(t, dest) + let s = computeSize(bc, tid)[0] + build bc, info, StoreM: + bc.add info, ImmediateValM, uint32 s + preprocess(c, bc, t, a, {WantAddr}) + preprocess(c, bc, t, src, {}) + else: + let s = computeSize(bc, tid)[0] + build bc, info, AsgnM: + bc.add info, ImmediateValM, uint32 s + preprocess(c, bc, t, dest, {WantAddr}) + preprocess(c, bc, t, src, {}) of SetExc: recurse SetExcM of TestExc: @@ -308,14 +571,14 @@ proc preprocess(c: var Preprocessing; u: var Universe; t: Tree; n: NodePos) = recurse CheckedRangeM of CheckedIndex: recurse CheckedIndexM - of Call: - recurse CallM - of IndirectCall: - recurse IndirectCallM - of CheckedCall: - recurse CheckedCallM - of CheckedIndirectCall: - recurse CheckedIndirectCallM + of Call, IndirectCall: + # avoid the Typed thing at position 0: + build bc, info, CallM: + for ch in sonsFrom1(t, n): preprocess(c, bc, t, ch, {WantAddr}) + of CheckedCall, CheckedIndirectCall: + # avoid the Typed thing at position 0: + build bc, info, CheckedCallM: + for ch in sonsFrom1(t, n): preprocess(c, bc, t, ch, {WantAddr}) of CheckedAdd: recurse CheckedAddM of CheckedSub: @@ -367,9 +630,20 @@ proc preprocess(c: var Preprocessing; u: var Universe; t: Tree; n: NodePos) = of TestOf: recurse TestOfM of Emit: - assert false, "cannot interpret: Emit" + raiseAssert "cannot interpret: Emit" of ProcDecl: - recurse ProcDeclM + var c2 = Preprocessing(u: c.u, thisModule: c.thisModule) + let sym = t[n.firstSon].symId + let here = CodePos(bc.len) + var p: seq[CodePos] = @[] + if bc.procUsagesToPatch.take(sym, p): + for x in p: (bc.code[x]) = toIns(bc.code[x].kind, uint32 here) + bc.procs[sym] = here + build bc, info, ProcDeclM: + let toPatch = bc.code.len + bc.add info, AllocLocals, 0'u32 + for ch in sons(t, n): preprocess(c2, bc, t, ch, {}) + bc.code[toPatch] = toIns(AllocLocals, c2.localsAddr) of PragmaPair: recurse PragmaPairM @@ -381,87 +655,399 @@ type payload: array[PayloadSize, byte] caller: StackFrame returnAddr: CodePos + jumpTo: CodePos # exception handling + u: ref Universe proc newStackFrame(size: int; caller: StackFrame; returnAddr: CodePos): StackFrame = - result = StackFrame(caller: caller, returnAddr: returnAddr) + result = StackFrame(caller: caller, returnAddr: returnAddr, u: caller.u) if size <= PayloadSize: result.locals = addr(result.payload) else: result.locals = alloc0(size) proc popStackFrame(s: StackFrame): StackFrame = - if result.locals != addr(result.payload): - dealloc result.locals + if s.locals != addr(s.payload): + dealloc s.locals result = s.caller template `+!`(p: pointer; diff: uint): pointer = cast[pointer](cast[uint](p) + diff) -proc eval(c: seq[Instr]; pc: CodePos; s: StackFrame; result: pointer) +proc isAtom(tree: seq[Instr]; pos: CodePos): bool {.inline.} = tree[pos.int].kind <= LastAtomicValue + +proc span(bc: seq[Instr]; pos: int): int {.inline.} = + if bc[pos].kind <= LastAtomicValue: 1 else: int(bc[pos].operand) + +proc sons2(tree: seq[Instr]; n: CodePos): (CodePos, CodePos) = + assert(not isAtom(tree, n)) + let a = n.int+1 + let b = a + span(tree, a) + result = (CodePos a, CodePos b) + +proc sons3(tree: seq[Instr]; n: CodePos): (CodePos, CodePos, CodePos) = + assert(not isAtom(tree, n)) + let a = n.int+1 + let b = a + span(tree, a) + let c = b + span(tree, b) + result = (CodePos a, CodePos b, CodePos c) + +proc sons4(tree: seq[Instr]; n: CodePos): (CodePos, CodePos, CodePos, CodePos) = + assert(not isAtom(tree, n)) + let a = n.int+1 + let b = a + span(tree, a) + let c = b + span(tree, b) + let d = c + span(tree, c) + result = (CodePos a, CodePos b, CodePos c, CodePos d) -proc evalAddr(c: seq[Instr]; pc: CodePos; s: StackFrame): pointer = - case c[pc].kind +proc typeId*(ins: Instr): TypeId {.inline.} = + assert ins.kind == TypedM + result = TypeId(ins.operand) + +proc immediateVal*(ins: Instr): int {.inline.} = + assert ins.kind == ImmediateValM + result = cast[int](ins.operand) + +proc litId*(ins: Instr): LitId {.inline.} = + assert ins.kind in {StrValM, IntValM} + result = LitId(ins.operand) + +proc eval(c: Bytecode; pc: CodePos; s: StackFrame; result: pointer; size: int) + +proc evalAddr(c: Bytecode; pc: CodePos; s: StackFrame): pointer = + case c.code[pc].kind of LoadLocalM: - result = s.locals +! c[pc].operand + result = s.locals +! c.code[pc].operand of FieldAtM: - result = eval(c, pc+1, s) - result = result +! c[pc+2].operand + let (x, offset) = sons2(c.code, pc) + result = evalAddr(c, x, s) + result = result +! c.code[offset].operand of ArrayAtM: - let elemSize = c[pc+1].operand - result = eval(c, pc+2, s) - var idx: int - eval(c, pc+3, addr idx) - result = result +! (idx * elemSize) - -proc eval(c: seq[Instr]; pc: CodePos; s: StackFrame; result: pointer) = - case c[pc].kind - of AddM: - # assume `int` here for now: - var x, y: int - eval c, pc+1, s, addr x - eval c, pc+2, s, addr y - cast[ptr int](res)[] = x + y + let (e, a, i) = sons3(c.code, pc) + let elemSize = c.code[e].operand + result = evalAddr(c, a, s) + var idx: int = 0 + eval(c, i, s, addr idx, sizeof(int)) + result = result +! (uint32(idx) * elemSize) + of LoadM: + let (_, arg) = sons2(c.code, pc) + let p = evalAddr(c, arg, s) + result = cast[ptr pointer](p)[] + of LoadGlobalM: + result = c.globalData +! c.code[pc].operand + else: + raiseAssert("unimplemented addressing mode") + +proc `div`(x, y: float32): float32 {.inline.} = x / y +proc `div`(x, y: float64): float64 {.inline.} = x / y + +from math import `mod` + +template binop(opr) {.dirty.} = + template impl(typ) {.dirty.} = + var x = default(typ) + var y = default(typ) + eval c, a, s, addr x, sizeof(typ) + eval c, b, s, addr y, sizeof(typ) + cast[ptr typ](result)[] = opr(x, y) + + let (t, a, b) = sons3(c.code, pc) + let tid = TypeId c.code[t].operand + case tid + of Bool8Id, Char8Id, UInt8Id: impl uint8 + of Int8Id: impl int8 + of Int16Id: impl int16 + of Int32Id: impl int32 + of Int64Id: impl int64 + of UInt16Id: impl uint16 + of UInt32Id: impl uint32 + of UInt64Id: impl uint64 + of Float32Id: impl float32 + of Float64Id: impl float64 + else: discard + +template checkedBinop(opr) {.dirty.} = + template impl(typ) {.dirty.} = + var x = default(typ) + var y = default(typ) + eval c, a, s, addr x, sizeof(typ) + eval c, b, s, addr y, sizeof(typ) + try: + cast[ptr typ](result)[] = opr(x, y) + except OverflowDefect, DivByZeroDefect: + s.jumpTo = CodePos c.code[j].operand + + let (t, j, a, b) = sons4(c.code, pc) + let tid = TypeId c.code[t].operand + case tid + of Bool8Id, Char8Id, UInt8Id: impl uint8 + of Int8Id: impl int8 + of Int16Id: impl int16 + of Int32Id: impl int32 + of Int64Id: impl int64 + of UInt16Id: impl uint16 + of UInt32Id: impl uint32 + of UInt64Id: impl uint64 + of Float32Id: impl float32 + of Float64Id: impl float64 + else: discard + +template bitop(opr) {.dirty.} = + template impl(typ) {.dirty.} = + var x = default(typ) + var y = default(typ) + eval c, a, s, addr x, sizeof(typ) + eval c, b, s, addr y, sizeof(typ) + cast[ptr typ](result)[] = opr(x, y) + + let (t, a, b) = sons3(c.code, pc) + let tid = c.code[t].typeId + case tid + of Bool8Id, Char8Id, UInt8Id: impl uint8 + of Int8Id: impl int8 + of Int16Id: impl int16 + of Int32Id: impl int32 + of Int64Id: impl int64 + of UInt16Id: impl uint16 + of UInt32Id: impl uint32 + of UInt64Id: impl uint64 + else: discard + +template cmpop(opr) {.dirty.} = + template impl(typ) {.dirty.} = + var x = default(typ) + var y = default(typ) + eval c, a, s, addr x, sizeof(typ) + eval c, b, s, addr y, sizeof(typ) + cast[ptr bool](result)[] = opr(x, y) + + let (t, a, b) = sons3(c.code, pc) + let tid = c.code[t].typeId + case tid + of Bool8Id, Char8Id, UInt8Id: impl uint8 + of Int8Id: impl int8 + of Int16Id: impl int16 + of Int32Id: impl int32 + of Int64Id: impl int64 + of UInt16Id: impl uint16 + of UInt32Id: impl uint32 + of UInt64Id: impl uint64 + of Float32Id: impl float32 + of Float64Id: impl float64 + else: discard + +proc evalSelect(c: Bytecode; pc: CodePos; s: StackFrame): CodePos = + template impl(typ) {.dirty.} = + var selector = default(typ) + eval c, sel, s, addr selector, sizeof(typ) + for pair in sonsFrom2(c, pc): + assert c.code[pair].kind == SelectPairM + let (values, action) = sons2(c.code, pair) + assert c.code[values].kind == SelectListM + for v in sons(c, values): + case c.code[v].kind + of SelectValueM: + var a = default(typ) + eval c, v.firstSon, s, addr a, sizeof(typ) + if selector == a: + return CodePos c.code[action].operand + of SelectRangeM: + let (va, vb) = sons2(c.code, v) + var a = default(typ) + eval c, va, s, addr a, sizeof(typ) + var b = default(typ) + eval c, vb, s, addr a, sizeof(typ) + if a <= selector and selector <= b: + return CodePos c.code[action].operand + else: raiseAssert "unreachable" + result = CodePos(-1) + + let (t, sel) = sons2(c.code, pc) + let tid = c.code[t].typeId + case tid + of Bool8Id, Char8Id, UInt8Id: impl uint8 + of Int8Id: impl int8 + of Int16Id: impl int16 + of Int32Id: impl int32 + of Int64Id: impl int64 + of UInt16Id: impl uint16 + of UInt32Id: impl uint32 + of UInt64Id: impl uint64 + else: raiseAssert "unreachable" + +proc eval(c: Bytecode; pc: CodePos; s: StackFrame; result: pointer; size: int) = + case c.code[pc].kind + of LoadLocalM: + let dest = s.locals +! c.code[pc].operand + copyMem dest, result, size + of FieldAtM, ArrayAtM, LoadM: + let dest = evalAddr(c, pc, s) + copyMem dest, result, size + of CheckedAddM: checkedBinop `+` + of CheckedSubM: checkedBinop `-` + of CheckedMulM: checkedBinop `*` + of CheckedDivM: checkedBinop `div` + of CheckedModM: checkedBinop `mod` + of AddM: binop `+` + of SubM: binop `-` + of MulM: binop `*` + of DivM: binop `div` + of ModM: binop `mod` + of BitShlM: bitop `shl` + of BitShrM: bitop `shr` + of BitAndM: bitop `and` + of BitOrM: bitop `or` + of BitXorM: bitop `xor` + of EqM: cmpop `==` + of LeM: cmpop `<=` + of LtM: cmpop `<` + of StrValM: - cast[ptr StringDesc](res)[] = addr(c.strings[c[pc].litId]) + # binary compatible and no deep copy required: + copyMem(cast[ptr string](result), addr(c.m.lit.strings[c[pc].litId]), sizeof(string)) + # XXX not correct! of ObjConstrM: - for ch in sons(c, pc): - let offset = c[ch] - eval c, ch+2, s, result+!offset + for offset, size, val in triples(c, pc): + eval c, val, s, result+!offset, size of ArrayConstrM: - let elemSize = c[pc+1].operand + let elemSize = c.code[pc.firstSon].operand var r = result - for ch in sons(c, pc): - eval c, ch, s, r + for ch in sonsFrom1(c, pc): + eval c, ch, s, r, elemSize.int r = r+!elemSize # can even do strength reduction here! + of NumberConvM: + let (t, x) = sons2(c.code, pc) + let word = if c[x].kind == NilValM: 0'i64 else: c.m.lit.numbers[c[x].litId] + + template impl(typ: typedesc) {.dirty.} = + cast[ptr typ](result)[] = cast[typ](word) + + let tid = c.code[t].typeId + case tid + of Bool8Id, Char8Id, UInt8Id: impl uint8 + of Int8Id: impl int8 + of Int16Id: impl int16 + of Int32Id: impl int32 + of Int64Id: impl int64 + of UInt16Id: impl uint16 + of UInt32Id: impl uint32 + of UInt64Id: impl uint64 + else: + case c.m.types[tid].kind + of ProcTy, UPtrTy, APtrTy, AArrayPtrTy, UArrayPtrTy: + # the VM always uses 64 bit pointers: + impl uint64 + else: + raiseAssert "cannot happen" else: - assert false, "cannot happen" + #debug c, c.debug[pc.int] + raiseAssert "cannot happen: " & $c.code[pc].kind -proc exec(c: seq[Instr]; pc: CodePos) = - var pc = pc - var currentFrame: StackFrame = nil +proc evalProc(c: Bytecode; pc: CodePos; s: StackFrame): CodePos = + assert c.code[pc].kind == LoadProcM + let procSym = c[pc].operand + when false: + if procSym >= ForwardedProc: + for k, v in c.procUsagesToPatch: + if uint32(k) == procSym - ForwardedProc: + echo k.int, " ", v.len, " <-- this one" + else: + echo k.int, " ", v.len + + assert procSym < ForwardedProc + result = CodePos(procSym) + +proc echoImpl(c: Bytecode; pc: CodePos; s: StackFrame) = + type StringArray = object + len: int + data: ptr UncheckedArray[string] + var sa = default(StringArray) + for a in sonsFrom1(c, pc): + eval(c, a, s, addr(sa), sizeof(sa)) + for i in 0..<sa.len: + stdout.write sa.data[i] + stdout.write "\n" + stdout.flushFile() + +proc evalBuiltin(c: Bytecode; pc: CodePos; s: StackFrame; prc: CodePos; didEval: var bool): CodePos = + var prc = prc while true: - case c[pc].kind + case c[prc].kind + of PragmaPairM: + let (x, y) = sons2(c.code, prc) + if cast[PragmaKey](c[x]) == CoreName: + let lit = c[y].litId + case c.m.lit.strings[lit] + of "echoBinSafe": echoImpl(c, pc, s) + else: discard + echo "running compilerproc: ", c.m.lit.strings[lit] + didEval = true + of PragmaIdM: discard + else: break + next c, prc + result = prc + +proc exec(c: Bytecode; pc: CodePos; u: ref Universe) = + var pc = pc + var s = StackFrame(u: u) + while pc.int < c.code.len: + case c.code[pc].kind of GotoM: - pc = CodePos(c[pc].operand) - of Asgn: - let (size, a, b) = sons3(c, pc) + pc = CodePos(c.code[pc].operand) + of AsgnM: + let (sz, a, b) = sons3(c.code, pc) let dest = evalAddr(c, a, s) - eval(c, b, s, dest) + eval(c, b, s, dest, c.code[sz].operand.int) + next c, pc + of StoreM: + let (sz, a, b) = sons3(c.code, pc) + let destPtr = evalAddr(c, a, s) + let dest = cast[ptr pointer](destPtr)[] + eval(c, b, s, dest, c.code[sz].operand.int) + next c, pc of CallM: # No support for return values, these are mapped to `var T` parameters! - let prc = evalProc(c, pc+1) - # setup storage for the proc already: - let s2 = newStackFrame(prc.frameSize, currentFrame, pc) - var i = 0 - for a in sons(c, pc): - eval(c, a, s2, paramAddr(s2, i)) - inc i - currentFrame = s2 - pc = pcOf(prc) + var prc = evalProc(c, pc.firstSon, s) + assert c.code[prc.firstSon].kind == AllocLocals + let frameSize = int c.code[prc.firstSon].operand + # skip stupid stuff: + var didEval = false + prc = evalBuiltin(c, pc, s, prc.firstSon, didEval) + if didEval: + next c, pc + else: + # setup storage for the proc already: + let callInstr = pc + next c, pc + let s2 = newStackFrame(frameSize, s, pc) + for a in sonsFrom1(c, callInstr): + assert c[prc].kind == SummonParamM + let paramAddr = c[prc].operand + assert c[prc.firstSon].kind == ImmediateValM + let paramSize = c[prc.firstSon].operand.int + eval(c, a, s2, s2.locals +! paramAddr, paramSize) + next c, prc + next c, prc + s = s2 + pc = prc of RetM: - pc = currentFrame.returnAddr - currentFrame = popStackFrame(currentFrame) + pc = s.returnAddr + s = popStackFrame(s) of SelectM: - var x: bool - eval(c, b, addr x) - # follow the selection instructions... - pc = activeBranch(c, b, x) + let pc2 = evalSelect(c, pc, s) + if pc2.int >= 0: + pc = pc2 + else: + next c, pc + of ProcDeclM: + next c, pc + else: + raiseAssert "unreachable" + +proc execCode*(bc: var Bytecode; t: Tree; n: NodePos) = + traverseTypes bc + var c = Preprocessing(u: nil, thisModule: 1'u32) + let start = CodePos(bc.code.len) + var pc = n + while pc.int < t.len: + preprocess c, bc, t, pc, {} + next t, pc + exec bc, start, nil diff --git a/compiler/nir/types2ir.nim b/compiler/nir/types2ir.nim index 76907d587..4c3ce7001 100644 --- a/compiler/nir/types2ir.nim +++ b/compiler/nir/types2ir.nim @@ -15,11 +15,11 @@ type TypesCon* = object processed: Table[ItemId, TypeId] recursionCheck: HashSet[ItemId] - g*: TypeGraph conf: ConfigRef + stringType: TypeId -proc initTypesCon*(conf: ConfigRef; lit: Literals): TypesCon = - TypesCon(g: initTypeGraph(lit), conf: conf) +proc initTypesCon*(conf: ConfigRef): TypesCon = + TypesCon(conf: conf, stringType: TypeId(-1)) proc mangle(c: var TypesCon; t: PType): string = result = $sighashes.hashType(t, c.conf) @@ -30,131 +30,131 @@ template cached(c: var TypesCon; t: PType; body: untyped) = body c.processed[t.itemId] = result -proc typeToIr*(c: var TypesCon; t: PType): TypeId +proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId -proc collectFieldTypes(c: var TypesCon; n: PNode; dest: var Table[ItemId, TypeId]) = +proc collectFieldTypes(c: var TypesCon; g: var TypeGraph; n: PNode; dest: var Table[ItemId, TypeId]) = case n.kind of nkRecList: for i in 0..<n.len: - collectFieldTypes(c, n[i], dest) + collectFieldTypes(c, g, n[i], dest) of nkRecCase: assert(n[0].kind == nkSym) - collectFieldTypes(c, n[0], dest) + collectFieldTypes(c, g, n[0], dest) for i in 1..<n.len: case n[i].kind of nkOfBranch, nkElse: - collectFieldTypes c, lastSon(n[i]), dest + collectFieldTypes c, g, lastSon(n[i]), dest else: discard of nkSym: - dest[n.sym.itemId] = typeToIr(c, n.sym.typ) + dest[n.sym.itemId] = typeToIr(c, g, n.sym.typ) else: assert false, "unknown node kind: " & $n.kind -proc objectToIr(c: var TypesCon; n: PNode; fieldTypes: Table[ItemId, TypeId]; unionId: var int) = +proc objectToIr(c: var TypesCon; g: var TypeGraph; n: PNode; fieldTypes: Table[ItemId, TypeId]; unionId: var int) = case n.kind of nkRecList: for i in 0..<n.len: - objectToIr(c, n[i], fieldTypes, unionId) + objectToIr(c, g, n[i], fieldTypes, unionId) of nkRecCase: assert(n[0].kind == nkSym) - objectToIr(c, n[0], fieldTypes, unionId) - let u = openType(c.g, UnionDecl) - c.g.addName "u_" & $unionId + objectToIr(c, g, n[0], fieldTypes, unionId) + let u = openType(g, UnionDecl) + g.addName "u_" & $unionId inc unionId for i in 1..<n.len: case n[i].kind of nkOfBranch, nkElse: - let subObj = openType(c.g, ObjectDecl) - c.g.addName "uo_" & $unionId & "_" & $i - objectToIr c, lastSon(n[i]), fieldTypes, unionId - sealType(c.g, subObj) + let subObj = openType(g, ObjectDecl) + g.addName "uo_" & $unionId & "_" & $i + objectToIr c, g, lastSon(n[i]), fieldTypes, unionId + sealType(g, subObj) else: discard - sealType(c.g, u) + sealType(g, u) of nkSym: - c.g.addField n.sym.name.s & "_" & $n.sym.position, fieldTypes[n.sym.itemId], n.sym.offset + g.addField n.sym.name.s & "_" & $n.sym.position, fieldTypes[n.sym.itemId], n.sym.offset else: assert false, "unknown node kind: " & $n.kind -proc objectToIr(c: var TypesCon; t: PType): TypeId = +proc objectToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = if t[0] != nil: # ensure we emitted the base type: - discard typeToIr(c, t[0]) + discard typeToIr(c, g, t[0]) var unionId = 0 var fieldTypes = initTable[ItemId, TypeId]() - collectFieldTypes c, t.n, fieldTypes - let obj = openType(c.g, ObjectDecl) - c.g.addName mangle(c, t) - c.g.addSize c.conf.getSize(t) - c.g.addAlign c.conf.getAlign(t) + collectFieldTypes c, g, t.n, fieldTypes + let obj = openType(g, ObjectDecl) + g.addName mangle(c, t) + g.addSize c.conf.getSize(t) + g.addAlign c.conf.getAlign(t) if t[0] != nil: - c.g.addNominalType(ObjectTy, mangle(c, t[0])) + g.addNominalType(ObjectTy, mangle(c, t[0])) else: - c.g.addBuiltinType VoidId # object does not inherit + g.addBuiltinType VoidId # object does not inherit if not lacksMTypeField(t): - let f2 = c.g.openType FieldDecl - let voidPtr = openType(c.g, APtrTy) - c.g.addBuiltinType(VoidId) - sealType(c.g, voidPtr) - c.g.addOffset 0 # type field is always at offset 0 - c.g.addName "m_type" - sealType(c.g, f2) # FieldDecl + let f2 = g.openType FieldDecl + let voidPtr = openType(g, APtrTy) + g.addBuiltinType(VoidId) + sealType(g, voidPtr) + g.addOffset 0 # type field is always at offset 0 + g.addName "m_type" + sealType(g, f2) # FieldDecl - objectToIr c, t.n, fieldTypes, unionId - result = finishType(c.g, obj) + objectToIr c, g, t.n, fieldTypes, unionId + result = finishType(g, obj) -proc objectHeaderToIr(c: var TypesCon; t: PType): TypeId = - result = c.g.nominalType(ObjectTy, mangle(c, t)) +proc objectHeaderToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = + result = g.nominalType(ObjectTy, mangle(c, t)) -proc tupleToIr(c: var TypesCon; t: PType): TypeId = +proc tupleToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = var fieldTypes = newSeq[TypeId](t.len) for i in 0..<t.len: - fieldTypes[i] = typeToIr(c, t[i]) - let obj = openType(c.g, ObjectDecl) - c.g.addName mangle(c, t) - c.g.addSize c.conf.getSize(t) - c.g.addAlign c.conf.getAlign(t) + fieldTypes[i] = typeToIr(c, g, t[i]) + let obj = openType(g, ObjectDecl) + g.addName mangle(c, t) + g.addSize c.conf.getSize(t) + g.addAlign c.conf.getAlign(t) var accum = OffsetAccum(maxAlign: 1) for i in 0..<t.len: let child = t[i] - c.g.addField "f_" & $i, fieldTypes[i], accum.offset + g.addField "f_" & $i, fieldTypes[i], accum.offset computeSizeAlign(c.conf, child) accum.align(child.align) accum.inc(int32(child.size)) - result = finishType(c.g, obj) + result = finishType(g, obj) -proc procToIr(c: var TypesCon; t: PType; addEnv = false): TypeId = +proc procToIr(c: var TypesCon; g: var TypeGraph; t: PType; addEnv = false): TypeId = var fieldTypes = newSeq[TypeId](0) for i in 0..<t.len: if t[i] == nil or not isCompileTimeOnly(t[i]): - fieldTypes.add typeToIr(c, t[i]) - let obj = openType(c.g, ProcTy) + fieldTypes.add typeToIr(c, g, t[i]) + let obj = openType(g, ProcTy) case t.callConv - of ccNimCall, ccFastCall, ccClosure: c.g.addAnnotation "__fastcall" - of ccStdCall: c.g.addAnnotation "__stdcall" - of ccCDecl: c.g.addAnnotation "__cdecl" - of ccSafeCall: c.g.addAnnotation "__safecall" - of ccSysCall: c.g.addAnnotation "__syscall" - of ccInline: c.g.addAnnotation "__inline" - of ccNoInline: c.g.addAnnotation "__noinline" - of ccThisCall: c.g.addAnnotation "__thiscall" - of ccNoConvention: c.g.addAnnotation "" + of ccNimCall, ccFastCall, ccClosure: g.addAnnotation "__fastcall" + of ccStdCall: g.addAnnotation "__stdcall" + of ccCDecl: g.addAnnotation "__cdecl" + of ccSafeCall: g.addAnnotation "__safecall" + of ccSysCall: g.addAnnotation "__syscall" + of ccInline: g.addAnnotation "__inline" + of ccNoInline: g.addAnnotation "__noinline" + of ccThisCall: g.addAnnotation "__thiscall" + of ccNoConvention: g.addAnnotation "" for i in 0..<fieldTypes.len: - c.g.addType fieldTypes[i] + g.addType fieldTypes[i] if addEnv: - let a = openType(c.g, APtrTy) - c.g.addBuiltinType(VoidId) - sealType(c.g, a) + let a = openType(g, APtrTy) + g.addBuiltinType(VoidId) + sealType(g, a) if tfVarargs in t.flags: - c.g.addVarargs() - result = finishType(c.g, obj) + g.addVarargs() + result = finishType(g, obj) proc nativeInt(c: TypesCon): TypeId = case c.conf.target.intSize @@ -162,65 +162,65 @@ proc nativeInt(c: TypesCon): TypeId = of 4: result = Int32Id else: result = Int64Id -proc openArrayPayloadType*(c: var TypesCon; t: PType): TypeId = +proc openArrayPayloadType*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = let e = lastSon(t) - let elementType = typeToIr(c, e) - let arr = c.g.openType AArrayPtrTy - c.g.addType elementType - result = finishType(c.g, arr) # LastArrayTy + let elementType = typeToIr(c, g, e) + let arr = g.openType AArrayPtrTy + g.addType elementType + result = finishType(g, arr) # LastArrayTy -proc openArrayToIr(c: var TypesCon; t: PType): TypeId = +proc openArrayToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = # object (a: ArrayPtr[T], len: int) let e = lastSon(t) let mangledBase = mangle(c, e) let typeName = "NimOpenArray" & mangledBase - let elementType = typeToIr(c, e) + let elementType = typeToIr(c, g, e) #assert elementType.int >= 0, typeToString(t) - let p = openType(c.g, ObjectDecl) - c.g.addName typeName - c.g.addSize c.conf.target.ptrSize*2 - c.g.addAlign c.conf.target.ptrSize - - let f = c.g.openType FieldDecl - let arr = c.g.openType AArrayPtrTy - c.g.addType elementType - sealType(c.g, arr) # LastArrayTy - c.g.addOffset 0 - c.g.addName "data" - sealType(c.g, f) # FieldDecl - - c.g.addField "len", c.nativeInt, c.conf.target.ptrSize - - result = finishType(c.g, p) # ObjectDecl - -proc strPayloadType(c: var TypesCon): string = - result = "NimStrPayload" - let p = openType(c.g, ObjectDecl) - c.g.addName result - c.g.addSize c.conf.target.ptrSize*2 - c.g.addAlign c.conf.target.ptrSize - - c.g.addField "cap", c.nativeInt, 0 - - let f = c.g.openType FieldDecl - let arr = c.g.openType LastArrayTy - c.g.addBuiltinType Char8Id - sealType(c.g, arr) # LastArrayTy - c.g.addOffset c.conf.target.ptrSize # comes after the len field - c.g.addName "data" - sealType(c.g, f) # FieldDecl - - sealType(c.g, p) - -proc strPayloadPtrType*(c: var TypesCon): TypeId = - let mangled = strPayloadType(c) - let ffp = c.g.openType APtrTy - c.g.addNominalType ObjectTy, mangled - result = finishType(c.g, ffp) # APtrTy - -proc stringToIr(c: var TypesCon): TypeId = + let p = openType(g, ObjectDecl) + g.addName typeName + g.addSize c.conf.target.ptrSize*2 + g.addAlign c.conf.target.ptrSize + + let f = g.openType FieldDecl + let arr = g.openType AArrayPtrTy + g.addType elementType + sealType(g, arr) # LastArrayTy + g.addOffset 0 + g.addName "data" + sealType(g, f) # FieldDecl + + g.addField "len", c.nativeInt, c.conf.target.ptrSize + + result = finishType(g, p) # ObjectDecl + +proc strPayloadType(c: var TypesCon; g: var TypeGraph): (string, TypeId) = + result = ("NimStrPayload", TypeId(-1)) + let p = openType(g, ObjectDecl) + g.addName result[0] + g.addSize c.conf.target.ptrSize*2 + g.addAlign c.conf.target.ptrSize + + g.addField "cap", c.nativeInt, 0 + + let f = g.openType FieldDecl + let arr = g.openType LastArrayTy + g.addBuiltinType Char8Id + result[1] = finishType(g, arr) # LastArrayTy + g.addOffset c.conf.target.ptrSize # comes after the len field + g.addName "data" + sealType(g, f) # FieldDecl + + sealType(g, p) + +proc strPayloadPtrType*(c: var TypesCon; g: var TypeGraph): (TypeId, TypeId) = + let (mangled, arrayType) = strPayloadType(c, g) + let ffp = g.openType APtrTy + g.addNominalType ObjectTy, mangled + result = (finishType(g, ffp), arrayType) # APtrTy + +proc stringToIr(c: var TypesCon; g: var TypeGraph): TypeId = #[ NimStrPayload = object @@ -232,86 +232,86 @@ proc stringToIr(c: var TypesCon): TypeId = p: ptr NimStrPayload ]# - let payload = strPayloadType(c) + let payload = strPayloadType(c, g) - let str = openType(c.g, ObjectDecl) - c.g.addName "NimStringV2" - c.g.addSize c.conf.target.ptrSize*2 - c.g.addAlign c.conf.target.ptrSize + let str = openType(g, ObjectDecl) + g.addName "NimStringV2" + g.addSize c.conf.target.ptrSize*2 + g.addAlign c.conf.target.ptrSize - c.g.addField "len", c.nativeInt, 0 + g.addField "len", c.nativeInt, 0 - let fp = c.g.openType FieldDecl - let ffp = c.g.openType APtrTy - c.g.addNominalType ObjectTy, "NimStrPayload" - sealType(c.g, ffp) # APtrTy - c.g.addOffset c.conf.target.ptrSize # comes after 'len' field - c.g.addName "p" - sealType(c.g, fp) # FieldDecl + let fp = g.openType FieldDecl + let ffp = g.openType APtrTy + g.addNominalType ObjectTy, "NimStrPayload" + sealType(g, ffp) # APtrTy + g.addOffset c.conf.target.ptrSize # comes after 'len' field + g.addName "p" + sealType(g, fp) # FieldDecl - result = finishType(c.g, str) # ObjectDecl + result = finishType(g, str) # ObjectDecl -proc seqPayloadType(c: var TypesCon; t: PType): string = +proc seqPayloadType(c: var TypesCon; g: var TypeGraph; t: PType): (string, TypeId) = #[ NimSeqPayload[T] = object cap: int data: UncheckedArray[T] ]# let e = lastSon(t) - result = mangle(c, e) - let payloadName = "NimSeqPayload" & result - - let elementType = typeToIr(c, e) - - let p = openType(c.g, ObjectDecl) - c.g.addName payloadName - c.g.addSize c.conf.target.intSize - c.g.addAlign c.conf.target.intSize - - c.g.addField "cap", c.nativeInt, 0 - - let f = c.g.openType FieldDecl - let arr = c.g.openType LastArrayTy - c.g.addType elementType - sealType(c.g, arr) # LastArrayTy - c.g.addOffset c.conf.target.ptrSize - c.g.addName "data" - sealType(c.g, f) # FieldDecl - sealType(c.g, p) - -proc seqPayloadPtrType*(c: var TypesCon; t: PType): TypeId = - let mangledBase = seqPayloadType(c, t) - let ffp = c.g.openType APtrTy - c.g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase - result = finishType(c.g, ffp) # APtrTy - -proc seqToIr(c: var TypesCon; t: PType): TypeId = + result = (mangle(c, e), TypeId(-1)) + let payloadName = "NimSeqPayload" & result[0] + + let elementType = typeToIr(c, g, e) + + let p = openType(g, ObjectDecl) + g.addName payloadName + g.addSize c.conf.target.intSize + g.addAlign c.conf.target.intSize + + g.addField "cap", c.nativeInt, 0 + + let f = g.openType FieldDecl + let arr = g.openType LastArrayTy + g.addType elementType + result[1] = finishType(g, arr) # LastArrayTy + g.addOffset c.conf.target.ptrSize + g.addName "data" + sealType(g, f) # FieldDecl + sealType(g, p) + +proc seqPayloadPtrType*(c: var TypesCon; g: var TypeGraph; t: PType): (TypeId, TypeId) = + let (mangledBase, arrayType) = seqPayloadType(c, g, t) + let ffp = g.openType APtrTy + g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase + result = (finishType(g, ffp), arrayType) # APtrTy + +proc seqToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = #[ NimSeqV2*[T] = object len: int p: ptr NimSeqPayload[T] ]# - let mangledBase = seqPayloadType(c, t) + let (mangledBase, _) = seqPayloadType(c, g, t) - let sq = openType(c.g, ObjectDecl) - c.g.addName "NimSeqV2" & mangledBase - c.g.addSize c.conf.getSize(t) - c.g.addAlign c.conf.getAlign(t) + let sq = openType(g, ObjectDecl) + g.addName "NimSeqV2" & mangledBase + g.addSize c.conf.getSize(t) + g.addAlign c.conf.getAlign(t) - c.g.addField "len", c.nativeInt, 0 + g.addField "len", c.nativeInt, 0 - let fp = c.g.openType FieldDecl - let ffp = c.g.openType APtrTy - c.g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase - sealType(c.g, ffp) # APtrTy - c.g.addOffset c.conf.target.ptrSize - c.g.addName "p" - sealType(c.g, fp) # FieldDecl + let fp = g.openType FieldDecl + let ffp = g.openType APtrTy + g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase + sealType(g, ffp) # APtrTy + g.addOffset c.conf.target.ptrSize + g.addName "p" + sealType(g, fp) # FieldDecl - result = finishType(c.g, sq) # ObjectDecl + result = finishType(g, sq) # ObjectDecl -proc closureToIr(c: var TypesCon; t: PType): TypeId = +proc closureToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = # struct {fn(args, void* env), env} # typedef struct {$n" & # "N_NIMCALL_PTR($2, ClP_0) $3;$n" & @@ -319,31 +319,31 @@ proc closureToIr(c: var TypesCon; t: PType): TypeId = let mangledBase = mangle(c, t) let typeName = "NimClosure" & mangledBase - let procType = procToIr(c, t, addEnv=true) + let procType = procToIr(c, g, t, addEnv=true) - let p = openType(c.g, ObjectDecl) - c.g.addName typeName - c.g.addSize c.conf.getSize(t) - c.g.addAlign c.conf.getAlign(t) + let p = openType(g, ObjectDecl) + g.addName typeName + g.addSize c.conf.getSize(t) + g.addAlign c.conf.getAlign(t) - let f = c.g.openType FieldDecl - c.g.addType procType - c.g.addOffset 0 - c.g.addName "ClP_0" - sealType(c.g, f) # FieldDecl + let f = g.openType FieldDecl + g.addType procType + g.addOffset 0 + g.addName "ClP_0" + sealType(g, f) # FieldDecl - let f2 = c.g.openType FieldDecl - let voidPtr = openType(c.g, APtrTy) - c.g.addBuiltinType(VoidId) - sealType(c.g, voidPtr) + let f2 = g.openType FieldDecl + let voidPtr = openType(g, APtrTy) + g.addBuiltinType(VoidId) + sealType(g, voidPtr) - c.g.addOffset c.conf.target.ptrSize - c.g.addName "ClE_0" - sealType(c.g, f2) # FieldDecl + g.addOffset c.conf.target.ptrSize + g.addName "ClE_0" + sealType(g, f2) # FieldDecl - result = finishType(c.g, p) # ObjectDecl + result = finishType(g, p) # ObjectDecl -proc bitsetBasetype*(c: var TypesCon; t: PType): TypeId = +proc bitsetBasetype*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = let s = int(getSize(c.conf, t)) case s of 1: result = UInt8Id @@ -352,7 +352,7 @@ proc bitsetBasetype*(c: var TypesCon; t: PType): TypeId = of 8: result = UInt64Id else: result = UInt8Id -proc typeToIr*(c: var TypesCon; t: PType): TypeId = +proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = if t == nil: return VoidId case t.kind of tyInt: @@ -370,7 +370,7 @@ proc typeToIr*(c: var TypesCon; t: PType): TypeId = else: result = Float64Id of tyFloat32: result = Float32Id of tyFloat64: result = Float64Id - of tyFloat128: result = getFloat128Type(c.g) + of tyFloat128: result = getFloat128Type(g) of tyUInt: case int(getSize(c.conf, t)) of 2: result = UInt16Id @@ -384,7 +384,7 @@ proc typeToIr*(c: var TypesCon; t: PType): TypeId = of tyChar: result = Char8Id of tyVoid: result = VoidId of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned, tyRange: - result = typeToIr(c, t.lastSon) + result = typeToIr(c, g, t.lastSon) of tyEnum: if firstOrd(c.conf, t) < 0: result = Int32Id @@ -397,47 +397,47 @@ proc typeToIr*(c: var TypesCon; t: PType): TypeId = else: result = Int32Id of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic: if t.len > 0: - result = typeToIr(c, t.lastSon) + result = typeToIr(c, g, t.lastSon) else: result = TypeId(-1) of tyFromExpr: if t.n != nil and t.n.typ != nil: - result = typeToIr(c, t.n.typ) + result = typeToIr(c, g, t.n.typ) else: result = TypeId(-1) of tyArray: cached(c, t): var n = toInt64(lengthOrd(c.conf, t)) if n <= 0: n = 1 # make an array of at least one element - let elemType = typeToIr(c, t[1]) - let a = openType(c.g, ArrayTy) - c.g.addType(elemType) - c.g.addArrayLen n - result = finishType(c.g, a) + let elemType = typeToIr(c, g, t[1]) + let a = openType(g, ArrayTy) + g.addType(elemType) + g.addArrayLen n + result = finishType(g, a) of tyPtr, tyRef: cached(c, t): let e = t.lastSon if e.kind == tyUncheckedArray: - let elemType = typeToIr(c, e.lastSon) - let a = openType(c.g, AArrayPtrTy) - c.g.addType(elemType) - result = finishType(c.g, a) + let elemType = typeToIr(c, g, e.lastSon) + let a = openType(g, AArrayPtrTy) + g.addType(elemType) + result = finishType(g, a) else: - let elemType = typeToIr(c, t.lastSon) - let a = openType(c.g, APtrTy) - c.g.addType(elemType) - result = finishType(c.g, a) + let elemType = typeToIr(c, g, t.lastSon) + let a = openType(g, APtrTy) + g.addType(elemType) + result = finishType(g, a) of tyVar, tyLent: cached(c, t): let e = t.lastSon if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}: # skip the modifier, `var openArray` is a (ptr, len) pair too: - result = typeToIr(c, e) + result = typeToIr(c, g, e) else: - let elemType = typeToIr(c, e) - let a = openType(c.g, APtrTy) - c.g.addType(elemType) - result = finishType(c.g, a) + let elemType = typeToIr(c, g, e) + let a = openType(g, APtrTy) + g.addType(elemType) + result = finishType(g, a) of tySet: let s = int(getSize(c.conf, t)) case s @@ -448,54 +448,57 @@ proc typeToIr*(c: var TypesCon; t: PType): TypeId = else: # array[U8, s] cached(c, t): - let a = openType(c.g, ArrayTy) - c.g.addType(UInt8Id) - c.g.addArrayLen s - result = finishType(c.g, a) + let a = openType(g, ArrayTy) + g.addType(UInt8Id) + g.addArrayLen s + result = finishType(g, a) of tyPointer, tyNil: # tyNil can happen for code like: `const CRAP = nil` which we have in posix.nim - let a = openType(c.g, APtrTy) - c.g.addBuiltinType(VoidId) - result = finishType(c.g, a) + let a = openType(g, APtrTy) + g.addBuiltinType(VoidId) + result = finishType(g, a) of tyObject: # Objects are special as they can be recursive in Nim. This is easily solvable. # We check if we are already "processing" t. If so, we produce `ObjectTy` # instead of `ObjectDecl`. cached(c, t): if not c.recursionCheck.containsOrIncl(t.itemId): - result = objectToIr(c, t) + result = objectToIr(c, g, t) else: - result = objectHeaderToIr(c, t) + result = objectHeaderToIr(c, g, t) of tyTuple: cached(c, t): - result = tupleToIr(c, t) + result = tupleToIr(c, g, t) of tyProc: cached(c, t): if t.callConv == ccClosure: - result = closureToIr(c, t) + result = closureToIr(c, g, t) else: - result = procToIr(c, t) + result = procToIr(c, g, t) of tyVarargs, tyOpenArray: cached(c, t): - result = openArrayToIr(c, t) + result = openArrayToIr(c, g, t) of tyString: - cached(c, t): - result = stringToIr(c) + if c.stringType.int < 0: + result = stringToIr(c, g) + c.stringType = result + else: + result = c.stringType of tySequence: cached(c, t): - result = seqToIr(c, t) + result = seqToIr(c, g, t) of tyCstring: cached(c, t): - let a = openType(c.g, AArrayPtrTy) - c.g.addBuiltinType Char8Id - result = finishType(c.g, a) + let a = openType(g, AArrayPtrTy) + g.addBuiltinType Char8Id + result = finishType(g, a) of tyUncheckedArray: # We already handled the `ptr UncheckedArray` in a special way. cached(c, t): - let elemType = typeToIr(c, t.lastSon) - let a = openType(c.g, LastArrayTy) - c.g.addType(elemType) - result = finishType(c.g, a) + let elemType = typeToIr(c, g, t.lastSon) + let a = openType(g, LastArrayTy) + g.addType(elemType) + result = finishType(g, a) of tyUntyped, tyTyped: # this avoids a special case for system.echo which is not a generic but # uses `varargs[typed]`: diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index be931ed14..1c8a79fd8 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -65,7 +65,7 @@ elif defined(macosx) or defined(linux) or defined(freebsd) or SIGSEGV* = cint(11) SIGTERM* = cint(15) SIGPIPE* = cint(13) - SIG_DFL* = cast[CSighandlerT](0) + SIG_DFL* = CSighandlerT(nil) elif defined(haiku): const SIGABRT* = cint(6) @@ -75,7 +75,7 @@ elif defined(haiku): SIGSEGV* = cint(11) SIGTERM* = cint(15) SIGPIPE* = cint(7) - SIG_DFL* = cast[CSighandlerT](0) + SIG_DFL* = CSighandlerT(nil) else: when defined(nimscript): {.error: "SIGABRT not ported to your platform".} |