diff options
author | ringabout <43030857+ringabout@users.noreply.github.com> | 2024-07-09 15:29:45 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-09 09:29:45 +0200 |
commit | 732f7752a954bb33a92e839304006ba5d865400a (patch) | |
tree | 8ad5d283cba3570b5916cfe81ac388116faed881 /compiler | |
parent | 14f86b3965bfe096b5fed81caa0cc1570f7e7fdf (diff) | |
download | Nim-732f7752a954bb33a92e839304006ba5d865400a.tar.gz |
remove nir; succeeded by nif (#23809)
ref https://github.com/nim-lang/nif
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/commands.nim | 2 | ||||
-rw-r--r-- | compiler/extccomp.nim | 2 | ||||
-rw-r--r-- | compiler/ic/ic.nim | 2 | ||||
-rw-r--r-- | compiler/ic/iclineinfos.nim (renamed from compiler/nir/nirlineinfos.nim) | 2 | ||||
-rw-r--r-- | compiler/ic/navigator.nim | 2 | ||||
-rw-r--r-- | compiler/ic/packed_ast.nim | 2 | ||||
-rw-r--r-- | compiler/main.nim | 39 | ||||
-rw-r--r-- | compiler/modulegraphs.nim | 2 | ||||
-rw-r--r-- | compiler/nim.nim | 3 | ||||
-rw-r--r-- | compiler/nir/ast2ir.nim | 2638 | ||||
-rw-r--r-- | compiler/nir/cir.nim | 983 | ||||
-rw-r--r-- | compiler/nir/nir.nim | 105 | ||||
-rw-r--r-- | compiler/nir/nirc.nim | 52 | ||||
-rw-r--r-- | compiler/nir/nirfiles.nim | 83 | ||||
-rw-r--r-- | compiler/nir/nirinsts.nim | 582 | ||||
-rw-r--r-- | compiler/nir/nirslots.nim | 104 | ||||
-rw-r--r-- | compiler/nir/nirtypes.nim | 475 | ||||
-rw-r--r-- | compiler/nir/nirvm.nim | 1175 | ||||
-rw-r--r-- | compiler/nir/stringcases.nim | 200 | ||||
-rw-r--r-- | compiler/nir/types2ir.nim | 525 | ||||
-rw-r--r-- | compiler/options.nim | 4 | ||||
-rw-r--r-- | compiler/pipelines.nim | 13 |
22 files changed, 11 insertions, 6984 deletions
diff --git a/compiler/commands.nim b/compiler/commands.nim index 176b73044..5b261b3e8 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -462,7 +462,6 @@ proc handleCmdInput*(conf: ConfigRef) = proc parseCommand*(command: string): Command = case command.normalize of "c", "cc", "compile", "compiletoc": cmdCompileToC - of "nir": cmdCompileToNir of "cpp", "compiletocpp": cmdCompileToCpp of "objc", "compiletooc": cmdCompileToOC of "js", "compiletojs": cmdCompileToJS @@ -500,7 +499,6 @@ proc setCmd*(conf: ConfigRef, cmd: Command) = of cmdCompileToCpp: conf.backend = backendCpp of cmdCompileToOC: conf.backend = backendObjc of cmdCompileToJS: conf.backend = backendJs - of cmdCompileToNir: conf.backend = backendNir else: discard proc setCommandEarly*(conf: ConfigRef, command: string) = diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index dc9b43514..a8b6489b8 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -337,7 +337,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string = var fullSuffix = suffix case conf.backend of backendCpp, backendJs, backendObjc: fullSuffix = "." & $conf.backend & suffix - of backendC, backendNir: discard + of backendC: discard of backendInvalid: # during parsing of cfg files; we don't know the backend yet, no point in # guessing wrong thing diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 22b886ff4..f59a53a16 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -16,7 +16,7 @@ from std/os import removeFile, isAbsolute import ../../dist/checksums/src/checksums/sha1 -import ".." / nir / nirlineinfos +import iclineinfos when defined(nimPreviewSlimSystem): import std/[syncio, assertions, formatfloat] diff --git a/compiler/nir/nirlineinfos.nim b/compiler/ic/iclineinfos.nim index f11ef7c42..74a7d971b 100644 --- a/compiler/nir/nirlineinfos.nim +++ b/compiler/ic/iclineinfos.nim @@ -1,7 +1,7 @@ # # # The Nim Compiler -# (c) Copyright 2023 Andreas Rumpf +# (c) Copyright 2024 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim index ca2f981a1..39037b94f 100644 --- a/compiler/ic/navigator.nim +++ b/compiler/ic/navigator.nim @@ -20,7 +20,7 @@ when defined(nimPreviewSlimSystem): import std/assertions import ".." / [ast, modulegraphs, msgs, options] -import ".." / nir / nirlineinfos +import iclineinfos import packed_ast, bitabs, ic type diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index 392f6b325..a39bb7adf 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -16,7 +16,7 @@ import std/[hashes, tables, strtabs] import bitabs, rodfiles import ".." / [ast, options] -import ".." / nir / nirlineinfos +import iclineinfos when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/main.nim b/compiler/main.nim index 0b74162a9..4c52317cf 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -22,8 +22,6 @@ import modules, modulegraphs, lineinfos, pathutils, vmprofiler -# ensure NIR compiles: -import nir / nir when defined(nimPreviewSlimSystem): import std/[syncio, assertions] @@ -48,9 +46,6 @@ proc writeDepsFile(g: ModuleGraph) = f.writeLine(toFullPath(g.config, k)) f.close() -proc writeNinjaFile(g: ModuleGraph) = - discard "to implement" - proc writeCMakeDepsFile(conf: ConfigRef) = ## write a list of C files for build systems like CMake. ## only updated when the C file list changes. @@ -161,26 +156,6 @@ proc commandCompileToC(graph: ModuleGraph) = if optGenCDeps in graph.config.globalOptions: writeCMakeDepsFile(conf) -proc commandCompileToNir(graph: ModuleGraph) = - let conf = graph.config - extccomp.initVars(conf) - if conf.symbolFiles == disabledSf: - if {optRun, optForceFullMake} * conf.globalOptions == {optRun}: - if not changeDetectedViaJsonBuildInstructions(conf, conf.jsonBuildInstructionsFile): - # nothing changed - graph.config.notes = graph.config.mainPackageNotes - return - - if not extccomp.ccHasSaneOverflow(conf): - conf.symbols.defineSymbol("nimEmulateOverflowChecks") - - if conf.symbolFiles == disabledSf: - setPipeLinePass(graph, NirPass) - else: - setPipeLinePass(graph, SemPass) - compilePipelineProject(graph) - writeNinjaFile(graph) - proc commandJsonScript(graph: ModuleGraph) = extccomp.runJsonBuildInstructions(graph.config, graph.config.jsonBuildInstructionsFile) @@ -197,16 +172,13 @@ proc commandCompileToJS(graph: ModuleGraph) = if optGenScript in conf.globalOptions: writeDepsFile(graph) -proc commandInteractive(graph: ModuleGraph; useNir: bool) = +proc commandInteractive(graph: ModuleGraph) = graph.config.setErrorMaxHighMaybe initDefines(graph.config.symbols) - if useNir: - defineSymbol(graph.config.symbols, "noSignalHandler") - else: - defineSymbol(graph.config.symbols, "nimscript") + defineSymbol(graph.config.symbols, "nimscript") # note: seems redundant with -d:nimHasLibFFI when hasFFI: defineSymbol(graph.config.symbols, "nimffi") - setPipeLinePass(graph, if useNir: NirReplPass else: InterpreterPass) + setPipeLinePass(graph, InterpreterPass) compilePipelineSystemModule(graph) if graph.config.commandArgs.len > 0: discard graph.compilePipelineModule(fileInfoIdx(graph.config, graph.config.projectFull), {}) @@ -293,8 +265,6 @@ proc mainCommand*(graph: ModuleGraph) = # and it has added this define implictly, so we must undo that here. # A better solution might be to fix system.nim undefSymbol(conf.symbols, "useNimRtl") - of backendNir: - if conf.exc == excNone: conf.exc = excGoto of backendInvalid: raiseAssert "unreachable" proc compileToBackend() = @@ -305,7 +275,6 @@ proc mainCommand*(graph: ModuleGraph) = of backendCpp: commandCompileToC(graph) of backendObjc: commandCompileToC(graph) of backendJs: commandCompileToJS(graph) - of backendNir: commandCompileToNir(graph) of backendInvalid: raiseAssert "unreachable" template docLikeCmd(body) = @@ -444,7 +413,7 @@ proc mainCommand*(graph: ModuleGraph) = wantMainModule(conf) commandView(graph) #msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!") - of cmdInteractive: commandInteractive(graph, isDefined(conf, "nir")) + of cmdInteractive: commandInteractive(graph) of cmdNimscript: if conf.projectIsCmd or conf.projectIsStdin: discard elif not fileExists(conf.projectFull): diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 75f3a3c70..a2b69a7e8 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -62,8 +62,6 @@ type CgenPass EvalPass InterpreterPass - NirPass - NirReplPass GenDependPass Docgen2TexPass Docgen2JsonPass diff --git a/compiler/nim.nim b/compiler/nim.nim index 3473ea443..1d499a50d 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -116,8 +116,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = conf.backend = backendC if conf.selectedGC == gcUnselected: - if conf.backend in {backendC, backendCpp, backendObjc, backendNir} or - (conf.cmd == cmdInteractive and isDefined(conf, "nir")) or + if conf.backend in {backendC, backendCpp, backendObjc} or (conf.cmd in cmdDocLike and conf.backend != backendJs): initOrcDefines(conf) diff --git a/compiler/nir/ast2ir.nim b/compiler/nir/ast2ir.nim deleted file mode 100644 index 11bd711f9..000000000 --- a/compiler/nir/ast2ir.nim +++ /dev/null @@ -1,2638 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2023 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -import std / [assertions, tables, sets] -import ".." / [ast, astalgo, types, options, lineinfos, msgs, magicsys, - modulegraphs, renderer, transf, bitsets, trees, nimsets, - expanddefaults] -from ".." / lowerings import lowerSwap, lowerTupleUnpacking -from ".." / pathutils import customPath -import .. / ic / bitabs - -import nirtypes, nirinsts, nirlineinfos, nirslots, types2ir, nirfiles - -when defined(nimCompilerStacktraceHints): - import std/stackframes - -type - ModuleCon* = ref object - nirm*: ref NirModule - types: TypesCon - module*: PSym - graph*: ModuleGraph - nativeIntId, nativeUIntId: TypeId - strPayloadId: (TypeId, TypeId) - idgen: IdGenerator - processedProcs, pendingProcsAsSet: HashSet[ItemId] - pendingProcs: seq[PSym] # procs we still need to generate code for - pendingVarsAsSet: HashSet[ItemId] - pendingVars: seq[PSym] - noModularity*: bool - inProc: int - toSymId: Table[ItemId, SymId] - symIdCounter: int32 - - ProcCon* = object - config*: ConfigRef - lit: Literals - lastFileKey: FileIndex - lastFileVal: LitId - labelGen: int - exitLabel: LabelId - #code*: Tree - blocks: seq[(PSym, LabelId)] - sm: SlotManager - idgen: IdGenerator - m: ModuleCon - prc: PSym - options: TOptions - -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 - result.nativeUIntId = UInt16Id - of 4: - result.nativeIntId = Int32Id - result.nativeUIntId = UInt16Id - else: - result.nativeIntId = Int64Id - result.nativeUIntId = UInt16Id - result.strPayloadId = strPayloadPtrType(result.types, result.nirm.types) - nirm.namespace = nirm.lit.strings.getOrIncl(customPath(toFullPath(config, module.info))) - nirm.intbits = uint32(config.target.intSize * 8) - -proc initProcCon*(m: ModuleCon; prc: PSym; config: ConfigRef): ProcCon = - result = ProcCon(m: m, sm: initSlotManager({}), prc: prc, config: config, - lit: m.nirm.lit, idgen: m.idgen, - options: if prc != nil: prc.options - else: config.options) - result.exitLabel = newLabel(result.labelGen) - -proc toLineInfo(c: var ProcCon; i: TLineInfo): PackedLineInfo = - var val: LitId - if c.lastFileKey == i.fileIndex: - val = c.lastFileVal - else: - val = c.lit.strings.getOrIncl(toFullPath(c.config, i.fileIndex)) - # remember the entry: - c.lastFileKey = i.fileIndex - c.lastFileVal = val - result = pack(c.m.nirm.man, val, int32 i.line, int32 i.col) - -proc bestEffort(c: ProcCon): TLineInfo = - if c.prc != nil: - c.prc.info - else: - c.m.module.info - -proc popBlock(c: var ProcCon; oldLen: int) = - c.blocks.setLen(oldLen) - -template withBlock(labl: PSym; info: PackedLineInfo; asmLabl: LabelId; body: untyped) {.dirty.} = - var oldLen {.gensym.} = c.blocks.len - c.blocks.add (labl, asmLabl) - body - popBlock(c, oldLen) - -type - GenFlag = enum - gfAddrOf # load the address of the expression - gfToOutParam # the expression is passed to an `out` parameter - GenFlags = set[GenFlag] - -proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) - -proc genScope(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = - openScope c.sm - gen c, n, d, flags - closeScope c.sm - -proc freeTemp(c: var ProcCon; tmp: Value) = - let s = extractTemp(tmp) - if s != SymId(-1): - freeTemp(c.sm, s) - -proc freeTemps(c: var ProcCon; tmps: openArray[Value]) = - for t in tmps: freeTemp(c, t) - -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, 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, t) - c.code.addSummon info, tmp, t - result = localToValue(info, tmp) - -proc gen(c: var ProcCon; n: PNode; flags: GenFlags = {}) = - var tmp = default(Value) - gen(c, n, tmp, flags) - freeTemp c, tmp - -proc genScope(c: var ProcCon; n: PNode; flags: GenFlags = {}) = - openScope c.sm - gen c, n, flags - closeScope c.sm - -proc genx(c: var ProcCon; n: PNode; flags: GenFlags = {}): Value = - result = default(Value) - gen(c, n, result, flags) - assert Tree(result).len > 0, $n - -proc clearDest(c: var ProcCon; n: PNode; d: var Value) {.inline.} = - when false: - if n.typ.isNil or n.typ.kind == tyVoid: - let s = extractTemp(d) - if s != SymId(-1): - freeLoc(c.sm, s) - -proc isNotOpr(n: PNode): bool = - n.kind in nkCallKinds and n[0].kind == nkSym and n[0].sym.magic == mNot - -proc jmpBack(c: var ProcCon; n: PNode; lab: LabelId) = - c.code.gotoLabel toLineInfo(c, n.info), GotoLoop, lab - -type - JmpKind = enum opcFJmp, opcTJmp - -proc xjmp(c: var ProcCon; n: PNode; jk: JmpKind; v: Value): LabelId = - result = newLabel(c.labelGen) - let info = toLineInfo(c, n.info) - buildTyped c.code, info, Select, Bool8Id: - c.code.copyTree Tree(v) - build c.code, info, SelectPair: - build c.code, info, SelectValue: - c.code.boolVal(c.lit.numbers, info, jk == opcTJmp) - c.code.gotoLabel info, Goto, result - -proc patch(c: var ProcCon; n: PNode; L: LabelId) = - addLabel c.code, toLineInfo(c, n.info), Label, L - -proc genWhile(c: var ProcCon; n: PNode) = - # lab1: - # cond, tmp - # fjmp tmp, lab2 - # body - # jmp lab1 - # lab2: - let info = toLineInfo(c, n.info) - let lab1 = c.code.addNewLabel(c.labelGen, info, LoopLabel) - withBlock(nil, info, lab1): - if isTrue(n[0]): - c.gen(n[1]) - c.jmpBack(n, lab1) - elif isNotOpr(n[0]): - var tmp = c.genx(n[0][1]) - let lab2 = c.xjmp(n, opcTJmp, tmp) - c.freeTemp(tmp) - c.gen(n[1]) - c.jmpBack(n, lab1) - c.patch(n, lab2) - else: - var tmp = c.genx(n[0]) - let lab2 = c.xjmp(n, opcFJmp, tmp) - c.freeTemp(tmp) - c.gen(n[1]) - c.jmpBack(n, lab1) - c.patch(n, lab2) - -proc genBlock(c: var ProcCon; n: PNode; d: var Value) = - openScope c.sm - let info = toLineInfo(c, n.info) - let lab1 = newLabel(c.labelGen) - - withBlock(n[0].sym, info, lab1): - c.gen(n[1], d) - - c.code.addLabel(info, Label, lab1) - closeScope c.sm - c.clearDest(n, d) - -proc jumpTo(c: var ProcCon; n: PNode; L: LabelId) = - c.code.addLabel(toLineInfo(c, n.info), Goto, L) - -proc genBreak(c: var ProcCon; n: PNode) = - if n[0].kind == nkSym: - for i in countdown(c.blocks.len-1, 0): - if c.blocks[i][0] == n[0].sym: - c.jumpTo n, c.blocks[i][1] - return - localError(c.config, n.info, "NIR problem: cannot find 'break' target") - else: - c.jumpTo n, c.blocks[c.blocks.high][1] - -proc genIf(c: var ProcCon; n: PNode; d: var Value) = - # if (!expr1) goto lab1; - # thenPart - # goto LEnd - # lab1: - # if (!expr2) goto lab2; - # thenPart2 - # goto LEnd - # lab2: - # elsePart - # Lend: - if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n) - var ending = newLabel(c.labelGen) - for i in 0..<n.len: - var it = n[i] - if it.len == 2: - let info = toLineInfo(c, it[0].info) - var elsePos: LabelId - if isNotOpr(it[0]): - let tmp = c.genx(it[0][1]) - elsePos = c.xjmp(it[0][1], opcTJmp, tmp) # if true - c.freeTemp tmp - else: - let tmp = c.genx(it[0]) - elsePos = c.xjmp(it[0], opcFJmp, tmp) # if false - c.freeTemp tmp - c.clearDest(n, d) - if isEmptyType(it[1].typ): # maybe noreturn call, don't touch `d` - c.genScope(it[1]) - else: - c.genScope(it[1], d) # then part - if i < n.len-1: - c.jumpTo it[1], ending - c.patch(it, elsePos) - else: - c.clearDest(n, d) - if isEmptyType(it[0].typ): # maybe noreturn call, don't touch `d` - c.genScope(it[0]) - else: - c.genScope(it[0], d) - c.patch(n, ending) - c.clearDest(n, d) - -proc tempToDest(c: var ProcCon; n: PNode; d: var Value; tmp: Value) = - if isEmpty(d): - d = tmp - else: - let info = toLineInfo(c, n.info) - buildTyped c.code, info, Asgn, typeToIr(c.m, n.typ): - c.code.copyTree d - c.code.copyTree tmp - freeTemp(c, tmp) - -proc genAndOr(c: var ProcCon; n: PNode; opc: JmpKind; d: var Value) = - # asgn d, a - # tjmp|fjmp lab1 - # asgn d, b - # lab1: - var tmp = getTemp(c, n) - c.gen(n[1], tmp) - let lab1 = c.xjmp(n, opc, tmp) - c.gen(n[2], tmp) - c.patch(n, lab1) - tempToDest c, n, d, tmp - -proc unused(c: var ProcCon; n: PNode; x: Value) {.inline.} = - if hasValue(x): - #debug(n) - localError(c.config, n.info, "not unused") - -proc caseValue(c: var ProcCon; n: PNode) = - let info = toLineInfo(c, n.info) - build c.code, info, SelectValue: - let x = genx(c, n) - c.code.copyTree x - freeTemp(c, x) - -proc caseRange(c: var ProcCon; n: PNode) = - let info = toLineInfo(c, n.info) - build c.code, info, SelectRange: - let x = genx(c, n[0]) - let y = genx(c, n[1]) - c.code.copyTree x - c.code.copyTree y - freeTemp(c, y) - freeTemp(c, x) - -proc addUseCodegenProc(c: var ProcCon; dest: var Tree; name: string; info: PackedLineInfo) = - let cp = getCompilerProc(c.m.graph, name) - let theProc = c.genx newSymNode(cp) - copyTree c.code, theProc - -template buildCond(useNegation: bool; cond: typed; body: untyped) = - let lab = newLabel(c.labelGen) - buildTyped c.code, info, Select, Bool8Id: - c.code.copyTree cond - build c.code, info, SelectPair: - build c.code, info, SelectValue: - c.code.boolVal(c.lit.numbers, info, useNegation) - c.code.gotoLabel info, Goto, lab - - body - c.code.addLabel info, Label, lab - -template buildIf(cond: typed; body: untyped) = - buildCond false, cond, body - -template buildIfNot(cond: typed; body: untyped) = - buildCond true, cond, body - -template buildIfThenElse(cond: typed; then, otherwise: untyped) = - let lelse = newLabel(c.labelGen) - let lend = newLabel(c.labelGen) - buildTyped c.code, info, Select, Bool8Id: - c.code.copyTree cond - build c.code, info, SelectPair: - build c.code, info, SelectValue: - c.code.boolVal(c.lit.numbers, info, false) - c.code.gotoLabel info, Goto, lelse - - then() - c.code.gotoLabel info, Goto, lend - c.code.addLabel info, Label, lelse - otherwise() - c.code.addLabel info, Label, lend - -include stringcases - -proc genCase(c: var ProcCon; n: PNode; d: var Value) = - if not isEmptyType(n.typ): - if isEmpty(d): d = getTemp(c, n) - else: - unused(c, n, d) - - if n[0].typ.skipTypes(abstractInst).kind == tyString: - genStringCase(c, n, d) - return - - var sections = newSeqOfCap[LabelId](n.len-1) - let ending = newLabel(c.labelGen) - let info = toLineInfo(c, n.info) - let tmp = c.genx(n[0]) - buildTyped c.code, info, Select, typeToIr(c.m, n[0].typ): - c.code.copyTree tmp - for i in 1..<n.len: - let section = newLabel(c.labelGen) - sections.add section - let it = n[i] - let itinfo = toLineInfo(c, it.info) - build c.code, itinfo, SelectPair: - build c.code, itinfo, SelectList: - for j in 0..<it.len-1: - if it[j].kind == nkRange: - caseRange c, it[j] - else: - caseValue c, it[j] - c.code.addLabel itinfo, Goto, section - c.freeTemp tmp - for i in 1..<n.len: - let it = n[i] - let itinfo = toLineInfo(c, it.info) - c.code.addLabel itinfo, Label, sections[i-1] - c.gen it.lastSon - if i != n.len-1: - c.code.addLabel itinfo, Goto, ending - c.code.addLabel info, Label, ending - -proc rawCall(c: var ProcCon; info: PackedLineInfo; opc: Opcode; t: TypeId; args: var openArray[Value]) = - buildTyped c.code, info, opc, t: - if opc in {CheckedCall, CheckedIndirectCall}: - c.code.addLabel info, CheckedGoto, c.exitLabel - for a in mitems(args): - c.code.copyTree a - freeTemp c, a - -proc canRaiseDisp(c: ProcCon; n: PNode): bool = - # we assume things like sysFatal cannot raise themselves - if n.kind == nkSym and {sfNeverRaises, sfImportc, sfCompilerProc} * n.sym.flags != {}: - result = false - elif optPanics in c.config.globalOptions or - (n.kind == nkSym and sfSystemModule in getModule(n.sym).flags and - sfSystemRaisesDefect notin n.sym.flags): - # we know we can be strict: - result = canRaise(n) - else: - # we have to be *very* conservative: - result = canRaiseConservative(n) - -proc genCall(c: var ProcCon; n: PNode; d: var Value) = - let canRaise = canRaiseDisp(c, n[0]) - - let opc = if n[0].kind == nkSym and n[0].sym.kind in routineKinds: - (if canRaise: CheckedCall else: Call) - else: - (if canRaise: CheckedIndirectCall else: IndirectCall) - let info = toLineInfo(c, n.info) - - # In the IR we cannot nest calls. Thus we use two passes: - var args: seq[Value] = @[] - var t = n[0].typ - if t != nil: t = t.skipTypes(abstractInst) - args.add genx(c, n[0]) - for i in 1..<n.len: - if t != nil and i < t.len: - if isCompileTimeOnly(t[i]): discard - elif isOutParam(t[i]): args.add genx(c, n[i], {gfToOutParam}) - else: args.add genx(c, n[i]) - else: - args.add genx(c, n[i]) - - 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)`. - buildTyped c.code, info, Asgn, tb: - c.code.copyTree d - rawCall c, info, opc, tb, args - else: - rawCall c, info, opc, tb, args - freeTemps c, args - -proc genRaise(c: var ProcCon; n: PNode) = - let info = toLineInfo(c, n.info) - let tb = typeToIr(c.m, n[0].typ) - - let d = genx(c, n[0]) - buildTyped c.code, info, SetExc, tb: - c.code.copyTree d - c.freeTemp(d) - c.code.addLabel info, Goto, c.exitLabel - -proc genReturn(c: var ProcCon; n: PNode) = - if n[0].kind != nkEmpty: - gen(c, n[0]) - # XXX Block leave actions? - let info = toLineInfo(c, n.info) - c.code.addLabel info, Goto, c.exitLabel - -proc genTry(c: var ProcCon; n: PNode; d: var Value) = - if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n) - var endings: seq[LabelId] = @[] - let ehPos = newLabel(c.labelGen) - let oldExitLab = c.exitLabel - c.exitLabel = ehPos - if isEmptyType(n[0].typ): # maybe noreturn call, don't touch `d` - c.gen(n[0]) - else: - c.gen(n[0], d) - c.clearDest(n, d) - - # Add a jump past the exception handling code - let jumpToFinally = newLabel(c.labelGen) - c.jumpTo n, jumpToFinally - # This signals where the body ends and where the exception handling begins - c.patch(n, ehPos) - c.exitLabel = oldExitLab - for i in 1..<n.len: - let it = n[i] - if it.kind != nkFinally: - # first opcExcept contains the end label of the 'except' block: - let endExcept = newLabel(c.labelGen) - for j in 0..<it.len - 1: - assert(it[j].kind == nkType) - 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, typ) - if it.len == 1: - let itinfo = toLineInfo(c, it.info) - build c.code, itinfo, TestExc: - c.code.addTyped itinfo, VoidId - let body = it.lastSon - if isEmptyType(body.typ): # maybe noreturn call, don't touch `d` - c.gen(body) - else: - c.gen(body, d) - c.clearDest(n, d) - if i < n.len: - endings.add newLabel(c.labelGen) - c.patch(it, endExcept) - let fin = lastSon(n) - # we always generate an 'opcFinally' as that pops the safepoint - # from the stack if no exception is raised in the body. - c.patch(fin, jumpToFinally) - #c.gABx(fin, opcFinally, 0, 0) - for endPos in endings: c.patch(n, endPos) - if fin.kind == nkFinally: - c.gen(fin[0]) - c.clearDest(n, d) - #c.gABx(fin, opcFinallyEnd, 0, 0) - -template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar -proc isGlobal(n: PNode): bool = n.kind == nkSym and isGlobal(n.sym) - -proc genField(c: var ProcCon; n: PNode; d: var Value) = - var pos: int - if n.kind != nkSym or n.sym.kind != skField: - localError(c.config, n.info, "no field symbol") - pos = 0 - else: - pos = n.sym.position - d.addImmediateVal toLineInfo(c, n.info), pos - -proc genIndex(c: var ProcCon; n: PNode; arr: PType; d: var Value) = - let info = toLineInfo(c, n.info) - if arr.skipTypes(abstractInst).kind == tyArray and - (let offset = firstOrd(c.config, arr); offset != Zero): - let x = c.genx(n) - buildTyped d, info, Sub, c.m.nativeIntId: - copyTree d.Tree, x - d.addImmediateVal toLineInfo(c, n.info), toInt(offset) - else: - c.gen(n, d) - if optBoundsCheck in c.options: - let idx = move d - build d, info, CheckedIndex: - d.Tree.addLabel info, CheckedGoto, c.exitLabel - copyTree d.Tree, idx - let x = toInt64 lengthOrd(c.config, arr) - d.addIntVal c.lit.numbers, info, c.m.nativeIntId, x - -proc rawGenNew(c: var ProcCon; d: Value; refType: PType; ninfo: TLineInfo; needsInit: bool) = - assert refType.kind == tyRef - let baseType = refType.elementType - - let info = toLineInfo(c, ninfo) - let codegenProc = magicsys.getCompilerProc(c.m.graph, - if needsInit: "nimNewObj" else: "nimNewObjUninit") - let refTypeIr = typeToIr(c.m, refType) - buildTyped c.code, info, Asgn, refTypeIr: - copyTree c.code, d - buildTyped c.code, info, Cast, refTypeIr: - buildTyped c.code, info, Call, VoidPtrId: - 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) - let baseType = seqtype.elementType - var a = c.genx(n[1]) - if isEmpty(d): d = getTemp(c, n) - # $1.len = 0 - buildTyped c.code, info, Asgn, 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, c.m.nirm.types, seqtype)[0] - buildTyped c.code, info, Asgn, payloadPtr: - # $1.p - 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)) - buildTyped c.code, info, Cast, payloadPtr: - buildTyped c.code, info, Call, VoidPtrId: - let codegenProc = magicsys.getCompilerProc(c.m.graph, "newSeqPayloadUninit") - let theProc = c.genx newSymNode(codegenProc, n.info) - copyTree c.code, theProc - copyTree c.code, a - c.code.addImmediateVal info, int(getSize(c.config, baseType)) - c.code.addImmediateVal info, int(getAlign(c.config, baseType)) - freeTemp c, a - -proc genNewSeqPayload(c: var ProcCon; info: PackedLineInfo; d, b: Value; seqtype: PType) = - let baseType = seqtype.elementType - # $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3)) - 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, 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, typeToIr(c.m, seqtype): - copyTree c.code, d - c.code.addImmediateVal info, 1 - # ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3)) - buildTyped c.code, info, Cast, payloadPtr: - buildTyped c.code, info, Call, VoidPtrId: - let codegenProc = magicsys.getCompilerProc(c.m.graph, "newSeqPayload") - let theProc = c.genx newSymNode(codegenProc) - copyTree c.code, theProc - copyTree c.code, b - c.code.addImmediateVal info, int(getSize(c.config, baseType)) - c.code.addImmediateVal info, int(getAlign(c.config, baseType)) - -proc genNewSeq(c: var ProcCon; n: PNode) = - let info = toLineInfo(c, n.info) - let seqtype = skipTypes(n[1].typ, abstractVarRange) - var d = c.genx(n[1]) - var b = c.genx(n[2]) - - genNewSeqPayload(c, info, d, b, seqtype) - - freeTemp c, b - freeTemp c, d - -template intoDest*(d: var Value; info: PackedLineInfo; typ: TypeId; body: untyped) = - if typ == VoidId: - body(c.code) - elif isEmpty(d): - body(Tree(d)) - else: - buildTyped c.code, info, Asgn, typ: - copyTree c.code, d - body(c.code) - -template valueIntoDest(c: var ProcCon; info: PackedLineInfo; d: var Value; typ: PType; body: untyped) = - if isEmpty(d): - body(Tree d) - else: - buildTyped c.code, info, Asgn, typeToIr(c.m, typ): - copyTree c.code, d - body(c.code) - -template constrIntoDest(c: var ProcCon; info: PackedLineInfo; d: var Value; typ: PType; body: untyped) = - var tmp = default(Value) - body(Tree tmp) - if isEmpty(d): - d = tmp - else: - buildTyped c.code, info, Asgn, typeToIr(c.m, typ): - copyTree c.code, d - copyTree c.code, tmp - -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, n.typ) - template body(target) = - buildTyped target, info, opc, t: - if opc in {CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedMod}: - target.addLabel info, CheckedGoto, c.exitLabel - copyTree target, tmp - copyTree target, tmp2 - intoDest d, info, t, body - c.freeTemp(tmp) - c.freeTemp(tmp2) - -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, n[1].typ) - template body(target) = - buildTyped target, info, opc, t: - copyTree target, tmp - copyTree target, tmp2 - intoDest d, info, Bool8Id, body - c.freeTemp(tmp) - c.freeTemp(tmp2) - -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, n.typ) - template body(target) = - buildTyped target, info, opc, t: - copyTree target, tmp - intoDest d, info, t, body - c.freeTemp(tmp) - -proc genIncDec(c: var ProcCon; n: PNode; opc: Opcode) = - let info = toLineInfo(c, n.info) - let t = typeToIr(c.m, skipTypes(n[1].typ, abstractVar)) - - let d = c.genx(n[1]) - let tmp = c.genx(n[2]) - # we produce code like: i = i + 1 - buildTyped c.code, info, Asgn, t: - copyTree c.code, d - buildTyped c.code, info, opc, t: - if opc in {CheckedAdd, CheckedSub}: - c.code.addLabel info, CheckedGoto, c.exitLabel - copyTree c.code, d - copyTree c.code, tmp - c.freeTemp(tmp) - #c.genNarrow(n[1], d) - c.freeTemp(d) - -proc genArrayLen(c: var ProcCon; n: PNode; d: var Value) = - #echo c.m.graph.config $ n.info, " ", n - let info = toLineInfo(c, n.info) - var a = n[1] - #if a.kind == nkHiddenAddr: a = a[0] - var typ = skipTypes(a.typ, abstractVar + tyUserTypeClasses) - case typ.kind - of tyOpenArray, tyVarargs: - let xa = c.genx(a) - template body(target) = - 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 - - of tyCstring: - let xa = c.genx(a) - if isEmpty(d): d = getTemp(c, n) - buildTyped c.code, info, Call, c.m.nativeIntId: - let codegenProc = magicsys.getCompilerProc(c.m.graph, "nimCStrLen") - assert codegenProc != nil - let theProc = c.genx newSymNode(codegenProc, n.info) - copyTree c.code, theProc - copyTree c.code, xa - - of tyString, tySequence: - let xa = c.genx(a) - - if typ.kind == tySequence: - # we go through a temporary here because people write bullshit code. - if isEmpty(d): d = getTemp(c, n) - - template body(target) = - 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 - - of tyArray: - template body(target) = - target.addIntVal(c.lit.numbers, info, c.m.nativeIntId, toInt lengthOrd(c.config, typ)) - intoDest d, info, c.m.nativeIntId, body - else: internalError(c.config, n.info, "genArrayLen()") - -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, n.typ) - template body(target) = - buildTyped target, info, Sub, t: - # Little hack: This works because we know that `0.0` is all 0 bits: - target.addIntVal(c.lit.numbers, info, t, 0) - copyTree target, tmp - intoDest d, info, t, body - c.freeTemp(tmp) - -proc genHigh(c: var ProcCon; n: PNode; d: var Value) = - let info = toLineInfo(c, n.info) - let t = typeToIr(c.m, n.typ) - var x = default(Value) - genArrayLen(c, n, x) - template body(target) = - buildTyped target, info, Sub, t: - copyTree target, x - target.addIntVal(c.lit.numbers, info, t, 1) - intoDest d, info, t, body - c.freeTemp x - -proc genBinaryCp(c: var ProcCon; n: PNode; d: var Value; compilerProc: string) = - let info = toLineInfo(c, n.info) - let xa = c.genx(n[1]) - let xb = c.genx(n[2]) - if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n) - - let t = typeToIr(c.m, n.typ) - template body(target) = - buildTyped target, info, Call, t: - let codegenProc = magicsys.getCompilerProc(c.m.graph, compilerProc) - #assert codegenProc != nil, $n & " " & (c.m.graph.config $ n.info) - let theProc = c.genx newSymNode(codegenProc, n.info) - copyTree target, theProc - copyTree target, xa - copyTree target, xb - - intoDest d, info, t, body - c.freeTemp xb - c.freeTemp xa - -proc genUnaryCp(c: var ProcCon; n: PNode; d: var Value; compilerProc: string; argAt = 1) = - let info = toLineInfo(c, n.info) - let xa = c.genx(n[argAt]) - if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n) - - let t = typeToIr(c.m, n.typ) - template body(target) = - buildTyped target, info, Call, t: - let codegenProc = magicsys.getCompilerProc(c.m.graph, compilerProc) - let theProc = c.genx newSymNode(codegenProc, n.info) - copyTree target, theProc - copyTree target, xa - - intoDest d, info, t, body - c.freeTemp xa - -proc genEnumToStr(c: var ProcCon; n: PNode; d: var Value) = - let t = n[1].typ.skipTypes(abstractInst+{tyRange}) - let toStrProc = getToStringProc(c.m.graph, t) - # XXX need to modify this logic for IC. - var nb = copyTree(n) - nb[0] = newSymNode(toStrProc) - gen(c, nb, d) - -proc genOf(c: var ProcCon; n: PNode; d: var Value) = - genUnaryOp c, n, d, TestOf - -template sizeOfLikeMsg(name): string = - "'" & name & "' requires '.importc' types to be '.completeStruct'" - -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, n[1].typ) - template body(target) = - buildTyped target, info, Eq, t: - copyTree target, tmp - addNilVal target, info, t - intoDest d, info, Bool8Id, body - c.freeTemp(tmp) - -proc fewCmps(conf: ConfigRef; s: PNode): bool = - # this function estimates whether it is better to emit code - # for constructing the set or generating a bunch of comparisons directly - if s.kind != nkCurly: - result = false - elif (getSize(conf, s.typ) <= conf.target.intSize) and (nfAllConst in s.flags): - result = false # it is better to emit the set generation code - elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}: - result = true # better not emit the set if int is basetype! - else: - result = s.len <= 8 # 8 seems to be a good value - -proc genInBitset(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 = 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 - of UInt16Id: 15 - of UInt32Id: 31 - else: 63 - let expansion = if t == UInt64Id: UInt64Id else: c.m.nativeUIntId - # "(($1 &(1U<<((NU)($2)&7U)))!=0)" - or - - # "(($1[(NU)($2)>>3] &(1U<<((NU)($2)&7U)))!=0)" - - template body(target) = - buildTyped target, info, BoolNot, Bool8Id: - buildTyped target, info, Eq, t: - buildTyped target, info, BitAnd, t: - if c.m.nirm.types[setType].kind != ArrayTy: - copyTree target, a - else: - buildTyped target, info, ArrayAt, setType: - copyTree target, a - buildTyped target, info, BitShr, t: - buildTyped target, info, Cast, expansion: - copyTree target, b - addIntVal target, c.lit.numbers, info, expansion, 3 - - buildTyped target, info, BitShl, t: - addIntVal target, c.lit.numbers, info, t, 1 - buildTyped target, info, BitAnd, t: - buildTyped target, info, Cast, expansion: - copyTree target, b - addIntVal target, c.lit.numbers, info, expansion, mask - addIntVal target, c.lit.numbers, info, t, 0 - intoDest d, info, t, body - - c.freeTemp(b) - c.freeTemp(a) - -proc genInSet(c: var ProcCon; n: PNode; d: var Value) = - let g {.cursor.} = c.m.graph - if n[1].kind == nkCurly and fewCmps(g.config, n[1]): - # a set constructor but not a constant set: - # do not emit the set, but generate a bunch of comparisons; and if we do - # so, we skip the unnecessary range check: This is a semantical extension - # that code now relies on. :-/ XXX - let elem = if n[2].kind in {nkChckRange, nkChckRange64}: n[2][0] - else: n[2] - let curly = n[1] - var ex: PNode = nil - for it in curly: - var test: PNode - if it.kind == nkRange: - test = newTree(nkCall, g.operators.opAnd.newSymNode, - newTree(nkCall, g.operators.opLe.newSymNode, it[0], elem), # a <= elem - newTree(nkCall, g.operators.opLe.newSymNode, elem, it[1]) - ) - else: - test = newTree(nkCall, g.operators.opEq.newSymNode, elem, it) - test.typ = getSysType(g, it.info, tyBool) - - if ex == nil: ex = test - else: ex = newTree(nkCall, g.operators.opOr.newSymNode, ex, test) - - if ex == nil: - let info = toLineInfo(c, n.info) - template body(target) = - boolVal target, c.lit.numbers, info, false - intoDest d, info, Bool8Id, body - else: - gen c, ex, d - else: - genInBitset c, n, d - -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, n.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.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.nirm.types, setType): - copyTree c.code, a - c.code.addImmediateVal info, int(getSize(c.config, n[1].typ)) - elif t == UInt64Id: - let codegenProc = magicsys.getCompilerProc(c.m.graph, "countBits64") - let theProc = c.genx newSymNode(codegenProc, n.info) - copyTree c.code, theProc - copyTree c.code, a - else: - let codegenProc = magicsys.getCompilerProc(c.m.graph, "countBits32") - let theProc = c.genx newSymNode(codegenProc, n.info) - copyTree c.code, theProc - buildTyped c.code, info, Cast, UInt32Id: - copyTree c.code, a - freeTemp c, a - -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, n.typ) - - let setType = typeToIr(c.m, n[1].typ) - - if c.m.nirm.types[setType].kind == ArrayTy: - if isEmpty(d): d = getTemp(c, n) - - buildTyped c.code, info, Asgn, t: - copyTree c.code, d - buildTyped c.code, info, Eq, t: - buildTyped c.code, info, Call, t: - 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.nirm.types, setType): - copyTree c.code, a - 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 - - else: - template body(target) = - buildTyped target, info, Eq, setType: - copyTree target, a - copyTree target, b - intoDest d, info, Bool8Id, body - - freeTemp c, b - freeTemp c, a - -proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: int): (SymId, LabelId, LabelId) = - 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 - c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, first - let lab1 = c.code.addNewLabel(c.labelGen, info, LoopLabel) - result = (tmp, lab1, newLabel(c.labelGen)) - - buildTyped c.code, info, Select, Bool8Id: - buildTyped c.code, info, Lt, c.m.nativeIntId: - c.code.addSymUse info, tmp - c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, last - build c.code, info, SelectPair: - build c.code, info, SelectValue: - c.code.boolVal(c.lit.numbers, info, false) - c.code.gotoLabel info, Goto, result[2] - -proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: Value): (SymId, LabelId, LabelId) = - 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 - copyTree c.code, first - let lab1 = c.code.addNewLabel(c.labelGen, info, LoopLabel) - result = (tmp, lab1, newLabel(c.labelGen)) - - buildTyped c.code, info, Select, Bool8Id: - buildTyped c.code, info, Le, c.m.nativeIntId: - c.code.addSymUse info, tmp - copyTree c.code, last - build c.code, info, SelectPair: - build c.code, info, SelectValue: - c.code.boolVal(c.lit.numbers, info, false) - c.code.gotoLabel info, Goto, result[2] - -proc endLoop(c: var ProcCon; info: PackedLineInfo; s: SymId; back, exit: LabelId) = - buildTyped c.code, info, Asgn, c.m.nativeIntId: - c.code.addSymUse info, s - buildTyped c.code, info, Add, c.m.nativeIntId: - c.code.addSymUse info, s - c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1 - c.code.addLabel info, GotoLoop, back - c.code.addLabel info, Label, exit - freeTemp(c.sm, s) - -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, n.typ) - - let setType = typeToIr(c.m, 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, Bool8Id: - copyTree c.code, d - buildTyped c.code, info, Eq, elemType: - buildTyped c.code, info, BitAnd, 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, setType: - copyTree c.code, b - c.code.addSymUse info, idx - c.code.addIntVal c.lit.numbers, info, elemType, 0 - - # if !$3: break - buildTyped c.code, info, Select, Bool8Id: - c.code.copyTree d - build c.code, info, SelectPair: - build c.code, info, SelectValue: - c.code.boolVal(c.lit.numbers, info, false) - c.code.gotoLabel info, Goto, endLabel - - endLoop(c, info, idx, backLabel, endLabel) - else: - # "(($1 & ~ $2)==0)" - template body(target) = - buildTyped target, info, Eq, setType: - buildTyped target, info, BitAnd, setType: - copyTree target, a - buildTyped target, info, BitNot, setType: - copyTree target, b - target.addIntVal c.lit.numbers, info, setType, 0 - - intoDest d, info, Bool8Id, body - - freeTemp c, b - freeTemp c, a - -proc genLtSet(c: var ProcCon; n: PNode; d: var Value) = - localError(c.m.graph.config, n.info, "`<` for sets not implemented") - -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, n.typ) - - let setType = typeToIr(c.m, 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, 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, setType: - copyTree c.code, a - c.code.addSymUse info, idx - if m == mMinusSet: - buildTyped c.code, info, BitNot, elemType: - buildTyped c.code, info, ArrayAt, setType: - copyTree c.code, b - c.code.addSymUse info, idx - else: - buildTyped c.code, info, ArrayAt, setType: - copyTree c.code, b - c.code.addSymUse info, idx - - endLoop(c, info, idx, backLabel, endLabel) - else: - # "(($1 & ~ $2)==0)" - template body(target) = - buildTyped target, info, (if m == mPlusSet: BitOr else: BitAnd), setType: - copyTree target, a - if m == mMinusSet: - buildTyped target, info, BitNot, setType: - copyTree target, b - else: - copyTree target, b - - intoDest d, info, setType, body - - freeTemp c, b - freeTemp c, a - -proc genInclExcl(c: var ProcCon; n: PNode; m: TMagic) = - let info = toLineInfo(c, n.info) - let a = c.genx(n[1]) - let b = c.genx(n[2]) - - let setType = typeToIr(c.m, n[1].typ) - - let t = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ) - let mask = - case t - of UInt8Id: 7 - of UInt16Id: 15 - of UInt32Id: 31 - else: 63 - - buildTyped c.code, info, Asgn, setType: - if c.m.nirm.types[setType].kind == ArrayTy: - if m == mIncl: - # $1[(NU)($2)>>3] |=(1U<<($2&7U)) - 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, 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, BitShl, t: - c.code.addIntVal c.lit.numbers, info, t, 1 - buildTyped c.code, info, BitAnd, t: - copyTree c.code, b - c.code.addIntVal c.lit.numbers, info, t, 7 - else: - # $1[(NU)($2)>>3] &= ~(1U<<($2&7U)) - 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, 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, BitNot, t: - buildTyped c.code, info, BitShl, t: - c.code.addIntVal c.lit.numbers, info, t, 1 - buildTyped c.code, info, BitAnd, t: - copyTree c.code, b - c.code.addIntVal c.lit.numbers, info, t, 7 - - else: - copyTree c.code, a - if m == mIncl: - # $1 |= ((NU8)1)<<(($2) & 7) - buildTyped c.code, info, BitOr, setType: - copyTree c.code, a - buildTyped c.code, info, BitShl, t: - c.code.addIntVal c.lit.numbers, info, t, 1 - buildTyped c.code, info, BitAnd, t: - copyTree c.code, b - c.code.addIntVal c.lit.numbers, info, t, mask - else: - # $1 &= ~(((NU8)1) << (($2) & 7)) - buildTyped c.code, info, BitAnd, setType: - copyTree c.code, a - buildTyped c.code, info, BitNot, t: - buildTyped c.code, info, BitShl, t: - c.code.addIntVal c.lit.numbers, info, t, 1 - buildTyped c.code, info, BitAnd, t: - copyTree c.code, b - c.code.addIntVal c.lit.numbers, info, t, mask - freeTemp c, b - freeTemp c, a - -proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = - # example: { a..b, c, d, e, f..g } - # we have to emit an expression of the form: - # 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, n.typ) - let size = int(getSize(c.config, n.typ)) - let t = bitsetBasetype(c.m.types, c.m.nirm.types, n.typ) - let mask = - case t - of UInt8Id: 7 - of UInt16Id: 15 - of UInt32Id: 31 - else: 63 - - if isEmpty(d): d = getTemp(c, n) - 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 - - for it in n: - if it.kind == nkRange: - let a = genx(c, it[0]) - let b = genx(c, it[1]) - let (idx, backLabel, endLabel) = beginCountLoop(c, info, a, b) - buildTyped c.code, info, Asgn, setType: - copyTree c.code, d - buildTyped c.code, info, BitAnd, setType: - copyTree c.code, d - buildTyped c.code, info, BitNot, t: - buildTyped c.code, info, BitShl, t: - c.code.addIntVal c.lit.numbers, info, t, 1 - buildTyped c.code, info, BitAnd, t: - c.code.addSymUse info, idx - c.code.addIntVal c.lit.numbers, info, t, mask - - endLoop(c, info, idx, backLabel, endLabel) - freeTemp c, b - freeTemp c, a - - else: - let a = genx(c, it) - buildTyped c.code, info, Asgn, setType: - copyTree c.code, d - buildTyped c.code, info, BitAnd, setType: - copyTree c.code, d - buildTyped c.code, info, BitNot, t: - buildTyped c.code, info, BitShl, t: - c.code.addIntVal c.lit.numbers, info, t, 1 - buildTyped c.code, info, BitAnd, t: - copyTree c.code, a - c.code.addIntVal c.lit.numbers, info, t, mask - freeTemp c, a - - else: - # init loop: - let (idx, backLabel, endLabel) = beginCountLoop(c, info, 0, size) - buildTyped c.code, info, Asgn, t: - copyTree c.code, d - c.code.addIntVal c.lit.numbers, info, t, 0 - endLoop(c, info, idx, backLabel, endLabel) - - # incl elements: - for it in n: - if it.kind == nkRange: - let a = genx(c, it[0]) - let b = genx(c, it[1]) - let (idx, backLabel, endLabel) = beginCountLoop(c, info, a, b) - - buildTyped c.code, info, Asgn, 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, 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, BitShl, t: - c.code.addIntVal c.lit.numbers, info, t, 1 - buildTyped c.code, info, BitAnd, t: - c.code.addSymUse info, idx - c.code.addIntVal c.lit.numbers, info, t, 7 - - endLoop(c, info, idx, backLabel, endLabel) - freeTemp c, b - freeTemp c, a - - else: - let a = genx(c, it) - # $1[(NU)($2)>>3] |=(1U<<($2&7U)) - buildTyped c.code, info, Asgn, 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, 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, BitShl, t: - c.code.addIntVal c.lit.numbers, info, t, 1 - buildTyped c.code, info, BitAnd, t: - copyTree c.code, a - c.code.addIntVal c.lit.numbers, info, t, 7 - freeTemp c, a - -proc genSetConstr(c: var ProcCon; n: PNode; d: var Value) = - if isDeepConstExpr(n): - let info = toLineInfo(c, n.info) - let setType = typeToIr(c.m, n.typ) - let size = int(getSize(c.config, n.typ)) - let cs = toBitSet(c.config, n) - - 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, c.m.nirm.types, n.typ) - template body(target) = - buildTyped target, info, ArrayConstr, setType: - for i in 0..high(cs): - target.addIntVal c.lit.numbers, info, t, int64 cs[i] - intoDest d, info, setType, body - else: - genSetConstrDyn c, n, d - -proc genStrConcat(c: var ProcCon; n: PNode; d: var Value) = - let info = toLineInfo(c, n.info) - # <Nim code> - # s = "Hello " & name & ", how do you feel?" & 'z' - # - # <generated code> - # { - # string tmp0; - # ... - # tmp0 = rawNewString(6 + 17 + 1 + s2->len); - # // we cannot generate s = rawNewString(...) here, because - # // ``s`` may be used on the right side of the expression - # appendString(tmp0, strlit_1); - # appendString(tmp0, name); - # appendString(tmp0, strlit_2); - # appendChar(tmp0, 'z'); - # 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 - else: - argsRuntimeLen.add args[^1] - - # generate length computation: - 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(argsRuntimeLen): - buildTyped c.code, info, Asgn, c.m.nativeIntId: - c.code.addSymUse info, tmpLen - buildTyped c.code, info, CheckedAdd, c.m.nativeIntId: - c.code.addLabel info, CheckedGoto, c.exitLabel - c.code.addSymUse info, tmpLen - 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, n.typ) - buildTyped c.code, info, Asgn, t: - copyTree c.code, tmpStr - buildTyped c.code, info, Call, t: - let codegenProc = magicsys.getCompilerProc(c.m.graph, "rawNewString") - #assert codegenProc != nil, $n & " " & (c.m.graph.config $ n.info) - let theProc = c.genx newSymNode(codegenProc, n.info) - copyTree c.code, theProc - c.code.addSymUse info, tmpLen - freeTemp c.sm, tmpLen - - for i in 1 ..< n.len: - let it = n[i] - let isChar = skipTypes(it.typ, abstractVarRange).kind == tyChar - buildTyped c.code, info, Call, VoidId: - let codegenProc = magicsys.getCompilerProc(c.m.graph, - (if isChar: "appendChar" else: "appendString")) - #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.nirm.types, t): - copyTree c.code, tmpStr - copyTree c.code, args[i-1] - freeTemp c, args[i-1] - - if isEmpty(d): - d = tmpStr - else: - # XXX Test that this does not cause memory leaks! - buildTyped c.code, info, Asgn, t: - copyTree c.code, d - copyTree c.code, tmpStr - -proc genDefault(c: var ProcCon; n: PNode; d: var Value) = - let m = expandDefault(n.typ, n.info) - gen c, m, d - -proc genWasMoved(c: var ProcCon; n: PNode) = - let n1 = n[1].skipAddr - # XXX We need a way to replicate this logic or better yet a better - # solution for injectdestructors.nim: - #if c.withinBlockLeaveActions > 0 and notYetAlive(n1): - var d = c.genx(n1) - assert not isEmpty(d) - let m = expandDefault(n1.typ, n1.info) - gen c, m, d - -proc genMove(c: var ProcCon; n: PNode; d: var Value) = - let info = toLineInfo(c, n.info) - let n1 = n[1].skipAddr - var a = c.genx(n1) - if n.len == 4: - # generated by liftdestructors: - let src = c.genx(n[2]) - # if ($1.p == $2.p) goto lab1 - let lab1 = newLabel(c.labelGen) - - let 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, n1t: - copyTree c.code, a - c.code.addImmediateVal info, 1 # (len, p)-pair - buildTyped c.code, info, FieldAt, n1t: - copyTree c.code, src - c.code.addImmediateVal info, 1 # (len, p)-pair - - build c.code, info, SelectPair: - build c.code, info, SelectValue: - c.code.boolVal(c.lit.numbers, info, true) - c.code.gotoLabel info, Goto, lab1 - - gen(c, n[3]) - c.patch n, lab1 - - 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, n1.typ): - copyTree c.code, d - copyTree c.code, a - var op = getAttachedOp(c.m.graph, n.typ, attachedWasMoved) - if op == nil or skipTypes(n1.typ, abstractVar+{tyStatic}).kind in {tyOpenArray, tyVarargs}: - let m = expandDefault(n1.typ, n1.info) - gen c, m, a - else: - var opB = c.genx(newSymNode(op)) - buildTyped c.code, info, Call, typeToIr(c.m, n.typ): - copyTree c.code, opB - 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 = - var result = default(Tree) - buildTyped result, info, FieldAt, t: - copyTree result, x - result.addImmediateVal info, i - result - -template eqNil(x: Tree; t: TypeId): Tree = - var result = default(Tree) - buildTyped result, info, Eq, t: - copyTree result, x - result.addNilVal info, t - result - -template eqZero(x: Tree): Tree = - var result = default(Tree) - buildTyped result, info, Eq, c.m.nativeIntId: - copyTree result, x - result.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0 - result - -template bitOp(x: Tree; opc: Opcode; y: int): Tree = - var result = default(Tree) - buildTyped result, info, opc, c.m.nativeIntId: - copyTree result, x - result.addIntVal c.lit.numbers, info, c.m.nativeIntId, y - result - -proc genDestroySeq(c: var ProcCon; n: PNode; t: PType) = - let info = toLineInfo(c, n.info) - let strLitFlag = 1 shl (c.m.graph.config.target.intSize * 8 - 2) # see also NIM_STRLIT_FLAG - - let x = c.genx(n[1]) - let baseType = t.elementType - - 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, 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) - copyTree c.code, theProc - copyTree c.code, p - c.code.addImmediateVal info, int(getAlign(c.config, baseType)) - - freeTemp c, x - -proc genDestroy(c: var ProcCon; n: PNode) = - let t = n[1].typ.skipTypes(abstractInst) - case t.kind - of tyString: - var unused = default(Value) - genUnaryCp(c, n, unused, "nimDestroyStrV1") - of tySequence: - genDestroySeq(c, n, t) - else: discard "nothing to do" - -type - IndexFor = enum - ForSeq, ForStr, ForOpenArray, ForArray - -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) - let idx = genx(c, n) - build result, info, CheckedIndex: - result.Tree.addLabel info, CheckedGoto, c.exitLabel - copyTree result.Tree, idx - case kind - of ForSeq, ForStr: - 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, typeToIr(c.m, arr): - copyTree result.Tree, a - result.addImmediateVal info, 1 # (p, len)-pair - of ForArray: - let x = toInt64 lengthOrd(c.config, arr) - result.addIntVal c.lit.numbers, info, c.m.nativeIntId, x - freeTemp c, idx - else: - result = genx(c, n) - -proc addSliceFields(c: var ProcCon; target: var Tree; info: PackedLineInfo; - x: Value; n: PNode; arrType: PType) = - let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.elementType)) - case arrType.kind - of tyString, tySequence: - let checkKind = if arrType.kind == tyString: ForStr else: ForSeq - 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, arrType) - let z = genIndexCheck(c, n[3], x, checkKind, arrType) - - buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ): - target.addImmediateVal info, 0 - buildTyped target, info, AddrOf, elemType: - buildTyped target, info, DerefArrayAt, pay[1]: - buildTyped target, info, FieldAt, typeToIr(c.m, arrType): - copyTree target, x - target.addImmediateVal info, 1 # (len, p)-pair - copyTree target, y - - # len: - 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 - of tyArray: - # XXX This evaluates the index check for `y` twice. - # This check is also still insufficient for non-zero based arrays. - 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, n.typ): - target.addImmediateVal info, 0 - buildTyped target, info, AddrOf, elemType: - buildTyped target, info, ArrayAt, typeToIr(c.m, arrType): - copyTree target, x - 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 - 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, DerefArrayAt, 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) - -proc genSlice(c: var ProcCon; n: PNode; d: var Value) = - let info = toLineInfo(c, n.info) - - let x = c.genx(n[1]) - - let arrType = n[1].typ.skipTypes(abstractVar) - - template body(target) = - c.addSliceFields target, info, x, n, arrType - - valueIntoDest c, info, d, arrType, body - freeTemp c, x - -proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) = - case m - of mAnd: c.genAndOr(n, opcFJmp, d) - of mOr: c.genAndOr(n, opcTJmp, d) - of mPred, mSubI: c.genBinaryOp(n, d, if optOverflowCheck in c.options: CheckedSub else: Sub) - of mSucc, mAddI: c.genBinaryOp(n, d, if optOverflowCheck in c.options: CheckedAdd else: Add) - of mInc: - unused(c, n, d) - c.genIncDec(n, if optOverflowCheck in c.options: CheckedAdd else: Add) - of mDec: - unused(c, n, d) - c.genIncDec(n, if optOverflowCheck in c.options: CheckedSub else: Sub) - of mOrd, mChr, mUnown: - c.gen(n[1], d) - of generatedMagics: - genCall(c, n, d) - of mNew, mNewFinalize: - unused(c, n, d) - c.genNew(n, needsInit = true) - of mNewSeq: - unused(c, n, d) - c.genNewSeq(n) - of mNewSeqOfCap: c.genNewSeqOfCap(n, d) - of mNewString, mNewStringOfCap, mExit: c.genCall(n, d) - of mLengthOpenArray, mLengthArray, mLengthSeq, mLengthStr: - genArrayLen(c, n, d) - of mMulI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedMul else: Mul) - of mDivI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedDiv else: Div) - of mModI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedMod else: Mod) - of mAddF64: genBinaryOp(c, n, d, Add) - of mSubF64: genBinaryOp(c, n, d, Sub) - of mMulF64: genBinaryOp(c, n, d, Mul) - of mDivF64: genBinaryOp(c, n, d, Div) - of mShrI: genBinaryOp(c, n, d, BitShr) - of mShlI: genBinaryOp(c, n, d, BitShl) - of mAshrI: genBinaryOp(c, n, d, BitShr) - of mBitandI: genBinaryOp(c, n, d, BitAnd) - of mBitorI: genBinaryOp(c, n, d, BitOr) - of mBitxorI: genBinaryOp(c, n, d, BitXor) - of mAddU: genBinaryOp(c, n, d, Add) - of mSubU: genBinaryOp(c, n, d, Sub) - of mMulU: genBinaryOp(c, n, d, Mul) - of mDivU: genBinaryOp(c, n, d, Div) - of mModU: genBinaryOp(c, n, d, Mod) - of mEqI, mEqB, mEqEnum, mEqCh: - genCmpOp(c, n, d, Eq) - of mLeI, mLeEnum, mLeCh, mLeB: - genCmpOp(c, n, d, Le) - of mLtI, mLtEnum, mLtCh, mLtB: - genCmpOp(c, n, d, Lt) - of mEqF64: genCmpOp(c, n, d, Eq) - of mLeF64: genCmpOp(c, n, d, Le) - of mLtF64: genCmpOp(c, n, d, Lt) - of mLePtr, mLeU: genCmpOp(c, n, d, Le) - of mLtPtr, mLtU: genCmpOp(c, n, d, Lt) - of mEqProc, mEqRef: - genCmpOp(c, n, d, Eq) - of mXor: genBinaryOp(c, n, d, BitXor) - of mNot: genUnaryOp(c, n, d, BoolNot) - of mUnaryMinusI, mUnaryMinusI64: - genUnaryMinus(c, n, d) - #genNarrow(c, n, d) - of mUnaryMinusF64: genUnaryMinus(c, n, d) - of mUnaryPlusI, mUnaryPlusF64: gen(c, n[1], d) - of mBitnotI: - genUnaryOp(c, n, d, BitNot) - when false: - # XXX genNarrowU modified, do not narrow signed types - let t = skipTypes(n.typ, abstractVar-{tyTypeDesc}) - let size = getSize(c.config, t) - if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8): - c.gABC(n, opcNarrowU, d, TRegister(size*8)) - of mStrToStr, mEnsureMove: c.gen n[1], d - of mBoolToStr: genUnaryCp(c, n, d, "nimBoolToStr") - of mCharToStr: genUnaryCp(c, n, d, "nimCharToStr") - of mCStrToStr: genUnaryCp(c, n, d, "cstrToNimstr") - of mEnumToStr: genEnumToStr(c, n, d) - - of mEqStr: genBinaryCp(c, n, d, "eqStrings") - of mEqCString: genCall(c, n, d) - of mLeStr: genBinaryCp(c, n, d, "leStrings") - of mLtStr: genBinaryCp(c, n, d, "ltStrings") - - of mSetLengthStr: - unused(c, n, d) - let nb = copyTree(n) - nb[1] = makeAddr(nb[1], c.m.idgen) - genBinaryCp(c, nb, d, "setLengthStrV2") - - of mSetLengthSeq: - unused(c, n, d) - let nb = copyTree(n) - nb[1] = makeAddr(nb[1], c.m.idgen) - genCall(c, nb, d) - - of mSwap: - unused(c, n, d) - c.gen(lowerSwap(c.m.graph, n, c.m.idgen, - if c.prc == nil: c.m.module else: c.prc), d) - of mParseBiggestFloat: - genCall c, n, d - of mHigh: - c.genHigh n, d - - of mEcho: - unused(c, n, d) - genUnaryCp c, n, d, "echoBinSafe" - - of mAppendStrCh: - unused(c, n, d) - let nb = copyTree(n) - nb[1] = makeAddr(nb[1], c.m.idgen) - genBinaryCp(c, nb, d, "nimAddCharV1") - of mMinI, mMaxI, mAbsI, mDotDot: - c.genCall(n, d) - of mSizeOf: - localError(c.config, n.info, sizeOfLikeMsg("sizeof")) - of mAlignOf: - localError(c.config, n.info, sizeOfLikeMsg("alignof")) - of mOffsetOf: - localError(c.config, n.info, sizeOfLikeMsg("offsetof")) - of mRunnableExamples: - discard "just ignore any call to runnableExamples" - of mOf: genOf(c, n, d) - of mAppendStrStr: - unused(c, n, d) - let nb = copyTree(n) - nb[1] = makeAddr(nb[1], c.m.idgen) - genBinaryCp(c, nb, d, "nimAddStrV1") - of mAppendSeqElem: - unused(c, n, d) - let nb = copyTree(n) - nb[1] = makeAddr(nb[1], c.m.idgen) - genCall(c, nb, d) - of mIsNil: genIsNil(c, n, d) - of mInSet: genInSet(c, n, d) - of mCard: genCard(c, n, d) - of mEqSet: genEqSet(c, n, d) - of mLeSet: genLeSet(c, n, d) - of mLtSet: genLtSet(c, n, d) - of mMulSet: genBinarySet(c, n, d, m) - of mPlusSet: genBinarySet(c, n, d, m) - of mMinusSet: genBinarySet(c, n, d, m) - of mIncl, mExcl: - unused(c, n, d) - genInclExcl(c, n, m) - of mConStrStr: genStrConcat(c, n, d) - of mDefault, mZeroDefault: - genDefault c, n, d - of mMove: genMove(c, n, d) - of mWasMoved: - unused(c, n, d) - genWasMoved(c, n) - of mDestroy: genDestroy(c, n) - #of mAccessEnv: unaryExpr(d, n, d, "$1.ClE_0") - #of mAccessTypeField: genAccessTypeField(c, n, d) - of mSlice: genSlice(c, n, d) - of mTrace: discard "no code to generate" - else: - # mGCref, mGCunref: unused by ORC - globalError(c.config, n.info, "cannot generate code for: " & $m) - -proc canElimAddr(n: PNode; idgen: IdGenerator): PNode = - result = nil - case n[0].kind - of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64: - var m = n[0][0] - if m.kind in {nkDerefExpr, nkHiddenDeref}: - # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x) - result = copyNode(n[0]) - result.add m[0] - if n.typ.skipTypes(abstractVar).kind != tyOpenArray: - result.typ = n.typ - elif n.typ.skipTypes(abstractInst).kind in {tyVar}: - result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen) - of nkHiddenStdConv, nkHiddenSubConv, nkConv: - var m = n[0][1] - if m.kind in {nkDerefExpr, nkHiddenDeref}: - # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x) - result = copyNode(n[0]) - result.add n[0][0] - result.add m[0] - if n.typ.skipTypes(abstractVar).kind != tyOpenArray: - result.typ = n.typ - elif n.typ.skipTypes(abstractInst).kind in {tyVar}: - result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen) - else: - if n[0].kind in {nkDerefExpr, nkHiddenDeref}: - # addr ( deref ( x )) --> x - result = n[0][0] - -proc genAddr(c: var ProcCon; n: PNode; d: var Value, flags: GenFlags) = - if (let m = canElimAddr(n, c.m.idgen); m != nil): - gen(c, m, d, flags) - return - - let info = toLineInfo(c, n.info) - let tmp = c.genx(n[0], flags) - template body(target) = - buildTyped target, info, AddrOf, typeToIr(c.m, n.typ): - copyTree target, tmp - - valueIntoDest c, info, d, n.typ, body - freeTemp c, tmp - -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, n.typ): - copyTree target, tmp - - valueIntoDest c, info, d, n.typ, body - freeTemp c, tmp - -proc addAddrOfFirstElem(c: var ProcCon; target: var Tree; info: PackedLineInfo; tmp: Value; typ: PType) = - let arrType = typ.skipTypes(abstractVar) - let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.elementType)) - case arrType.kind - of tyString: - let t = typeToIr(c.m, typ) - target.addImmediateVal info, 0 - buildTyped target, info, AddrOf, elemType: - buildTyped target, info, DerefArrayAt, 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, 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, typ) - target.addImmediateVal info, 0 - buildTyped target, info, AddrOf, elemType: - buildTyped target, info, DerefArrayAt, 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, 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, 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, arrType)) - else: - raiseAssert "addAddrOfFirstElem: " & typeToString(typ) - -proc genToOpenArrayConv(c: var ProcCon; arg: PNode; d: var Value; flags: GenFlags; destType: PType) = - let info = toLineInfo(c, arg.info) - let tmp = c.genx(arg, flags) - let arrType = destType.skipTypes(abstractVar) - template body(target) = - buildTyped target, info, ObjConstr, typeToIr(c.m, arrType): - c.addAddrOfFirstElem target, info, tmp, arg.typ - - valueIntoDest c, info, d, arrType, body - freeTemp c, tmp - -proc genConv(c: var ProcCon; n, arg: PNode; d: var Value; flags: GenFlags; opc: Opcode) = - let targetType = n.typ.skipTypes({tyDistinct}) - let argType = arg.typ.skipTypes({tyDistinct}) - - if sameBackendType(targetType, argType) or ( - argType.kind == tyProc and targetType.kind == argType.kind): - # don't do anything for lambda lifting conversions: - gen c, arg, d - return - - if opc != Cast and targetType.skipTypes({tyVar, tyLent}).kind in {tyOpenArray, tyVarargs} and - argType.skipTypes({tyVar, tyLent}).kind notin {tyOpenArray, tyVarargs}: - genToOpenArrayConv c, arg, d, flags, n.typ - return - - let info = toLineInfo(c, n.info) - let tmp = c.genx(arg, flags) - template body(target) = - buildTyped target, info, opc, typeToIr(c.m, n.typ): - if opc == CheckedObjConv: - target.addLabel info, CheckedGoto, c.exitLabel - copyTree target, tmp - - valueIntoDest c, info, d, n.typ, body - freeTemp c, tmp - -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, t): - for i in ord(n.kind == nkObjConstr)..<n.len: - let it = n[i] - if it.kind == nkExprColonExpr: - genField(c, it[0], Value target) - let tmp = c.genx(it[1]) - copyTree target, tmp - c.freeTemp(tmp) - else: - let tmp = c.genx(it) - target.addImmediateVal info, i - copyTree target, tmp - c.freeTemp(tmp) - - 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 - - constrIntoDest 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.elementType - - 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) - - let info = toLineInfo(c, n.info) - let seqtype = skipTypes(n.typ, abstractVarRange) - let baseType = seqtype.elementType - - var b = default(Value) - b.addIntVal c.lit.numbers, info, c.m.nativeIntId, n.len - - genNewSeqPayload(c, info, d, b, seqtype) - - for i in 0..<n.len: - var dd = default(Value) - buildTyped dd, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[1]: - buildTyped dd, info, FieldAt, typeToIr(c.m, seqtype): - copyTree Tree(dd), d - dd.addImmediateVal info, 1 # (len, p)-pair - dd.addIntVal c.lit.numbers, info, c.m.nativeIntId, i - gen(c, n[i], dd) - - freeTemp c, d - -proc genArrayConstr(c: var ProcCon; n: PNode, d: var Value) = - let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc}) - if seqType.kind == tySequence: - genSeqConstr(c, n, d) - return - - let info = toLineInfo(c, n.info) - template body(target) = - buildTyped target, info, ArrayConstr, typeToIr(c.m, n.typ): - for i in 0..<n.len: - let tmp = c.genx(n[i]) - copyTree target, tmp - c.freeTemp(tmp) - - constrIntoDest c, info, d, n.typ, body - -proc genAsgn2(c: var ProcCon; a, b: PNode) = - assert a != nil - assert b != nil - var d = c.genx(a) - c.gen b, d - -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 genForeignVar(c: var ProcCon; s: PSym) = - var opc: Opcode - if s.kind == skConst: - opc = SummonConst - elif sfThread in s.flags: - opc = SummonThreadLocal - else: - assert sfGlobal in s.flags - opc = SummonGlobal - let t = typeToIr(c.m, s.typ) - let info = toLineInfo(c, s.info) - build c.code, info, ForeignDecl: - buildTyped c.code, info, opc, t: - build c.code, info, ModuleSymUse: - c.code.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(s)) - c.code.addImmediateVal info, s.itemId.item.int - -proc genVarSection(c: var ProcCon; n: PNode) = - for a in n: - if a.kind == nkCommentStmt: continue - #assert(a[0].kind == nkSym) can happen for transformed vars - if a.kind == nkVarTuple: - c.gen(lowerTupleUnpacking(c.m.graph, a, c.m.idgen, c.prc)) - else: - var vn = a[0] - if vn.kind == nkPragmaExpr: vn = vn[0] - if vn.kind == nkSym: - let s = vn.sym - if s.kind == skConst: - if dontInlineConstant(n, s.astdef): - let symId = toSymId(c, s) - c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(s.name.s) - let val = c.genx(s.astdef) - let info = toLineInfo(c, a.info) - buildTyped c.code, info, SummonConst, typeToIr(c.m, s.typ): - c.code.addSymDef info, symId - c.code.copyTree val - freeTemp c, val - else: - var opc: Opcode - if sfThread in s.flags: - opc = SummonThreadLocal - elif sfGlobal in s.flags: - opc = SummonGlobal - else: - opc = Summon - #assert t.int >= 0, typeToString(s.typ) & (c.config $ n.info) - let symId = toSymId(c, s) - c.code.addSummon toLineInfo(c, a.info), symId, typeToIr(c.m, s.typ), opc - c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(s.name.s) - if a[2].kind != nkEmpty: - genAsgn2(c, vn, a[2]) - else: - if a[2].kind == nkEmpty: - genAsgn2(c, vn, expandDefault(vn.typ, vn.info)) - else: - genAsgn2(c, vn, a[2]) - -proc genAsgn(c: var ProcCon; n: PNode) = - var d = c.genx(n[0]) - c.gen n[1], d - -proc convStrToCStr(c: var ProcCon; n: PNode; d: var Value) = - genUnaryCp(c, n, d, "nimToCStringConv", argAt = 0) - -proc convCStrToStr(c: var ProcCon; n: PNode; d: var Value) = - genUnaryCp(c, n, d, "cstrToNimstr", argAt = 0) - -proc genRdVar(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = - let info = toLineInfo(c, n.info) - let s = n.sym - if fromForeignModule(c, s): - if s.kind in {skVar, skConst, skLet} and not c.m.pendingVarsAsSet.containsOrIncl(s.itemId): - c.m.pendingVars.add s - - template body(target) = - build target, info, ModuleSymUse: - target.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(s)) - target.addImmediateVal info, s.itemId.item.int - - valueIntoDest c, info, d, s.typ, body - else: - template body(target) = - 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 = {}) = - let s = n.sym - case s.kind - of skConst: - if dontInlineConstant(n, s.astdef): - genRdVar(c, n, d, flags) - else: - gen(c, s.astdef, d, flags) - of skVar, skForVar, skTemp, skLet, skResult, skParam: - genRdVar(c, n, d, flags) - of skProc, skFunc, skConverter, skMethod, skIterator: - if not c.m.noModularity: - # anon and generic procs have no AST so we need to remember not to forget - # to emit these: - 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, n.typ), s.position - valueIntoDest c, info, d, n.typ, body - else: - localError(c.config, n.info, "cannot generate code for: " & s.name.s) - -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, n.typ), bits - valueIntoDest c, info, d, n.typ, body - -proc genStringLit(c: var ProcCon; n: PNode; d: var Value) = - let info = toLineInfo(c, n.info) - template body(target) = - target.addStrVal c.lit.strings, info, n.strVal - valueIntoDest c, info, d, n.typ, body - -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, n.typ) - valueIntoDest c, info, d, n.typ, body - -proc genRangeCheck(c: var ProcCon; n: PNode; d: var Value) = - if optRangeCheck in c.options: - let info = toLineInfo(c, n.info) - let tmp = c.genx n[0] - let a = c.genx n[1] - let b = c.genx n[2] - template body(target) = - buildTyped target, info, CheckedRange, typeToIr(c.m, n.typ): - target.addLabel info, CheckedGoto, c.exitLabel - copyTree target, tmp - copyTree target, a - copyTree target, b - valueIntoDest c, info, d, n.typ, body - freeTemp c, tmp - freeTemp c, a - freeTemp c, b - else: - gen c, n[0], d - -proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = - 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, arrayType) - let t = typeToIr(c.m, n.typ) - template body(target) = - buildTyped target, info, DerefArrayAt, 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 - intoDest d, info, t, body - freeTemp c, b - freeTemp c, a - - of tyCstring, tyPtr, tyUncheckedArray: - let a = genx(c, n[0], flags) - let b = genx(c, n[1]) - template body(target) = - buildTyped target, info, DerefArrayAt, typeToIr(c.m, arrayType): - copyTree target, a - copyTree target, b - valueIntoDest c, info, d, n.typ, body - - freeTemp c, b - freeTemp c, a - of tyTuple: - let a = genx(c, n[0], flags) - let b = int n[1].intVal - template body(target) = - buildTyped target, info, FieldAt, typeToIr(c.m, arrayType): - copyTree target, a - target.addImmediateVal info, b - valueIntoDest c, info, d, n.typ, body - - freeTemp c, a - of tyOpenArray, tyVarargs: - let a = genx(c, n[0], flags) - let b = genIndexCheck(c, n[1], a, ForOpenArray, arrayType) - let t = typeToIr(c.m, n.typ) - template body(target) = - buildTyped target, info, DerefArrayAt, 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 - intoDest d, info, t, body - - freeTemp c, b - freeTemp c, a - of tyArray: - let a = genx(c, n[0], flags) - var b = default(Value) - genIndex(c, n[1], n[0].typ, b) - - template body(target) = - buildTyped target, info, ArrayAt, typeToIr(c.m, arrayType): - copyTree target, a - copyTree target, b - valueIntoDest c, info, d, n.typ, body - freeTemp c, b - freeTemp c, a - of tySequence: - let a = genx(c, n[0], flags) - let b = genIndexCheck(c, n[1], a, ForSeq, arrayType) - let t = typeToIr(c.m, n.typ) - template body(target) = - buildTyped target, info, DerefArrayAt, 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 - intoDest d, info, t, body - freeTemp c, b - freeTemp c, a - else: - localError c.config, n.info, "invalid type for nkBracketExpr: " & $arrayKind - -proc genObjAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = - let info = toLineInfo(c, n.info) - - var n0 = n[0] - var opc = FieldAt - if n0.kind == nkDotExpr: - # obj[].a --> DerefFieldAt instead of FieldAt: - n0 = n[0] - opc = DerefFieldAt - - let a = genx(c, n0, flags) - - template body(target) = - buildTyped target, info, opc, typeToIr(c.m, n0.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; prc: PSym): PSym = - result = nil - if params.len > 0 and resultPos < prc.ast.len: - let resNode = prc.ast[resultPos] - result = resNode.sym # get result symbol - c.code.addSummon toLineInfo(c, result.info), toSymId(c, result), - typeToIr(c.m, result.typ), SummonResult - elif prc.typ.len > 0 and not isEmptyType(prc.typ.returnType) and not isCompileTimeOnly(prc.typ.returnType): - # happens for procs without bodies: - let t = typeToIr(c.m, prc.typ.returnType) - let tmp = allocTemp(c, t) - c.code.addSummon toLineInfo(c, params.info), tmp, t, SummonResult - - for i in 1..<params.len: - let s = params[i].sym - if not isCompileTimeOnly(s.typ): - let t = typeToIr(c.m, s.typ) - assert t.int != -1, typeToString(s.typ) - let symId = toSymId(c, s) - c.code.addSummon toLineInfo(c, params[i].info), symId, t, SummonParam - c.m.nirm.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 - case callConv - of ccNimCall, ccFastCall, ccClosure: ann FastCall - of ccStdCall: ann StdCall - of ccCDecl: ann CDeclCall - of ccSafeCall: ann SafeCall - of ccSysCall: ann SysCall - of ccInline: ann InlineCall - of ccNoInline: ann NoinlineCall - of ccThisCall: ann ThisCall - of ccNoConvention, ccMember: ann NoCall - -proc genProc(cOuter: var ProcCon; prc: PSym) = - if prc.magic notin generatedMagics: return - 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) - let body = - if not fromForeignModule(c, prc): - transformBody(c.m.graph, c.m.idgen, prc, {useCache, keepOpenArrayConversions}) - else: - nil - - let info = toLineInfo(c, prc.info) - build c.code, info, (if body != nil: ProcDecl else: ForeignProcDecl): - if body != nil: - let symId = toSymId(c, prc) - addSymDef c.code, info, symId - c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(prc.name.s) - else: - build c.code, info, ModuleSymUse: - c.code.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(prc)) - c.code.addImmediateVal info, prc.itemId.item.int - 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 - c.code.addStrVal c.lit.strings, info, prc.loc.r - if sfImportc in prc.flags: - if lfHeader in prc. loc.flags: - assert(prc. annex != nil) - let str = getStr(prc. annex.path) - build c.code, info, PragmaPair: - c.code.addPragmaId info, HeaderImport - c.code.addStrVal c.lit.strings, info, str - elif lfDynamicLib in prc. loc.flags: - assert(prc. annex != nil) - let str = getStr(prc. annex.path) - build c.code, info, PragmaPair: - c.code.addPragmaId info, DllImport - c.code.addStrVal c.lit.strings, info, str - elif sfExportc in prc.flags: - if lfDynamicLib in prc. loc.flags: - c.code.addPragmaId info, DllExport - else: - c.code.addPragmaId info, ObjExport - - let resultSym = genParams(c, prc.typ.n, prc) - if body != nil: - gen(c, body) - patch c, body, c.exitLabel - if resultSym != nil: - build c.code, info, Ret: - c.code.addSymUse info, toSymId(c, resultSym) - else: - build c.code, info, Ret: - c.code.addNop info - - #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) 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 - case n.kind - of nkSym: genSym(c, n, d, flags) - of nkCallKinds: - if n[0].kind == nkSym: - let s = n[0].sym - if s.magic != mNone: - genMagic(c, n, d, s.magic) - elif s.kind == skMethod: - localError(c.config, n.info, "cannot call method " & s.name.s & - " at compile time") - else: - genComplexCall(c, n, d) - else: - genComplexCall(c, n, d) - of nkCharLit..nkInt64Lit, nkUIntLit..nkUInt64Lit: - genNumericLit(c, n, d, n.intVal) - of nkFloatLit..nkFloat128Lit: - genNumericLit(c, n, d, cast[int64](n.floatVal)) - of nkStrLit..nkTripleStrLit: - genStringLit(c, n, d) - of nkNilLit: - if not n.typ.isEmptyType: genNilLit(c, n, d) - else: unused(c, n, d) - of nkAsgn, nkFastAsgn, nkSinkAsgn: - unused(c, n, d) - genAsgn(c, n) - of nkDotExpr: genObjAccess(c, n, d, flags) - of nkCheckedFieldExpr: genObjAccess(c, n[0], d, flags) - of nkBracketExpr: genArrAccess(c, n, d, flags) - of nkDerefExpr, nkHiddenDeref: genDeref(c, n, d, flags) - of nkAddr, nkHiddenAddr: genAddr(c, n, d, flags) - of nkIfStmt, nkIfExpr: genIf(c, n, d) - of nkWhenStmt: - # This is "when nimvm" node. Chose the first branch. - gen(c, n[0][1], d) - of nkCaseStmt: genCase(c, n, d) - of nkWhileStmt: - unused(c, n, d) - genWhile(c, n) - of nkBlockExpr, nkBlockStmt: genBlock(c, n, d) - of nkReturnStmt: genReturn(c, n) - of nkRaiseStmt: genRaise(c, n) - of nkBreakStmt: genBreak(c, n) - of nkTryStmt, nkHiddenTryStmt: genTry(c, n, d) - of nkStmtList: - #unused(c, n, d) - # XXX Fix this bug properly, lexim triggers it - for x in n: gen(c, x) - of nkStmtListExpr: - for i in 0..<n.len-1: gen(c, n[i]) - gen(c, n[^1], d, flags) - of nkPragmaBlock: - gen(c, n.lastSon, d, flags) - of nkDiscardStmt: - unused(c, n, d) - gen(c, n[0], d) - of nkHiddenStdConv, nkHiddenSubConv, nkConv: - genConv(c, n, n[1], d, flags, NumberConv) # misnomer? - of nkObjDownConv: - genConv(c, n, n[0], d, flags, ObjConv) - of nkObjUpConv: - genConv(c, n, n[0], d, flags, CheckedObjConv) - of nkVarSection, nkLetSection, nkConstSection: - unused(c, n, d) - genVarSection(c, n) - of nkLambdaKinds: - #let s = n[namePos].sym - #discard genProc(c, s) - gen(c, newSymNode(n[namePos].sym), d) - of nkChckRangeF, nkChckRange64, nkChckRange: - genRangeCheck(c, n, d) - of declarativeDefs - {nkIteratorDef}: - unused(c, n, d) - genProc(c, n) - of nkEmpty, nkCommentStmt, nkTypeSection, nkPragma, - nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt, - nkMixinStmt, nkBindStmt, nkMacroDef, nkIteratorDef: - unused(c, n, d) - of nkStringToCString: convStrToCStr(c, n, d) - of nkCStringToString: convCStrToStr(c, n, d) - of nkBracket: genArrayConstr(c, n, d) - of nkCurly: genSetConstr(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: - discard "XXX to implement for better stack traces" - #of nkState: genState(c, n) - #of nkGotoState: genGotoState(c, n) - #of nkBreakState: genBreakState(c, n, d) - else: - localError(c.config, n.info, "cannot generate IR code for " & $n) - -proc genPendingProcs(c: var ProcCon) = - while c.m.pendingProcs.len > 0 or c.m.pendingVars.len > 0: - let procs = move(c.m.pendingProcs) - for v in procs: - genProc(c, v) - let vars = move(c.m.pendingVars) - for v in vars: - genForeignVar(c, v) - -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 - genPendingProcs c - -proc genExpr*(c: var ProcCon; n: PNode, requiresValue = true): int = - result = c.code.len - var d = default(Value) - c.gen(n, d) - genPendingProcs c - if isEmpty d: - if requiresValue: - globalError(c.config, n.info, "VM problem: d register is not set") diff --git a/compiler/nir/cir.nim b/compiler/nir/cir.nim deleted file mode 100644 index 01f9c4c9a..000000000 --- a/compiler/nir/cir.nim +++ /dev/null @@ -1,983 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2023 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# We produce C code as a list of tokens. - -import std / [assertions, syncio, tables, intsets, formatfloat] -from std / strutils import toOctal -import .. / ic / [bitabs, rodfiles] -import nirtypes, nirinsts, nirfiles -import ../../dist/checksums/src/checksums/md5 - -type - Token = LitId # indexing into the tokens BiTable[string] - - PredefinedToken = enum - IgnoreMe = "<unused>" - EmptyToken = "" - CurlyLe = "{" - CurlyRi = "}" - ParLe = "(" - ParRi = ")" - BracketLe = "[" - BracketRi = "]" - NewLine = "\n" - Semicolon = ";" - Comma = ", " - Space = " " - Colon = ": " - Dot = "." - Arrow = "->" - Star = "*" - Amp = "&" - AsgnOpr = " = " - ScopeOpr = "::" - ConstKeyword = "const " - StaticKeyword = "static " - ExternKeyword = "extern " - WhileKeyword = "while " - IfKeyword = "if (" - ElseKeyword = "else " - SwitchKeyword = "switch " - CaseKeyword = "case " - DefaultKeyword = "default:" - BreakKeyword = "break" - NullPtr = "nullptr" - IfNot = "if (!(" - ReturnKeyword = "return " - TypedefStruct = "typedef struct " - TypedefUnion = "typedef union " - IncludeKeyword = "#include " - -proc fillTokenTable(tab: var BiTable[string]) = - for e in EmptyToken..high(PredefinedToken): - let id = tab.getOrIncl $e - assert id == LitId(e), $(id, " ", ord(e)) - -type - GeneratedCode* = object - m: NirModule - includes: seq[LitId] - includedHeaders: IntSet - data: seq[LitId] - protos: seq[LitId] - code: seq[LitId] - init: seq[LitId] - tokens: BiTable[string] - emittedStrings: IntSet - needsPrefix: IntSet - generatedTypes: IntSet - mangledModules: Table[LitId, LitId] - -proc initGeneratedCode*(m: sink NirModule): GeneratedCode = - result = GeneratedCode(m: m, code: @[], tokens: initBiTable[string]()) - fillTokenTable(result.tokens) - -proc add*(g: var GeneratedCode; t: PredefinedToken) {.inline.} = - g.code.add Token(t) - -proc add*(g: var GeneratedCode; s: string) {.inline.} = - g.code.add g.tokens.getOrIncl(s) - -proc mangleModuleName(c: var GeneratedCode; key: LitId): LitId = - result = c.mangledModules.getOrDefault(key, LitId(0)) - if result == LitId(0): - let u {.cursor.} = c.m.lit.strings[key] - var last = u.len - len(".nim") - 1 - var start = last - while start >= 0 and u[start] != '/': dec start - var sum = getMD5(u) - sum.setLen(8) - let dest = u.substr(start+1, last) & sum - result = c.tokens.getOrIncl(dest) - c.mangledModules[key] = result - -type - CppFile = object - f: File - -proc write(f: var CppFile; s: string) = write(f.f, s) -proc write(f: var CppFile; c: char) = write(f.f, c) - -proc writeTokenSeq(f: var CppFile; s: seq[Token]; c: GeneratedCode) = - var indent = 0 - for i in 0..<s.len: - let x = s[i] - case x - of Token(CurlyLe): - inc indent - write f, c.tokens[x] - write f, "\n" - for i in 1..indent*2: write f, ' ' - of Token(CurlyRi): - dec indent - write f, c.tokens[x] - if i+1 < s.len and s[i+1] == Token(CurlyRi): - discard - else: - write f, "\n" - for i in 1..indent*2: write f, ' ' - of Token(Semicolon): - write f, c.tokens[x] - if i+1 < s.len and s[i+1] == Token(CurlyRi): - discard "no newline before }" - else: - write f, "\n" - for i in 1..indent*2: write f, ' ' - of Token(NewLine): - write f, c.tokens[x] - for i in 1..indent*2: write f, ' ' - else: - write f, c.tokens[x] - - -# Type graph - -type - TypeList = object - processed: IntSet - s: seq[(TypeId, PredefinedToken)] - -proc add(dest: var TypeList; elem: TypeId; decl: PredefinedToken) = - if not containsOrIncl(dest.processed, int(elem)): - dest.s.add (elem, decl) - -type - TypeOrder = object - forwardedDecls, ordered: TypeList - typeImpls: Table[string, TypeId] - lookedAt: IntSet - -proc traverseObject(types: TypeGraph; lit: Literals; c: var TypeOrder; t: TypeId) - -proc recordDependency(types: TypeGraph; lit: Literals; c: var TypeOrder; parent, child: TypeId) = - var ch = child - var viaPointer = false - while true: - case types[ch].kind - of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy: - viaPointer = true - ch = elementType(types, ch) - of LastArrayTy: - ch = elementType(types, ch) - else: - break - - case types[ch].kind - of ObjectTy, UnionTy: - let decl = if types[ch].kind == ObjectTy: TypedefStruct else: TypedefUnion - let obj = c.typeImpls.getOrDefault(lit.strings[types[ch].litId]) - if viaPointer: - c.forwardedDecls.add obj, decl - else: - if not containsOrIncl(c.lookedAt, obj.int): - traverseObject(types, lit, c, obj) - c.ordered.add obj, decl - of ArrayTy: - if viaPointer: - c.forwardedDecls.add ch, TypedefStruct - else: - if not containsOrIncl(c.lookedAt, ch.int): - traverseObject(types, lit, c, ch) - c.ordered.add ch, TypedefStruct - else: - discard "uninteresting type as we only focus on the required struct declarations" - -proc traverseObject(types: TypeGraph; lit: Literals; c: var TypeOrder; t: TypeId) = - for x in sons(types, t): - case types[x].kind - of FieldDecl: - recordDependency types, lit, c, t, x.firstSon - of ObjectTy: - # inheritance - recordDependency types, lit, c, t, x - else: discard - -proc traverseTypes(types: TypeGraph; lit: Literals; c: var TypeOrder) = - for t in allTypes(types): - if types[t].kind in {ObjectDecl, UnionDecl}: - assert types[t.firstSon].kind == NameVal - c.typeImpls[lit.strings[types[t.firstSon].litId]] = t - - for t in allTypesIncludingInner(types): - case types[t].kind - of ObjectDecl, UnionDecl: - traverseObject types, lit, c, t - let decl = if types[t].kind == ObjectDecl: TypedefStruct else: TypedefUnion - c.ordered.add t, decl - of ArrayTy: - traverseObject types, lit, c, t - c.ordered.add t, TypedefStruct - else: discard - -when false: - template emitType(s: string) = c.types.add c.tokens.getOrIncl(s) - template emitType(t: Token) = c.types.add t - template emitType(t: PredefinedToken) = c.types.add Token(t) - -proc genType(g: var GeneratedCode; types: TypeGraph; lit: Literals; t: TypeId; name = "") = - template maybeAddName = - if name != "": - g.add Space - g.add name - - template atom(s: string) = - g.add s - maybeAddName() - case types[t].kind - of VoidTy: atom "void" - of IntTy: atom "NI" & $types[t].integralBits - of UIntTy: atom "NU" & $types[t].integralBits - of FloatTy: atom "NF" & $types[t].integralBits - of BoolTy: atom "NB" & $types[t].integralBits - of CharTy: atom "NC" & $types[t].integralBits - of ObjectTy, UnionTy, NameVal, AnnotationVal: - atom lit.strings[types[t].litId] - of VarargsTy: - g.add "..." - of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy: - genType g, types, lit, elementType(types, t) - g.add Star - maybeAddName() - of ArrayTy: - genType g, types, lit, arrayName(types, t) - maybeAddName() - of LastArrayTy: - genType g, types, lit, elementType(types, t) - maybeAddName() - g.add BracketLe - g.add BracketRi - of ProcTy: - let (retType, callConv) = returnType(types, t) - genType g, types, lit, retType - g.add Space - g.add ParLe - genType g, types, lit, callConv - g.add Star # "(*fn)" - maybeAddName() - g.add ParRi - g.add ParLe - var i = 0 - for ch in params(types, t): - if i > 0: g.add Comma - genType g, types, lit, ch - inc i - g.add ParRi - of ObjectDecl, UnionDecl: - atom lit.strings[types[t.firstSon].litId] - of IntVal, SizeVal, AlignVal, OffsetVal, FieldDecl: - #raiseAssert "did not expect: " & $types[t].kind - g.add "BUG " - atom $types[t].kind - -proc generateTypes(g: var GeneratedCode; types: TypeGraph; lit: Literals; c: TypeOrder) = - for (t, declKeyword) in c.forwardedDecls.s: - let name = if types[t].kind == ArrayTy: arrayName(types, t) else: t.firstSon - let s {.cursor.} = lit.strings[types[name].litId] - g.add declKeyword - g.add s - g.add Space - g.add s - g.add Semicolon - - for (t, declKeyword) in c.ordered.s: - let name = if types[t].kind == ArrayTy: arrayName(types, t) else: t.firstSon - let litId = types[name].litId - if not g.generatedTypes.containsOrIncl(litId.int): - let s {.cursor.} = lit.strings[litId] - g.add declKeyword - g.add CurlyLe - if types[t].kind == ArrayTy: - genType g, types, lit, elementType(types, t), "a" - g.add BracketLe - g.add $arrayLen(types, t) - g.add BracketRi - g.add Semicolon - else: - var i = 0 - for x in sons(types, t): - case types[x].kind - of FieldDecl: - genType g, types, lit, x.firstSon, "F" & $i - g.add Semicolon - inc i - of ObjectTy: - genType g, types, lit, x, "P" - g.add Semicolon - else: discard - g.add CurlyRi - g.add s - g.add Semicolon - -# Procs - -proc toCChar*(c: char; result: var string) {.inline.} = - case c - of '\0'..'\x1F', '\x7F'..'\xFF': - result.add '\\' - result.add toOctal(c) - of '\'', '\"', '\\', '?': - result.add '\\' - result.add c - else: - result.add c - -proc makeCString(s: string): string = - result = newStringOfCap(s.len + 10) - result.add('"') - for c in s: toCChar(c, result) - result.add('"') - -template emitData(s: string) = c.data.add c.tokens.getOrIncl(s) -template emitData(t: Token) = c.data.add t -template emitData(t: PredefinedToken) = c.data.add Token(t) - -proc genStrLit(c: var GeneratedCode; lit: Literals; litId: LitId): Token = - result = Token(c.tokens.getOrIncl "QStr" & $litId) - if not containsOrIncl(c.emittedStrings, int(litId)): - let s {.cursor.} = lit.strings[litId] - emitData "static const struct " - emitData CurlyLe - emitData "NI cap" - emitData Semicolon - emitData "NC8 data" - emitData BracketLe - emitData $s.len - emitData "+1" - emitData BracketRi - emitData Semicolon - emitData CurlyRi - emitData result - emitData AsgnOpr - emitData CurlyLe - emitData $s.len - emitData " | NIM_STRLIT_FLAG" - emitData Comma - emitData makeCString(s) - emitData CurlyRi - emitData Semicolon - -proc genIntLit(c: var GeneratedCode; lit: Literals; litId: LitId) = - let i = lit.numbers[litId] - if i > low(int32) and i <= high(int32): - c.add $i - elif i == low(int32): - # Nim has the same bug for the same reasons :-) - c.add "(-2147483647 -1)" - elif i > low(int64): - c.add "IL64(" - c.add $i - c.add ")" - else: - c.add "(IL64(-9223372036854775807) - IL64(1))" - -proc gen(c: var GeneratedCode; t: Tree; n: NodePos) - -proc genDisplayName(c: var GeneratedCode; symId: SymId) = - let displayName = c.m.symnames[symId] - if displayName != LitId(0): - c.add "/*" - c.add c.m.lit.strings[displayName] - c.add "*/" - -proc genSymDef(c: var GeneratedCode; t: Tree; n: NodePos) = - if t[n].kind == SymDef: - let symId = t[n].symId - c.needsPrefix.incl symId.int - genDisplayName c, symId - gen c, t, n - -proc genGlobal(c: var GeneratedCode; t: Tree; name, typ: NodePos; annotation: string) = - c.add annotation - let m: string - if t[name].kind == SymDef: - let symId = t[name].symId - m = c.tokens[mangleModuleName(c, c.m.namespace)] & "__" & $symId - genDisplayName c, symId - else: - assert t[name].kind == ModuleSymUse - let (x, y) = sons2(t, name) - m = c.tokens[mangleModuleName(c, t[x].litId)] & "__" & $t[y].immediateVal - genType c, c.m.types, c.m.lit, t[typ].typeId, m - -proc genLocal(c: var GeneratedCode; t: Tree; name, typ: NodePos; annotation: string) = - assert t[name].kind == SymDef - c.add annotation - let symId = t[name].symId - genType c, c.m.types, c.m.lit, t[typ].typeId, "q" & $symId - genDisplayName c, symId - -proc genProcDecl(c: var GeneratedCode; t: Tree; n: NodePos; isExtern: bool) = - let signatureBegin = c.code.len - let name = n.firstSon - - var prc = n.firstSon - next t, prc - - while true: - case t[prc].kind - of PragmaPair: - let (x, y) = sons2(t, prc) - let key = cast[PragmaKey](t[x].rawOperand) - case key - of HeaderImport: - let lit = t[y].litId - let headerAsStr {.cursor.} = c.m.lit.strings[lit] - let header = c.tokens.getOrIncl(headerAsStr) - # headerAsStr can be empty, this has the semantics of the `nodecl` pragma: - if headerAsStr.len > 0 and not c.includedHeaders.containsOrIncl(int header): - if headerAsStr[0] == '#': - discard "skip the #include" - else: - c.includes.add Token(IncludeKeyword) - c.includes.add header - c.includes.add Token NewLine - # do not generate code for importc'ed procs: - return - of DllImport: - let lit = t[y].litId - raiseAssert "cannot eval: " & c.m.lit.strings[lit] - else: discard - of PragmaId: discard - else: break - next t, prc - - var resultDeclPos = NodePos(-1) - if t[prc].kind == SummonResult: - resultDeclPos = prc - gen c, t, prc.firstSon - next t, prc - else: - c.add "void" - c.add Space - genSymDef c, t, name - c.add ParLe - var params = 0 - while t[prc].kind == SummonParam: - if params > 0: c.add Comma - let (typ, sym) = sons2(t, prc) - genLocal c, t, sym, typ, "" - next t, prc - inc params - if params == 0: - c.add "void" - c.add ParRi - - for i in signatureBegin ..< c.code.len: - c.protos.add c.code[i] - c.protos.add Token Semicolon - - if isExtern: - c.code.setLen signatureBegin - else: - c.add CurlyLe - if resultDeclPos.int >= 0: - gen c, t, resultDeclPos - for ch in sonsRest(t, n, prc): - gen c, t, ch - c.add CurlyRi - -template triop(opr) = - let (typ, a, b) = sons3(t, n) - c.add ParLe - c.add ParLe - gen c, t, typ - c.add ParRi - gen c, t, a - c.add opr - gen c, t, b - c.add ParRi - -template cmpop(opr) = - let (_, a, b) = sons3(t, n) - c.add ParLe - gen c, t, a - c.add opr - gen c, t, b - c.add ParRi - -template binaryop(opr) = - let (typ, a) = sons2(t, n) - c.add ParLe - c.add ParLe - gen c, t, typ - c.add ParRi - c.add opr - gen c, t, a - c.add ParRi - -template checkedBinaryop(opr) = - let (typ, labIdx, a, b) = sons4(t, n) - let bits = integralBits(c.m.types[t[typ].typeId]) - let lab = t[labIdx].label - - c.add (opr & $bits) - c.add ParLe - c.gen t, a - c.add Comma - c.gen t, b - c.add Comma - c.add "L" & $lab.int - c.add ParRi - -proc genNumberConv(c: var GeneratedCode; t: Tree; n: NodePos) = - let (typ, arg) = sons2(t, n) - if t[arg].kind == IntVal: - let litId = t[arg].litId - c.add ParLe - c.add ParLe - gen c, t, typ - c.add ParRi - case c.m.types[t[typ].typeId].kind - of UIntTy: - let x = cast[uint64](c.m.lit.numbers[litId]) - c.add $x - of FloatTy: - let x = cast[float64](c.m.lit.numbers[litId]) - c.add $x - else: - gen c, t, arg - c.add ParRi - else: - binaryop "" - -template moveToDataSection(body: untyped) = - let oldLen = c.code.len - body - for i in oldLen ..< c.code.len: - c.data.add c.code[i] - setLen c.code, oldLen - -proc gen(c: var GeneratedCode; t: Tree; n: NodePos) = - case t[n].kind - of Nop: - discard "nothing to emit" - of ImmediateVal: - c.add $t[n].immediateVal - of IntVal: - genIntLit c, c.m.lit, t[n].litId - of StrVal: - c.code.add genStrLit(c, c.m.lit, t[n].litId) - of Typed: - genType c, c.m.types, c.m.lit, t[n].typeId - of SymDef, SymUse: - let s = t[n].symId - if c.needsPrefix.contains(s.int): - c.code.add mangleModuleName(c, c.m.namespace) - c.add "__" - c.add $s - else: - # XXX Use proper names here - c.add "q" - c.add $s - - of ModuleSymUse: - let (x, y) = sons2(t, n) - let u = mangleModuleName(c, t[x].litId) - let s = t[y].immediateVal - c.code.add u - c.add "__" - c.add $s - - of NilVal: - c.add NullPtr - of LoopLabel: - c.add WhileKeyword - c.add ParLe - c.add "1" - c.add ParRi - c.add CurlyLe - of GotoLoop: - c.add CurlyRi - of Label: - let lab = t[n].label - c.add "L" - c.add $lab.int - c.add Colon - c.add Semicolon - of Goto: - let lab = t[n].label - c.add "goto L" - c.add $lab.int - c.add Semicolon - of CheckedGoto: - discard "XXX todo" - of ArrayConstr: - c.add CurlyLe - c.add ".a = " - c.add CurlyLe - var i = 0 - for ch in sonsFrom1(t, n): - if i > 0: c.add Comma - c.gen t, ch - inc i - c.add CurlyRi - c.add CurlyRi - of ObjConstr: - c.add CurlyLe - var i = 0 - for ch in sonsFrom1(t, n): - if i mod 2 == 0: - if i > 0: c.add Comma - c.add ".F" & $t[ch].immediateVal - c.add AsgnOpr - else: - c.gen t, ch - inc i - c.add CurlyRi - of Ret: - c.add ReturnKeyword - c.gen t, n.firstSon - c.add Semicolon - of Select: - c.add SwitchKeyword - c.add ParLe - let (_, selector) = sons2(t, n) - c.gen t, selector - c.add ParRi - c.add CurlyLe - for ch in sonsFromN(t, n, 2): - c.gen t, ch - c.add CurlyRi - of SelectPair: - let (le, ri) = sons2(t, n) - c.gen t, le - c.gen t, ri - of SelectList: - for ch in sons(t, n): - c.gen t, ch - of SelectValue: - c.add CaseKeyword - c.gen t, n.firstSon - c.add Colon - of SelectRange: - let (le, ri) = sons2(t, n) - c.add CaseKeyword - c.gen t, le - c.add " ... " - c.gen t, ri - c.add Colon - of ForeignDecl: - c.data.add LitId(ExternKeyword) - c.gen t, n.firstSon - of SummonGlobal: - moveToDataSection: - let (typ, sym) = sons2(t, n) - c.genGlobal t, sym, typ, "" - c.add Semicolon - of SummonThreadLocal: - moveToDataSection: - let (typ, sym) = sons2(t, n) - c.genGlobal t, sym, typ, "__thread " - c.add Semicolon - of SummonConst: - moveToDataSection: - let (typ, sym, val) = sons3(t, n) - c.genGlobal t, sym, typ, "const " - c.add AsgnOpr - c.gen t, val - c.add Semicolon - of Summon, SummonResult: - let (typ, sym) = sons2(t, n) - c.genLocal t, sym, typ, "" - c.add Semicolon - - of SummonParam: - raiseAssert "SummonParam should have been handled in genProc" - of Kill: - discard "we don't care about Kill instructions" - of AddrOf: - let (_, arg) = sons2(t, n) - c.add "&" - gen c, t, arg - of DerefArrayAt: - let (_, a, i) = sons3(t, n) - gen c, t, a - c.add BracketLe - gen c, t, i - c.add BracketRi - of ArrayAt: - let (_, a, i) = sons3(t, n) - gen c, t, a - c.add Dot - c.add "a" - c.add BracketLe - gen c, t, i - c.add BracketRi - of FieldAt: - let (_, a, b) = sons3(t, n) - gen c, t, a - let field = t[b].immediateVal - c.add Dot - c.add "F" & $field - of DerefFieldAt: - let (_, a, b) = sons3(t, n) - gen c, t, a - let field = t[b].immediateVal - c.add Arrow - c.add "F" & $field - of Load: - let (_, arg) = sons2(t, n) - c.add ParLe - c.add "*" - gen c, t, arg - c.add ParRi - of Store: - raiseAssert "Assumption was that Store is unused!" - of Asgn: - let (_, dest, src) = sons3(t, n) - gen c, t, dest - c.add AsgnOpr - gen c, t, src - c.add Semicolon - of CheckedRange: - c.add "nimCheckRange" - c.add ParLe - let (_, gotoInstr, x, a, b) = sons5(t, n) - gen c, t, x - c.add Comma - gen c, t, a - c.add Comma - gen c, t, b - c.add Comma - c.add "L" & $t[gotoInstr].label.int - c.add ParRi - of CheckedIndex: - c.add "nimCheckIndex" - c.add ParLe - let (gotoInstr, x, a) = sons3(t, n) - gen c, t, x - c.add Comma - gen c, t, a - c.add Comma - c.add "L" & $t[gotoInstr].label.int - c.add ParRi - of Call, IndirectCall: - let (typ, fn) = sons2(t, n) - gen c, t, fn - c.add ParLe - var i = 0 - for ch in sonsFromN(t, n, 2): - if i > 0: c.add Comma - gen c, t, ch - inc i - c.add ParRi - if c.m.types[t[typ].typeId].kind == VoidTy: - c.add Semicolon - of CheckedCall, CheckedIndirectCall: - let (typ, gotoInstr, fn) = sons3(t, n) - gen c, t, fn - c.add ParLe - var i = 0 - for ch in sonsFromN(t, n, 3): - if i > 0: c.add Comma - gen c, t, ch - inc i - c.add ParRi - if c.m.types[t[typ].typeId].kind == VoidTy: - c.add Semicolon - - of CheckedAdd: checkedBinaryop "nimAddInt" - of CheckedSub: checkedBinaryop "nimSubInt" - of CheckedMul: checkedBinaryop "nimMulInt" - of CheckedDiv: checkedBinaryop "nimDivInt" - of CheckedMod: checkedBinaryop "nimModInt" - of Add: triop " + " - of Sub: triop " - " - of Mul: triop " * " - of Div: triop " / " - of Mod: triop " % " - of BitShl: triop " << " - of BitShr: triop " >> " - of BitAnd: triop " & " - of BitOr: triop " | " - of BitXor: triop " ^ " - of BitNot: binaryop " ~ " - of BoolNot: binaryop " !" - of Eq: cmpop " == " - of Le: cmpop " <= " - of Lt: cmpop " < " - of Cast: binaryop "" - of NumberConv: genNumberConv c, t, n - of CheckedObjConv: binaryop "" - of ObjConv: binaryop "" - of Emit: raiseAssert "cannot interpret: Emit" - of ProcDecl: genProcDecl c, t, n, false - of ForeignProcDecl: genProcDecl c, t, n, true - of PragmaPair, PragmaId, TestOf, Yld, SetExc, TestExc: - c.add "cannot interpret: " & $t[n].kind - -const - Prelude = """ -/* GENERATED CODE. DO NOT EDIT. */ - -#ifdef __cplusplus -#define NB8 bool -#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901) -// see #13798: to avoid conflicts for code emitting `#include <stdbool.h>` -#define NB8 _Bool -#else -typedef unsigned char NB8; // best effort -#endif - -typedef unsigned char NC8; - -typedef float NF32; -typedef double NF64; -#if defined(__BORLANDC__) || defined(_MSC_VER) -typedef signed char NI8; -typedef signed short int NI16; -typedef signed int NI32; -typedef __int64 NI64; -/* XXX: Float128? */ -typedef unsigned char NU8; -typedef unsigned short int NU16; -typedef unsigned int NU32; -typedef unsigned __int64 NU64; -#elif defined(HAVE_STDINT_H) -#ifndef USE_NIM_NAMESPACE -# include <stdint.h> -#endif -typedef int8_t NI8; -typedef int16_t NI16; -typedef int32_t NI32; -typedef int64_t NI64; -typedef uint8_t NU8; -typedef uint16_t NU16; -typedef uint32_t NU32; -typedef uint64_t NU64; -#elif defined(HAVE_CSTDINT) -#ifndef USE_NIM_NAMESPACE -# include <cstdint> -#endif -typedef std::int8_t NI8; -typedef std::int16_t NI16; -typedef std::int32_t NI32; -typedef std::int64_t NI64; -typedef std::uint8_t NU8; -typedef std::uint16_t NU16; -typedef std::uint32_t NU32; -typedef std::uint64_t NU64; -#else -/* Unknown compiler/version, do our best */ -#ifdef __INT8_TYPE__ -typedef __INT8_TYPE__ NI8; -#else -typedef signed char NI8; -#endif -#ifdef __INT16_TYPE__ -typedef __INT16_TYPE__ NI16; -#else -typedef signed short int NI16; -#endif -#ifdef __INT32_TYPE__ -typedef __INT32_TYPE__ NI32; -#else -typedef signed int NI32; -#endif -#ifdef __INT64_TYPE__ -typedef __INT64_TYPE__ NI64; -#else -typedef long long int NI64; -#endif -/* XXX: Float128? */ -#ifdef __UINT8_TYPE__ -typedef __UINT8_TYPE__ NU8; -#else -typedef unsigned char NU8; -#endif -#ifdef __UINT16_TYPE__ -typedef __UINT16_TYPE__ NU16; -#else -typedef unsigned short int NU16; -#endif -#ifdef __UINT32_TYPE__ -typedef __UINT32_TYPE__ NU32; -#else -typedef unsigned int NU32; -#endif -#ifdef __UINT64_TYPE__ -typedef __UINT64_TYPE__ NU64; -#else -typedef unsigned long long int NU64; -#endif -#endif - -#ifdef NIM_INTBITS -# if NIM_INTBITS == 64 -typedef NI64 NI; -typedef NU64 NU; -# elif NIM_INTBITS == 32 -typedef NI32 NI; -typedef NU32 NU; -# elif NIM_INTBITS == 16 -typedef NI16 NI; -typedef NU16 NU; -# elif NIM_INTBITS == 8 -typedef NI8 NI; -typedef NU8 NU; -# else -# error "invalid bit width for int" -# endif -#endif - -#define NIM_STRLIT_FLAG ((NU)(1) << ((NIM_INTBITS) - 2)) /* This has to be the same as system.strlitFlag! */ - -#define nimAddInt64(a, b, L) ({long long int res; if(__builtin_saddll_overflow(a, b, &res)) goto L; res}) -#define nimSubInt64(a, b, L) ({long long int res; if(__builtin_ssubll_overflow(a, b, &res)) goto L; res}) -#define nimMulInt64(a, b, L) ({long long int res; if(__builtin_smulll_overflow(a, b, &res)) goto L; res}) - -#define nimAddInt32(a, b, L) ({long int res; if(__builtin_sadd_overflow(a, b, &res)) goto L; res}) -#define nimSubInt32(a, b, L) ({long int res; if(__builtin_ssub_overflow(a, b, &res)) goto L; res}) -#define nimMulInt32(a, b, L) ({long int res; if(__builtin_smul_overflow(a, b, &res)) goto L; res}) - -#define nimCheckRange(x, a, b, L) ({if (x < a || x > b) goto L; x}) -#define nimCheckIndex(x, a, L) ({if (x >= a) goto L; x}) - -""" - -proc traverseCode(c: var GeneratedCode) = - const AllowedInToplevelC = {SummonConst, SummonGlobal, SummonThreadLocal, - ProcDecl, ForeignDecl, ForeignProcDecl} - var i = NodePos(0) - while i.int < c.m.code.len: - let oldLen = c.code.len - let moveToInitSection = c.m.code[NodePos(i)].kind notin AllowedInToplevelC - - gen c, c.m.code, NodePos(i) - next c.m.code, i - - if moveToInitSection: - for i in oldLen ..< c.code.len: - c.init.add c.code[i] - setLen c.code, oldLen - -proc generateCode*(inp, outp: string) = - var c = initGeneratedCode(load(inp)) - - var co = TypeOrder() - traverseTypes(c.m.types, c.m.lit, co) - - generateTypes(c, c.m.types, c.m.lit, co) - let typeDecls = move c.code - - traverseCode c - var f = CppFile(f: open(outp, fmWrite)) - f.write "#define NIM_INTBITS " & $c.m.intbits & "\n" - f.write Prelude - writeTokenSeq f, c.includes, c - writeTokenSeq f, typeDecls, c - writeTokenSeq f, c.data, c - writeTokenSeq f, c.protos, c - writeTokenSeq f, c.code, c - if c.init.len > 0: - f.write "void __attribute__((constructor)) init(void) {" - writeTokenSeq f, c.init, c - f.write "}\n\n" - f.f.close diff --git a/compiler/nir/nir.nim b/compiler/nir/nir.nim deleted file mode 100644 index 6f7077fb0..000000000 --- a/compiler/nir/nir.nim +++ /dev/null @@ -1,105 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2023 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Nim Intermediate Representation, designed to capture all of Nim's semantics without losing too much -## precious information. Can easily be translated into C. And to JavaScript, hopefully. - -from std/os import addFileExt, `/`, createDir - -import std / assertions -import ".." / [ast, modulegraphs, renderer, transf, options, msgs, lineinfos] -import nirtypes, nirinsts, ast2ir, nirlineinfos, nirfiles, nirvm - -import ".." / ic / [rodfiles, bitabs] - -type - PCtx* = ref object of TPassContext - m: ModuleCon - c: ProcCon - oldErrorCount: int - bytecode: Bytecode - -proc newCtx*(module: PSym; g: ModuleGraph; idgen: IdGenerator): PCtx = - 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.nirm) - #c.m.noModularity = true - c.c = initProcCon(c.m, nil, c.m.graph.config) - c.idgen = idgen - -proc setupGlobalCtx*(module: PSym; graph: ModuleGraph; idgen: IdGenerator) = - if graph.repl.isNil: - graph.repl = newCtx(module, graph, idgen) - #registerAdditionalOps(PCtx graph.repl) - else: - refresh(PCtx graph.repl, module, idgen) - -proc setupNirReplGen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = - setupGlobalCtx(module, graph, idgen) - result = PCtx graph.repl - -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 = "" - #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 - if pc.int < c.m.nirm.code.len: - c.bytecode.interactive = c.m.graph.interactive - execCode c.bytecode, c.m.nirm.code, pc - #echo res - -proc runCode*(c: PPassContext; n: PNode): PNode = - let c = PCtx(c) - # don't eval errornous code: - if c.oldErrorCount == c.m.graph.config.errorCounter: - evalStmt(c, n) - result = newNodeI(nkEmpty, n.info) - else: - result = n - c.oldErrorCount = c.m.graph.config.errorCounter - -type - NirPassContext* = ref object of TPassContext - m: ModuleCon - c: ProcCon - -proc openNirBackend*(g: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = - 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) = - let n = transformExpr(c.m.graph, c.idgen, c.m.module, n) - let pc = genStmt(c.c, n) - -proc nirBackend*(c: PPassContext; n: PNode): PNode = - gen(NirPassContext(c), n) - result = n - -proc closeNirBackend*(c: PPassContext; finalNode: PNode) = - discard nirBackend(c, finalNode) - - let c = NirPassContext(c) - let nimcache = getNimcacheDir(c.c.config).string - createDir nimcache - let outp = nimcache / c.m.module.name.s.addFileExt("nir") - #c.m.nirm.code = move c.c.code - try: - 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 deleted file mode 100644 index a2cf69988..000000000 --- a/compiler/nir/nirc.nim +++ /dev/null @@ -1,52 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2023 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Nir Compiler. - -import ".." / ic / [bitabs, rodfiles] -import nirinsts, nirtypes, nirlineinfos, nirfiles, cir - -proc view(filename: string) = - let m = load(filename) - var res = "" - allTreesToString m.code, m.lit.strings, m.lit.numbers, m.symnames, res - res.add "\n# TYPES\n" - nirtypes.toString res, m.types - echo res - -import std / [syncio, parseopt] - -proc writeHelp = - echo """Usage: nirc view|c <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 "c": - let outp = inp & ".c" - cir.generateCode inp, outp - -main() diff --git a/compiler/nir/nirfiles.nim b/compiler/nir/nirfiles.nim deleted file mode 100644 index cd5a79f06..000000000 --- a/compiler/nir/nirfiles.nim +++ /dev/null @@ -1,83 +0,0 @@ -# -# -# 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 - namespace*: LitId - intbits*: uint32 - 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 namespaceSection - r.loadPrim result.namespace - r.loadPrim result.intbits - - 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 namespaceSection - r.storePrim m.namespace - r.storePrim m.intbits - - 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 deleted file mode 100644 index 6cffc1a89..000000000 --- a/compiler/nir/nirinsts.nim +++ /dev/null @@ -1,582 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2023 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## NIR instructions. Somewhat inspired by LLVM's instructions. - -import std / [assertions, hashes] -import .. / ic / [bitabs, rodfiles] -import nirlineinfos, nirtypes - -const - NirVersion = 1 - nirCookie* = [byte(0), byte('N'), byte('I'), byte('R'), - byte(sizeof(int)*8), byte(system.cpuEndian), byte(0), byte(NirVersion)] - -type - SymId* = distinct int - -proc `$`*(s: SymId): string {.borrow.} -proc hash*(s: SymId): Hash {.borrow.} -proc `==`*(a, b: SymId): bool {.borrow.} - -type - Opcode* = enum - Nop, - ImmediateVal, - IntVal, - StrVal, - SymDef, - SymUse, - Typed, # with type ID - PragmaId, # with Pragma ID, possible values: see PragmaKey enum - NilVal, - Label, - Goto, - CheckedGoto, - LoopLabel, - GotoLoop, # last atom - - ModuleSymUse, # `"module".x` - - ArrayConstr, - ObjConstr, - Ret, - Yld, - - Select, - SelectPair, # ((values...), Label) - SelectList, # (values...) - SelectValue, # (value) - SelectRange, # (valueA..valueB) - ForeignDecl, # Can wrap SummonGlobal, SummonThreadLocal, SummonConst - SummonGlobal, - SummonThreadLocal, - Summon, # x = Summon Typed <Type ID>; x begins to live - SummonResult, - SummonParam, - SummonConst, - Kill, # `Kill x`: scope end for `x` - - AddrOf, - ArrayAt, # a[i] - DerefArrayAt, # a[i] where `a` is a PtrArray; `a[][i]` - FieldAt, # obj.field - DerefFieldAt, # obj[].field - - Load, # a[] - Store, # a[] = b - Asgn, # a = b - SetExc, - TestExc, - - CheckedRange, - CheckedIndex, - - Call, - IndirectCall, - CheckedCall, # call that can raise - CheckedIndirectCall, # call that can raise - CheckedAdd, # with overflow checking etc. - CheckedSub, - CheckedMul, - CheckedDiv, - CheckedMod, - Add, - Sub, - Mul, - Div, - Mod, - BitShl, - BitShr, - BitAnd, - BitOr, - BitXor, - BitNot, - BoolNot, - Eq, - Le, - Lt, - Cast, - NumberConv, - CheckedObjConv, - ObjConv, - TestOf, - Emit, - ProcDecl, - ForeignProcDecl, - PragmaPair - -type - PragmaKey* = enum - FastCall, StdCall, CDeclCall, SafeCall, SysCall, InlineCall, NoinlineCall, ThisCall, NoCall, - CoreName, - ExternName, - HeaderImport, - DllImport, - DllExport, - ObjExport - -const - LastAtomicValue = GotoLoop - - OpcodeBits = 8'u32 - OpcodeMask = (1'u32 shl OpcodeBits) - 1'u32 - - ValueProducingAtoms = {ImmediateVal, IntVal, StrVal, SymUse, NilVal} - - ValueProducing* = { - ImmediateVal, - IntVal, - StrVal, - SymUse, - NilVal, - ModuleSymUse, - ArrayConstr, - ObjConstr, - CheckedAdd, - CheckedSub, - CheckedMul, - CheckedDiv, - CheckedMod, - Add, - Sub, - Mul, - Div, - Mod, - BitShl, - BitShr, - BitAnd, - BitOr, - BitXor, - BitNot, - BoolNot, - Eq, - Le, - Lt, - Cast, - NumberConv, - CheckedObjConv, - ObjConv, - AddrOf, - Load, - ArrayAt, - DerefArrayAt, - FieldAt, - DerefFieldAt, - TestOf - } - -type - Instr* = object # 8 bytes - x: uint32 - info*: PackedLineInfo - -template kind*(n: Instr): Opcode = Opcode(n.x and OpcodeMask) -template operand(n: Instr): uint32 = (n.x shr OpcodeBits) - -template rawOperand*(n: Instr): uint32 = (n.x shr OpcodeBits) - -template toX(k: Opcode; operand: uint32): uint32 = - uint32(k) or (operand shl OpcodeBits) - -template toX(k: Opcode; operand: LitId): uint32 = - uint32(k) or (operand.uint32 shl OpcodeBits) - -type - Tree* = object - nodes: seq[Instr] - - Values* = object - numbers: BiTable[int64] - strings: BiTable[string] - -type - PatchPos* = distinct int - NodePos* = distinct int - -const - InvalidPatchPos* = PatchPos(-1) - -proc isValid(p: PatchPos): bool {.inline.} = p.int != -1 - -proc prepare*(tree: var Tree; info: PackedLineInfo; kind: Opcode): PatchPos = - result = PatchPos tree.nodes.len - tree.nodes.add Instr(x: toX(kind, 1'u32), info: info) - -proc isAtom(tree: Tree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue -proc isAtom(tree: Tree; pos: NodePos): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue - -proc patch*(tree: var Tree; pos: PatchPos) = - let pos = pos.int - let k = tree.nodes[pos].kind - assert k > LastAtomicValue - let distance = int32(tree.nodes.len - pos) - assert distance > 0 - tree.nodes[pos].x = toX(k, cast[uint32](distance)) - -template build*(tree: var Tree; info: PackedLineInfo; kind: Opcode; body: untyped) = - let pos = prepare(tree, info, kind) - body - patch(tree, pos) - -template buildTyped*(tree: var Tree; info: PackedLineInfo; kind: Opcode; typ: TypeId; body: untyped) = - let pos = prepare(tree, info, kind) - tree.addTyped info, typ - body - patch(tree, pos) - -proc len*(tree: Tree): int {.inline.} = tree.nodes.len - -template rawSpan(n: Instr): int = int(operand(n)) - -proc nextChild(tree: Tree; pos: var int) {.inline.} = - if tree.nodes[pos].kind > LastAtomicValue: - assert tree.nodes[pos].operand > 0'u32 - inc pos, tree.nodes[pos].rawSpan - else: - inc pos - -proc next*(tree: Tree; pos: var NodePos) {.inline.} = nextChild tree, int(pos) - -template firstSon*(n: NodePos): NodePos = NodePos(n.int+1) - -template skipTyped*(n: NodePos): NodePos = NodePos(n.int+2) - -iterator sons*(tree: Tree; n: NodePos): NodePos = - var pos = n.int - assert tree.nodes[pos].kind > LastAtomicValue - let last = pos + tree.nodes[pos].rawSpan - inc pos - while pos < last: - 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 - -iterator sonsFromN*(tree: Tree; n: NodePos; toSkip = 2): NodePos = - var pos = n.int - assert tree.nodes[pos].kind > LastAtomicValue - let last = pos + tree.nodes[pos].rawSpan - inc pos - for i in 1..toSkip: - nextChild tree, pos - while pos < last: - yield NodePos pos - nextChild tree, pos - -template `[]`*(t: Tree; n: NodePos): Instr = t.nodes[n.int] - -iterator sonsRest*(tree: Tree; parent, n: NodePos): NodePos = - var pos = n.int - assert tree[parent].kind > LastAtomicValue - let last = parent.int + tree[parent].rawSpan - while pos < last: - yield NodePos pos - nextChild tree, pos - -proc span(tree: Tree; pos: int): int {.inline.} = - if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand) - -proc copyTree*(dest: var Tree; src: Tree) = - let pos = 0 - let L = span(src, pos) - let d = dest.nodes.len - dest.nodes.setLen(d + L) - assert L > 0 - for i in 0..<L: - dest.nodes[d+i] = src.nodes[pos+i] - -proc sons2*(tree: Tree; n: NodePos): (NodePos, NodePos) {.inline.} = - 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) {.inline.} = - 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 sons4*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos, NodePos) {.inline.} = - assert(not isAtom(tree, n.int)) - let a = n.int+1 - let b = a + span(tree, a) - let c = b + span(tree, b) - let d = c + span(tree, c) - result = (NodePos a, NodePos b, NodePos c, NodePos d) - -proc sons5*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos, NodePos, NodePos) {.inline.} = - assert(not isAtom(tree, n.int)) - let a = n.int+1 - let b = a + span(tree, a) - let c = b + span(tree, b) - let d = c + span(tree, c) - let e = d + span(tree, d) - result = (NodePos a, NodePos b, NodePos c, NodePos d, NodePos e) - -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 - -proc newLabels*(labelGen: var int; n: int): LabelId {.inline.} = - result = LabelId labelGen - inc labelGen, n - -proc addNewLabel*(t: var Tree; labelGen: var int; info: PackedLineInfo; k: Opcode): LabelId = - assert k in {Label, LoopLabel} - result = LabelId labelGen - t.nodes.add Instr(x: toX(k, uint32(result)), info: info) - inc labelGen - -proc gotoLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) = - assert k in {Goto, GotoLoop, CheckedGoto} - t.nodes.add Instr(x: toX(k, uint32(L)), info: info) - -proc addLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) {.inline.} = - assert k in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto} - t.nodes.add Instr(x: toX(k, uint32(L)), info: info) - -proc addSymUse*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} = - t.nodes.add Instr(x: toX(SymUse, uint32(s)), info: info) - -proc addSymDef*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} = - t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info) - -proc addNop*(t: var Tree; info: PackedLineInfo) {.inline.} = - t.nodes.add Instr(x: toX(Nop, 0'u32), info: info) - -proc addTyped*(t: var Tree; info: PackedLineInfo; typ: TypeId) {.inline.} = - assert typ.int >= 0 - t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info) - -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, 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) - patch t, x - -proc addImmediateVal*(t: var Tree; info: PackedLineInfo; x: int) = - assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int) - t.nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info) - -proc addPragmaId*(t: var Tree; info: PackedLineInfo; x: PragmaKey) = - t.nodes.add Instr(x: toX(PragmaId, uint32(x)), info: info) - -proc addIntVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; typ: TypeId; x: int64) = - buildTyped t, info, NumberConv, typ: - t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(x))), info: info) - -proc boolVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; b: bool) = - buildTyped t, info, NumberConv, Bool8Id: - t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(ord b))), info: info) - -proc addStrVal*(t: var Tree; strings: var BiTable[string]; info: PackedLineInfo; s: string) = - t.nodes.add Instr(x: toX(StrVal, uint32(strings.getOrIncl(s))), info: info) - -proc addStrLit*(t: var Tree; info: PackedLineInfo; s: LitId) = - t.nodes.add Instr(x: toX(StrVal, uint32(s)), info: info) - -proc addNilVal*(t: var Tree; info: PackedLineInfo; typ: TypeId) = - buildTyped t, info, NumberConv, typ: - t.nodes.add Instr(x: toX(NilVal, uint32(0)), info: info) - -proc store*(r: var RodFile; t: Tree) = storeSeq r, t.nodes -proc load*(r: var RodFile; t: var Tree) = loadSeq r, t.nodes - -proc escapeToNimLit*(s: string; result: var string) = - result.add '"' - for c in items s: - if c < ' ' or int(c) >= 128: - result.add '\\' - result.addInt int(c) - elif c == '\\': - result.add r"\\" - elif c == '\n': - result.add r"\n" - elif c == '\r': - result.add r"\r" - elif c == '\t': - result.add r"\t" - else: - 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 ' ' - - case t[pos].kind - of Nop: r.add "Nop" - of ImmediateVal: - r.add $t[pos].operand - of IntVal: - r.add "IntVal " - r.add $integers[LitId t[pos].operand] - of StrVal: - escapeToNimLit(strings[LitId t[pos].operand], r) - of SymDef: - r.add "SymDef " - r.add localName(SymId t[pos].operand) - of SymUse: - r.add "SymUse " - r.add localName(SymId t[pos].operand) - of PragmaId: - r.add $cast[PragmaKey](t[pos].operand) - of Typed: - r.add "T<" - r.add $t[pos].operand - r.add ">" - of NilVal: - r.add "NilVal" - of Label: - # 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 - r.add " L" - r.add $t[pos].operand - else: - r.add $t[pos].kind - r.add "{\n" - for i in 0..<(nesting+1)*2: r.add ' ' - for p in sons(t, pos): - 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, names, r - nextChild t, i - -type - Value* = distinct Tree - -proc prepare*(dest: var Value; info: PackedLineInfo; k: Opcode): PatchPos {.inline.} = - assert k in ValueProducing - ValueProducingAtoms - result = prepare(Tree(dest), info, k) - -proc patch*(dest: var Value; pos: PatchPos) {.inline.} = - patch(Tree(dest), pos) - -proc localToValue*(info: PackedLineInfo; s: SymId): Value = - result = Value(Tree()) - Tree(result).addSymUse info, s - -proc hasValue*(v: Value): bool {.inline.} = Tree(v).len > 0 - -proc isEmpty*(v: Value): bool {.inline.} = Tree(v).len == 0 - -proc extractTemp*(v: Value): SymId = - if hasValue(v) and Tree(v)[NodePos 0].kind == SymUse: - result = SymId(Tree(v)[NodePos 0].operand) - else: - result = SymId(-1) - -proc copyTree*(dest: var Tree; src: Value) = copyTree dest, Tree(src) - -proc addImmediateVal*(t: var Value; info: PackedLineInfo; x: int) = - assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int) - Tree(t).nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info) - -template build*(tree: var Value; info: PackedLineInfo; kind: Opcode; body: untyped) = - let pos = prepare(Tree(tree), info, kind) - body - patch(tree, pos) - -proc addTyped*(t: var Value; info: PackedLineInfo; typ: TypeId) {.inline.} = - addTyped(Tree(t), info, typ) - -template buildTyped*(tree: var Value; info: PackedLineInfo; kind: Opcode; typ: TypeId; body: untyped) = - let pos = prepare(tree, info, kind) - tree.addTyped info, typ - body - patch(tree, pos) - -proc addStrVal*(t: var Value; strings: var BiTable[string]; info: PackedLineInfo; s: string) = - addStrVal(Tree(t), strings, info, s) - -proc addNilVal*(t: var Value; info: PackedLineInfo; typ: TypeId) = - addNilVal Tree(t), info, typ - -proc addIntVal*(t: var Value; integers: var BiTable[int64]; info: PackedLineInfo; typ: TypeId; x: int64) = - addIntVal Tree(t), integers, info, typ, x diff --git a/compiler/nir/nirslots.nim b/compiler/nir/nirslots.nim deleted file mode 100644 index a01e7a633..000000000 --- a/compiler/nir/nirslots.nim +++ /dev/null @@ -1,104 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2023 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Management of slots. Similar to "register allocation" -## in lower level languages. - -import std / [assertions, tables] -import nirtypes, nirinsts - -type - SlotManagerFlag* = enum - ReuseTemps, - ReuseVars - SlotKind* = enum - Temp, Perm - SlotManager* = object # "register allocator" - live: Table[SymId, (SlotKind, TypeId)] - dead: Table[TypeId, seq[SymId]] - flags: set[SlotManagerFlag] - inScope: seq[SymId] - -proc initSlotManager*(flags: set[SlotManagerFlag]): SlotManager {.inline.} = - SlotManager(flags: flags) - -proc allocRaw(m: var SlotManager; t: TypeId; f: SlotManagerFlag; k: SlotKind; - symIdgen: var int32): SymId {.inline.} = - if f in m.flags and m.dead.hasKey(t) and m.dead[t].len > 0: - result = m.dead[t].pop() - else: - inc symIdgen - result = SymId(symIdgen) - m.inScope.add result - m.live[result] = (k, t) - -proc allocTemp*(m: var SlotManager; t: TypeId; symIdgen: var int32): SymId {.inline.} = - result = allocRaw(m, t, ReuseTemps, Temp, symIdgen) - -proc allocVar*(m: var SlotManager; t: TypeId; symIdgen: var int32): SymId {.inline.} = - result = allocRaw(m, t, ReuseVars, Perm, symIdgen) - -proc freeLoc*(m: var SlotManager; s: SymId) = - let t = m.live.getOrDefault(s) - assert t[1].int != 0 - m.live.del s - m.dead.mgetOrPut(t[1], @[]).add s - -proc freeTemp*(m: var SlotManager; s: SymId) = - let t = m.live.getOrDefault(s) - if t[1].int != 0 and t[0] == Temp: - m.live.del s - m.dead.mgetOrPut(t[1], @[]).add s - -iterator stillAlive*(m: SlotManager): (SymId, TypeId) = - for k, v in pairs(m.live): - yield (k, v[1]) - -proc getType*(m: SlotManager; s: SymId): TypeId {.inline.} = m.live[s][1] - -proc openScope*(m: var SlotManager) = - m.inScope.add SymId(-1) # add marker - -proc closeScope*(m: var SlotManager) = - var i = m.inScope.len - 1 - while i >= 0: - if m.inScope[i] == SymId(-1): - m.inScope.setLen i - break - dec i - -when isMainModule: - var symIdgen: int32 - var m = initSlotManager({ReuseTemps}) - - var g = initTypeGraph(Literals()) - - let a = g.openType ArrayTy - g.addBuiltinType Int8Id - g.addArrayLen 5 - let finalArrayType = finishType(g, a) - - let obj = g.openType ObjectDecl - g.addName "MyType" - - g.addField "p", finalArrayType, 0 - let objB = finishType(g, obj) - - let x = m.allocTemp(objB, symIdgen) - assert x.int == 0 - - let y = m.allocTemp(objB, symIdgen) - assert y.int == 1 - - let z = m.allocTemp(Int8Id, symIdgen) - assert z.int == 2 - - m.freeLoc y - let y2 = m.allocTemp(objB, symIdgen) - assert y2.int == 1 diff --git a/compiler/nir/nirtypes.nim b/compiler/nir/nirtypes.nim deleted file mode 100644 index a79bf6d01..000000000 --- a/compiler/nir/nirtypes.nim +++ /dev/null @@ -1,475 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2023 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Type system for NIR. Close to C's type system but without its quirks. - -import std / [assertions, hashes] -import .. / ic / [bitabs, rodfiles] - -type - NirTypeKind* = enum - VoidTy, IntTy, UIntTy, FloatTy, BoolTy, CharTy, NameVal, - IntVal, SizeVal, AlignVal, OffsetVal, - AnnotationVal, - ObjectTy, - UnionTy, - VarargsTy, # the `...` in a C prototype; also the last "atom" - APtrTy, # pointer to aliasable memory - UPtrTy, # pointer to unique/unaliasable memory - AArrayPtrTy, # pointer to array of aliasable memory - UArrayPtrTy, # pointer to array of unique/unaliasable memory - ArrayTy, - LastArrayTy, # array of unspecified size as a last field inside an object - ProcTy, - ObjectDecl, - UnionDecl, - FieldDecl - -const - TypeKindBits = 8'u32 - TypeKindMask = (1'u32 shl TypeKindBits) - 1'u32 - -type - TypeNode* = object # 4 bytes - x: uint32 - -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) - -template toX(k: NirTypeKind; operand: LitId): uint32 = - uint32(k) or (operand.uint32 shl TypeKindBits) - -type - TypeId* = distinct int - -proc `==`*(a, b: TypeId): bool {.borrow.} -proc hash*(a: TypeId): Hash {.borrow.} - -type - Literals* = ref object - strings*: BiTable[string] - numbers*: BiTable[int64] - - TypeGraph* = object - nodes: seq[TypeNode] - lit: Literals - -const - VoidId* = TypeId 0 - Bool8Id* = TypeId 1 - Char8Id* = TypeId 2 - Int8Id* = TypeId 3 - Int16Id* = TypeId 4 - Int32Id* = TypeId 5 - Int64Id* = TypeId 6 - UInt8Id* = TypeId 7 - UInt16Id* = TypeId 8 - UInt32Id* = TypeId 9 - UInt64Id* = TypeId 10 - Float32Id* = TypeId 11 - Float64Id* = TypeId 12 - VoidPtrId* = TypeId 13 - LastBuiltinId* = 13 - -proc initTypeGraph*(lit: Literals): TypeGraph = - result = TypeGraph(nodes: @[ - TypeNode(x: toX(VoidTy, 0'u32)), - TypeNode(x: toX(BoolTy, 8'u32)), - TypeNode(x: toX(CharTy, 8'u32)), - TypeNode(x: toX(IntTy, 8'u32)), - TypeNode(x: toX(IntTy, 16'u32)), - TypeNode(x: toX(IntTy, 32'u32)), - TypeNode(x: toX(IntTy, 64'u32)), - TypeNode(x: toX(UIntTy, 8'u32)), - TypeNode(x: toX(UIntTy, 16'u32)), - TypeNode(x: toX(UIntTy, 32'u32)), - TypeNode(x: toX(UIntTy, 64'u32)), - TypeNode(x: toX(FloatTy, 32'u32)), - TypeNode(x: toX(FloatTy, 64'u32)), - TypeNode(x: toX(APtrTy, 2'u32)), - TypeNode(x: toX(VoidTy, 0'u32)) - ], lit: lit) - assert result.nodes.len == LastBuiltinId+2 - -type - TypePatchPos* = distinct int - -const - InvalidTypePatchPos* = TypePatchPos(-1) - LastAtomicValue = VarargsTy - -proc isValid(p: TypePatchPos): bool {.inline.} = p.int != -1 - -proc prepare(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos = - result = TypePatchPos tree.nodes.len - tree.nodes.add TypeNode(x: toX(kind, 1'u32)) - -proc isAtom(tree: TypeGraph; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue -proc isAtom(tree: TypeGraph; pos: TypeId): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue - -proc patch(tree: var TypeGraph; pos: TypePatchPos) = - let pos = pos.int - let k = tree.nodes[pos].kind - assert k > LastAtomicValue - let distance = int32(tree.nodes.len - pos) - assert distance > 0 - tree.nodes[pos].x = toX(k, cast[uint32](distance)) - -proc len*(tree: TypeGraph): int {.inline.} = tree.nodes.len - -template rawSpan(n: TypeNode): int = int(operand(n)) - -proc nextChild(tree: TypeGraph; pos: var int) {.inline.} = - if tree.nodes[pos].kind > LastAtomicValue: - assert tree.nodes[pos].operand > 0'u32 - inc pos, tree.nodes[pos].rawSpan - else: - inc pos - -iterator sons*(tree: TypeGraph; n: TypeId): TypeId = - var pos = n.int - assert tree.nodes[pos].kind > LastAtomicValue - let last = pos + tree.nodes[pos].rawSpan - inc pos - while pos < last: - yield TypeId pos - nextChild tree, pos - -template `[]`*(t: TypeGraph; n: TypeId): TypeNode = t.nodes[n.int] - -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.} = - if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand) - -proc sons2(tree: TypeGraph; n: TypeId): (TypeId, TypeId) = - assert(not isAtom(tree, n.int)) - let a = n.int+1 - let b = a + span(tree, a) - result = (TypeId a, TypeId b) - -proc sons3(tree: TypeGraph; n: TypeId): (TypeId, TypeId, TypeId) = - assert(not isAtom(tree, n.int)) - let a = n.int+1 - let b = a + span(tree, a) - let c = b + span(tree, b) - result = (TypeId a, TypeId b, TypeId c) - -proc arrayName*(tree: TypeGraph; n: TypeId): TypeId {.inline.} = - assert tree[n].kind == ArrayTy - let (_, _, c) = sons3(tree, n) - result = c - -proc arrayLen*(tree: TypeGraph; n: TypeId): BiggestInt = - assert tree[n].kind == ArrayTy - let (_, b) = sons2(tree, n) - result = tree.lit.numbers[LitId tree[b].operand] - -proc returnType*(tree: TypeGraph; n: TypeId): (TypeId, TypeId) = - # Returns the positions of the return type + calling convention. - var pos = n.int - assert tree.nodes[pos].kind == ProcTy - let a = n.int+1 - let b = a + span(tree, a) - result = (TypeId b, TypeId a) # not a typo, order is reversed - -iterator params*(tree: TypeGraph; n: TypeId): TypeId = - var pos = n.int - assert tree.nodes[pos].kind == ProcTy - let last = pos + tree.nodes[pos].rawSpan - inc pos - nextChild tree, pos - nextChild tree, pos - while pos < last: - yield TypeId pos - nextChild tree, pos - -proc openType*(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos = - assert kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, - ArrayTy, LastArrayTy, ProcTy, ObjectDecl, UnionDecl, - FieldDecl} - result = prepare(tree, kind) - -template typeInvariant(p: TypePatchPos) = - when false: - if tree[TypeId(p)].kind == FieldDecl: - var k = 0 - for ch in sons(tree, TypeId(p)): - inc k - assert k > 2, "damn! " & $k - -proc sealType*(tree: var TypeGraph; p: TypePatchPos) = - patch tree, p - typeInvariant(p) - -proc finishType*(tree: var TypeGraph; p: TypePatchPos): TypeId = - # Search for an existing instance of this type in - # order to reduce memory consumption: - patch tree, p - typeInvariant(p) - - let s = span(tree, p.int) - var i = 0 - while i < p.int: - if tree.nodes[i].x == tree.nodes[p.int].x: - var isMatch = true - for j in 1..<s: - if tree.nodes[j+i].x == tree.nodes[j+p.int].x: - discard "still a match" - else: - isMatch = false - break - if isMatch: - if p.int+s == tree.len: - setLen tree.nodes, p.int - return TypeId(i) - nextChild tree, i - result = TypeId(p) - -proc nominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string): TypeId = - assert kind in {ObjectTy, UnionTy} - let content = TypeNode(x: toX(kind, tree.lit.strings.getOrIncl(name))) - for i in 0..<tree.len: - if tree.nodes[i].x == content.x: - return TypeId(i) - result = TypeId tree.nodes.len - tree.nodes.add content - -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)) - -proc getFloat128Type*(tree: var TypeGraph): TypeId = - result = TypeId tree.nodes.len - tree.nodes.add TypeNode(x: toX(FloatTy, 128'u32)) - -proc addBuiltinType*(g: var TypeGraph; id: TypeId) = - g.nodes.add g[id] - -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: - if g[t].kind in {ObjectDecl, UnionDecl}: - assert g[t.firstSon].kind == NameVal - let name = LitId g[t.firstSon].operand - if g[t].kind == ObjectDecl: - g.nodes.add TypeNode(x: toX(ObjectTy, name)) - else: - g.nodes.add TypeNode(x: toX(UnionTy, name)) - else: - let pos = t.int - let L = span(g, pos) - let d = g.nodes.len - g.nodes.setLen(d + L) - assert L > 0 - for i in 0..<L: - g.nodes[d+i] = g.nodes[pos+i] - -proc addArrayLen*(g: var TypeGraph; len: int64) = - g.nodes.add TypeNode(x: toX(IntVal, g.lit.numbers.getOrIncl(len))) - -proc addSize*(g: var TypeGraph; s: int64) = - g.nodes.add TypeNode(x: toX(SizeVal, g.lit.numbers.getOrIncl(s))) - -proc addOffset*(g: var TypeGraph; offset: int64) = - g.nodes.add TypeNode(x: toX(OffsetVal, g.lit.numbers.getOrIncl(offset))) - -proc addAlign*(g: var TypeGraph; a: int64) = - g.nodes.add TypeNode(x: toX(AlignVal, g.lit.numbers.getOrIncl(a))) - -proc addName*(g: var TypeGraph; name: string) = - g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl(name))) - -proc addAnnotation*(g: var TypeGraph; name: string) = - g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl(name))) - -proc addField*(g: var TypeGraph; name: string; typ: TypeId; offset: int64) = - let f = g.openType FieldDecl - g.addType typ - g.addOffset offset - g.addName name - sealType(g, f) - -proc ptrTypeOf*(g: var TypeGraph; t: TypeId): TypeId = - let f = g.openType APtrTy - g.addType t - result = finishType(g, f) - -proc arrayPtrTypeOf*(g: var TypeGraph; t: TypeId): TypeId = - let f = g.openType AArrayPtrTy - g.addType t - result = finishType(g, f) - -proc store*(r: var RodFile; g: TypeGraph) = - storeSeq r, g.nodes - -proc load*(r: var RodFile; g: var TypeGraph) = - loadSeq r, g.nodes - -proc toString*(dest: var string; g: TypeGraph; i: TypeId) = - case g[i].kind - of VoidTy: dest.add "void" - of IntTy: - dest.add "i" - dest.addInt g[i].operand - of UIntTy: - dest.add "u" - dest.addInt g[i].operand - of FloatTy: - dest.add "f" - dest.addInt g[i].operand - of BoolTy: - dest.add "b" - dest.addInt g[i].operand - of CharTy: - dest.add "c" - dest.addInt g[i].operand - of NameVal, AnnotationVal: - dest.add g.lit.strings[LitId g[i].operand] - of IntVal, SizeVal, AlignVal, OffsetVal: - dest.add $g[i].kind - dest.add ' ' - dest.add $g.lit.numbers[LitId g[i].operand] - of VarargsTy: - dest.add "..." - of APtrTy: - dest.add "aptr[" - toString(dest, g, g.elementType(i)) - dest.add "]" - of UPtrTy: - dest.add "uptr[" - toString(dest, g, g.elementType(i)) - dest.add "]" - of AArrayPtrTy: - dest.add "aArrayPtr[" - toString(dest, g, g.elementType(i)) - dest.add "]" - of UArrayPtrTy: - dest.add "uArrayPtr[" - toString(dest, g, g.elementType(i)) - dest.add "]" - of ArrayTy: - dest.add "Array[" - let (elems, len, name) = g.sons3(i) - toString(dest, g, elems) - dest.add ", " - toString(dest, g, len) - dest.add ", " - toString(dest, g, name) - dest.add "]" - of LastArrayTy: - # array of unspecified size as a last field inside an object - dest.add "LastArrayTy[" - toString(dest, g, g.elementType(i)) - dest.add "]" - of ObjectTy: - dest.add "object " - dest.add g.lit.strings[LitId g[i].operand] - of UnionTy: - dest.add "union " - dest.add g.lit.strings[LitId g[i].operand] - of ProcTy: - dest.add "proc[" - for t in sons(g, i): - dest.add ' ' - toString(dest, g, t) - dest.add "]" - of ObjectDecl: - dest.add "object[" - for t in sons(g, i): - toString(dest, g, t) - dest.add '\n' - dest.add "]" - of UnionDecl: - dest.add "union[" - for t in sons(g, i): - toString(dest, g, t) - dest.add '\n' - dest.add "]" - of FieldDecl: - dest.add "field[" - for t in sons(g, i): - toString(dest, g, t) - dest.add ' ' - dest.add "]" - - when false: - let (typ, offset, name) = g.sons3(i) - toString(dest, g, typ) - dest.add ' ' - toString(dest, g, offset) - dest.add ' ' - toString(dest, g, name) - -proc toString*(dest: var string; g: TypeGraph) = - var i = 0 - while i < g.len: - dest.add "T<" - dest.addInt i - dest.add "> " - toString(dest, g, TypeId i) - 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 - -iterator allTypesIncludingInner*(g: TypeGraph; start = 0): TypeId = - var i = start - while i < g.len: - yield TypeId i - inc i - -proc `$`(g: TypeGraph): string = - result = "" - toString(result, g) - -when isMainModule: - var g = initTypeGraph(Literals()) - - let a = g.openType ArrayTy - g.addBuiltinType Int8Id - g.addArrayLen 5 - g.addName "SomeArray" - let finalArrayType = finishType(g, a) - - let obj = g.openType ObjectDecl - g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl("MyType"))) - - g.addField "p", finalArrayType, 0 - sealType(g, obj) - - echo g diff --git a/compiler/nir/nirvm.nim b/compiler/nir/nirvm.nim deleted file mode 100644 index faa7a1fb7..000000000 --- a/compiler/nir/nirvm.nim +++ /dev/null @@ -1,1175 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2023 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -##[ NIR is a little too high level to interpret it efficiently. Thus -we compute `addresses` for SymIds, labels and offsets for object fields -in a preprocessing step. - -We also split the instruction stream into separate (code, debug) seqs while -we're at it. -]## - -import std / [syncio, assertions, tables, intsets] -import ".." / ic / bitabs -import nirinsts, nirtypes, nirfiles, nirlineinfos - -type - OpcodeM = enum - ImmediateValM, - IntValM, - StrValM, - LoadLocalM, # with local ID - LoadGlobalM, - LoadProcM, - TypedM, # with type ID - PragmaIdM, # with Pragma ID, possible values: see PragmaKey enum - NilValM, - AllocLocals, - SummonParamM, - GotoM, - CheckedGotoM, # last atom - - ArrayConstrM, - ObjConstrM, - RetM, - YldM, - - SelectM, - SelectPairM, # ((values...), Label) - SelectListM, # (values...) - SelectValueM, # (value) - SelectRangeM, # (valueA..valueB) - - AddrOfM, - ArrayAtM, # (elemSize, addr(a), i) - DerefArrayAtM, - FieldAtM, # addr(obj.field) - DerefFieldAtM, - - LoadM, # a[] - AsgnM, # a = b - StoreM, # a[] = b - SetExcM, - TestExcM, - - CheckedRangeM, - CheckedIndexM, - - CallM, - CheckedAddM, # with overflow checking etc. - CheckedSubM, - CheckedMulM, - CheckedDivM, - CheckedModM, - AddM, - SubM, - MulM, - DivM, - ModM, - BitShlM, - BitShrM, - BitAndM, - BitOrM, - BitXorM, - BitNotM, - BoolNotM, - EqM, - LeM, - LtM, - CastM, - NumberConvM, - CheckedObjConvM, - ObjConvM, - TestOfM, - ProcDeclM, - PragmaPairM - -const - LastAtomicValue = CheckedGotoM - - OpcodeBits = 8'u32 - OpcodeMask = (1'u32 shl OpcodeBits) - 1'u32 - -type - Instr = distinct uint32 - -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)) - -template toIns(k: OpcodeM; operand: LitId): Instr = - Instr(uint32(k) or (operand.uint32 shl OpcodeBits)) - -type - NimStrPayloadVM = object - cap: int - data: UncheckedArray[char] - NimStringVM = object - len: int - p: ptr NimStrPayloadVM - -const - GlobalsSize = 1024*24 - -type - PatchPos = distinct int - CodePos = distinct int - - Bytecode* = object - code: seq[Instr] - debug: seq[PackedLineInfo] - m: ref NirModule - procs: Table[SymId, CodePos] - globals: Table[SymId, (uint32, int)] - strings: Table[LitId, NimStringVM] - 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]] - interactive*: bool - - Universe* = object ## all units: For interpretation we need that - units: seq[Bytecode] - unitNames: Table[string, int] - current: int - -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 - -proc debug(bc: Bytecode; t: Tree; n: NodePos) = - var buf = "" - toString(t, n, bc.m.lit.strings, bc.m.lit.numbers, bc.m.symnames, buf) - echo buf - -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 = int(b.m.lit.numbers[b.m.types[y].litId]) - break - b.offsets.mgetOrPut(offsetKey, @[]).add (offset, x.firstSon) - of SizeVal: - size = int(b.m.lit.numbers[b.m.types[x].litId]) - of AlignVal: - align = int(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) - -proc isValid(p: PatchPos): bool {.inline.} = p.int != -1 - -proc prepare(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM): PatchPos = - result = PatchPos bc.code.len - bc.code.add toIns(kind, 1'u32) - bc.debug.add info - -proc add(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; raw: uint32) = - bc.code.add toIns(kind, raw) - bc.debug.add info - -proc add(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; lit: LitId) = - 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 - -proc patch(bc: var Bytecode; pos: PatchPos) = - let pos = pos.int - let k = bc.code[pos].kind - assert k > LastAtomicValue - let distance = int32(bc.code.len - pos) - assert distance > 0 - bc.code[pos] = toIns(k, cast[uint32](distance)) - -template build(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; body: untyped) = - let pos = prepare(bc, info, kind) - body - patch(bc, pos) - -proc len*(bc: Bytecode): int {.inline.} = bc.code.len - -template rawSpan(n: Instr): int = int(operand(n)) - -proc nextChild(bc: Bytecode; pos: var int) {.inline.} = - if bc.code[pos].kind > LastAtomicValue: - assert bc.code[pos].operand > 0'u32 - inc pos, bc.code[pos].rawSpan - 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 - let last = pos + bc.code[pos].rawSpan - inc pos - while pos < last: - yield CodePos pos - nextChild bc, pos - -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 - -proc toString*(t: Bytecode; pos: CodePos; - r: var string; nesting = 0) = - if r.len > 0 and r[r.len-1] notin {' ', '\n', '(', '[', '{'}: - r.add ' ' - - case t[pos].kind - of ImmediateValM: - r.add $t[pos].operand - of IntValM: - r.add "IntVal " - r.add $t.m.lit.numbers[LitId t[pos].operand] - of StrValM: - escapeToNimLit(t.m.lit.strings[LitId t[pos].operand], r) - of LoadLocalM, LoadGlobalM, LoadProcM, AllocLocals, SummonParamM: - r.add $t[pos].kind - r.add ' ' - r.add $t[pos].operand - of PragmaIdM: - r.add $cast[PragmaKey](t[pos].operand) - of TypedM: - r.add "T<" - r.add $t[pos].operand - r.add ">" - of NilValM: - r.add "NilVal" - of GotoM, CheckedGotoM: - r.add $t[pos].kind - r.add " L" - r.add $t[pos].operand - else: - r.add $t[pos].kind - r.add "{\n" - for i in 0..<(nesting+1)*2: r.add ' ' - for p in sons(t, pos): - toString t, p, r, nesting+1 - r.add "\n" - for i in 0..<nesting*2: r.add ' ' - r.add "}" - -proc debug(b: Bytecode; pos: CodePos) = - var buf = "" - toString(b, pos, buf) - echo buf - -type - Preprocessing = object - u: ref Universe - known: Table[LabelId, CodePos] - toPatch: Table[LabelId, seq[CodePos]] - locals: Table[SymId, (uint32, int)] # address, size - thisModule: uint32 - localsAddr: uint32 - markedWithLabel: IntSet - -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: - bc.add info, opc, uint32 dest - else: - let here = CodePos(bc.code.len) - c.toPatch.mgetOrPut(lab, @[]).add here - bc.add info, opc, 1u32 # will be patched once we traversed the label - -type - AddrMode = enum - InDotExpr, WantAddr - -template maybeDeref(doDeref: bool; size: int; body: untyped) = - var pos = PatchPos(-1) - if doDeref: - pos = prepare(bc, info, LoadM) - bc.add info, ImmediateValM, uint32 size - body - if doDeref: - patch(bc, pos) - -proc toReadonlyString(s: string): NimStringVM = - if s.len == 0: - result = NimStringVM(len: 0, p: nil) - else: - result = NimStringVM(len: s.len, p: cast[ptr NimStrPayloadVM](alloc(s.len+1+sizeof(int)))) - copyMem(addr result.p.data[0], addr s[0], s.len+1) - result.p.cap = s.len or (1 shl (8 * 8 - 2)) # see also NIM_STRLIT_FLAG - -const - ForwardedProc = 10_000_000'u32 - -proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; flags: set[AddrMode]) = - let info = t[n].info - - template recurse(opc) = - build bc, info, opc: - for ch in sons(t, n): preprocess(c, bc, t, ch, {WantAddr}) - - case t[n].kind - of Nop, ForeignDecl, ForeignProcDecl: - discard "don't use Nop" - of ImmediateVal: - bc.add info, ImmediateValM, t[n].rawOperand - of IntVal: - bc.add info, IntValM, t[n].rawOperand - of StrVal: - let litId = LitId t[n].rawOperand - if not bc.strings.hasKey(litId): - bc.strings[litId] = toReadonlyString(bc.m.lit.strings[litId]) - bc.add info, StrValM, t[n].rawOperand - of SymDef: - 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): - let (address, size) = c.locals[s] - maybeDeref(WantAddr notin flags, size): - bc.add info, LoadLocalM, address - elif bc.procs.hasKey(s): - bc.add info, LoadProcM, uint32 bc.procs[s] - elif bc.globals.hasKey(s): - let (address, size) = bc.globals[s] - maybeDeref(WantAddr notin flags, size): - bc.add info, LoadGlobalM, address - else: - 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: - 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: - bc.add info, TypedM, t[n].rawOperand - of PragmaId: - bc.add info, PragmaIdM, t[n].rawOperand - of NilVal: - bc.add info, NilValM, t[n].rawOperand - of LoopLabel, Label: - let lab = t[n].label - let here = CodePos(bc.code.len) - c.known[lab] = here - var p: seq[CodePos] = @[] - if c.toPatch.take(lab, p): - 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(bc, info, t[n].label, GotoM) - of CheckedGoto: - c.genGoto(bc, info, t[n].label, CheckedGotoM) - of ArrayConstr: - 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: - #debug bc, t, n - 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: - recurse YldM - of Select: - recurse SelectM - of SelectPair: - recurse SelectPairM - of SelectList: - recurse SelectListM - of SelectValue: - recurse SelectValueM - of SelectRange: - recurse SelectRangeM - of SummonGlobal, SummonThreadLocal, SummonConst: - 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, size) - 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, size) - 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, size) - 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: - 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: - let (arrayType, a, i) = sons3(t, n) - let tid = t[arrayType].typeId - let size = uint32 computeElemSize(bc, tid) - build bc, info, ArrayAtM: - bc.add info, ImmediateValM, size - preprocess(c, bc, t, a, {WantAddr}) - preprocess(c, bc, t, i, {WantAddr}) - of DerefArrayAt: - let (arrayType, a, i) = sons3(t, n) - let tid = t[arrayType].typeId - let size = uint32 computeElemSize(bc, tid) - build bc, info, DerefArrayAtM: - bc.add info, ImmediateValM, size - preprocess(c, bc, t, a, {WantAddr}) - preprocess(c, bc, t, i, {WantAddr}) - of FieldAt: - let (typ, a, b) = sons3(t, n) - 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 DerefFieldAt: - let (typ, a, b) = sons3(t, n) - let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0] - build bc, info, DerefFieldAtM: - preprocess(c, bc, t, a, flags+{WantAddr}) - bc.add info, ImmediateValM, uint32(offset) - of Load: - 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: - raiseAssert "Assumption was that Store is unused!" - of Asgn: - 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, src.skipTyped, {WantAddr}) - preprocess(c, bc, t, dest, {WantAddr}) - for ch in sonsFromN(t, src, 2): preprocess(c, bc, t, ch, {WantAddr}) - elif t[src].kind in {CheckedCall, CheckedIndirectCall}: - let (_, gotoInstr, fn) = sons3(t, src) - build bc, info, CallM: - preprocess(c, bc, t, fn, {WantAddr}) - preprocess(c, bc, t, dest, {WantAddr}) - for ch in sonsFromN(t, src, 3): preprocess(c, bc, t, ch, {WantAddr}) - preprocess c, bc, t, gotoInstr, {} - 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: - recurse TestExcM - of CheckedRange: - recurse CheckedRangeM - of CheckedIndex: - recurse CheckedIndexM - 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: - let (_, gotoInstr, fn) = sons3(t, n) - build bc, info, CallM: - preprocess(c, bc, t, fn, {WantAddr}) - for ch in sonsFromN(t, n, 3): preprocess(c, bc, t, ch, {WantAddr}) - preprocess c, bc, t, gotoInstr, {WantAddr} - of CheckedAdd: - recurse CheckedAddM - of CheckedSub: - recurse CheckedSubM - of CheckedMul: - recurse CheckedMulM - of CheckedDiv: - recurse CheckedDivM - of CheckedMod: - recurse CheckedModM - of Add: - recurse AddM - of Sub: - recurse SubM - of Mul: - recurse MulM - of Div: - recurse DivM - of Mod: - recurse ModM - of BitShl: - recurse BitShlM - of BitShr: - recurse BitShrM - of BitAnd: - recurse BitAndM - of BitOr: - recurse BitOrM - of BitXor: - recurse BitXorM - of BitNot: - recurse BitNotM - of BoolNot: - recurse BoolNotM - of Eq: - recurse EqM - of Le: - recurse LeM - of Lt: - recurse LtM - of Cast: - recurse CastM - of NumberConv: - recurse NumberConvM - of CheckedObjConv: - recurse CheckedObjConvM - of ObjConv: - recurse ObjConvM - of TestOf: - recurse TestOfM - of Emit: - raiseAssert "cannot interpret: Emit" - of ProcDecl: - 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) - when false: - if here.int == 39850: - debug bc, t, n - debug bc, here - - of PragmaPair: - recurse PragmaPairM - -const PayloadSize = 128 - -type - StackFrame = ref object - locals: pointer # usually points into `payload` if size is small enough, otherwise it's `alloc`'ed. - 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, u: caller.u) - if size <= PayloadSize: - result.locals = addr(result.payload) - else: - result.locals = alloc0(size) - -proc popStackFrame(s: StackFrame): StackFrame = - 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 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 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.code[pc].operand - of FieldAtM: - let (x, offset) = sons2(c.code, pc) - result = evalAddr(c, x, s) - result = result +! c.code[offset].operand - of DerefFieldAtM: - let (x, offset) = sons2(c.code, pc) - let p = evalAddr(c, x, s) - result = cast[ptr pointer](p)[] +! c.code[offset].operand - of ArrayAtM: - 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 DerefArrayAtM: - let (e, a, i) = sons3(c.code, pc) - let elemSize = c.code[e].operand - var p = evalAddr(c, a, s) - var idx: int = 0 - eval(c, i, s, addr idx, sizeof(int)) - result = cast[ptr pointer](p)[] +! (uint32(idx) * elemSize) - 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 std / 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) - if c.code[values].kind == SelectValueM: - var a = default(typ) - eval c, values.firstSon, s, addr a, sizeof(typ) - if selector == a: - return CodePos c.code[action].operand - else: - assert c.code[values].kind == SelectListM, $c.code[values].kind - 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 src = s.locals +! c.code[pc].operand - copyMem result, src, size - of FieldAtM, DerefFieldAtM, ArrayAtM, DerefArrayAtM, LoadGlobalM: - let src = evalAddr(c, pc, s) - copyMem result, src, size - of LoadProcM: - let procAddr = c.code[pc].operand - cast[ptr pointer](result)[] = cast[pointer](procAddr) - of LoadM: - let (_, arg) = sons2(c.code, pc) - let src = evalAddr(c, arg, s) - copyMem result, src, 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: - # binary compatible and no deep copy required: - copyMem(cast[ptr string](result), addr(c.strings[c[pc].litId]), sizeof(string)) - of ObjConstrM: - for offset, size, val in triples(c, pc): - eval c, val, s, result+!offset, size - of ArrayConstrM: - let elemSize = c.code[pc.firstSon].operand - var r = result - 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 - of Float32Id: impl float32 - of Float64Id: impl float64 - 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: " & $c.m.types[tid].kind - else: - #debug c, c.debug[pc.int] - raiseAssert "cannot happen: " & $c.code[pc].kind - -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; frame: StackFrame) = - var s = default(NimStringVM) - for a in sonsFrom1(c, pc): - assert c[a].kind == ArrayConstrM - let elemSize = c.code[a.firstSon].operand.int - for ch in sonsFrom1(c, a): - eval c, ch, frame, addr s, elemSize - if s.len > 0: - discard stdout.writeBuffer(addr(s.p.data[0]), s.len) - stdout.write "\n" - stdout.flushFile() - -type - EvalBuiltinState = enum - DidNothing, DidEval, DidError - -proc evalBuiltin(c: Bytecode; pc: CodePos; s: StackFrame; prc: CodePos; state: var EvalBuiltinState): CodePos = - var prc = prc - while true: - case c[prc].kind - of PragmaPairM: - let (x, y) = sons2(c.code, prc) - let key = cast[PragmaKey](c[x].operand) - case key - of CoreName: - let lit = c[y].litId - case c.m.lit.strings[lit] - of "echoBinSafe": echoImpl(c, pc, s) - else: - raiseAssert "cannot eval: " & c.m.lit.strings[lit] - state = DidEval - of HeaderImport, DllImport: - let lit = c[y].litId - raiseAssert "cannot eval: " & c.m.lit.strings[lit] - else: discard - of PragmaIdM, AllocLocals: discard - else: break - next c, prc - result = prc - -proc exec(c: Bytecode; pc: CodePos; u: ref Universe) = - var pc = pc - var frame = StackFrame(u: u) - while pc.int < c.code.len: - when false: # c.interactive: - echo "running: ", pc.int - debug c, pc - - case c.code[pc].kind - of GotoM: - pc = CodePos(c.code[pc].operand) - of AsgnM: - let (sz, a, b) = sons3(c.code, pc) - let dest = evalAddr(c, a, frame) - eval(c, b, frame, dest, c.code[sz].operand.int) - next c, pc - of StoreM: - let (sz, a, b) = sons3(c.code, pc) - let destPtr = evalAddr(c, a, frame) - let dest = cast[ptr pointer](destPtr)[] - eval(c, b, frame, dest, c.code[sz].operand.int) - next c, pc - of CallM: - # No support for return values, these are mapped to `var T` parameters! - var prc = evalProc(c, pc.firstSon, frame) - assert c.code[prc.firstSon].kind == AllocLocals - let frameSize = int c.code[prc.firstSon].operand - # skip stupid stuff: - var evalState = DidNothing - prc = evalBuiltin(c, pc, frame, prc.firstSon, evalState) - if evalState != DidNothing: - next c, pc - if pc.int < c.code.len and c.code[pc].kind == CheckedGotoM: - if evalState == DidEval: - next c, pc - else: - pc = CodePos(c.code[pc].operand) - else: - # setup storage for the proc already: - let callInstr = pc - next c, pc - let s2 = newStackFrame(frameSize, frame, pc) - for a in sonsFrom1(c, callInstr): - assert c[prc].kind == SummonParamM - let paramAddr = c[prc].operand - next c, prc - assert c[prc].kind == ImmediateValM - let paramSize = c[prc].operand.int - next c, prc - eval(c, a, s2, s2.locals +! paramAddr, paramSize) - frame = s2 - pc = prc - of RetM: - pc = frame.returnAddr - if c.code[pc].kind == CheckedGotoM: - pc = frame.jumpTo - frame = popStackFrame(frame) - of SelectM: - let pc2 = evalSelect(c, pc, frame) - if pc2.int >= 0: - pc = pc2 - else: - next c, pc - of ProcDeclM: - next c, pc - else: - #debug c, c.debug[pc.int] - raiseAssert "unreachable: " & $c.code[pc].kind - -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: - #if bc.interactive: - # echo "RUnning: " - # debug bc, t, pc - preprocess c, bc, t, pc, {} - next t, pc - exec bc, start, nil diff --git a/compiler/nir/stringcases.nim b/compiler/nir/stringcases.nim deleted file mode 100644 index afdf8fda4..000000000 --- a/compiler/nir/stringcases.nim +++ /dev/null @@ -1,200 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2023 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## included from ast2ir.nim - -#[ - -case s -of "abc", "abbd": - echo 1 -of "hah": - echo 2 -of "gah": - echo 3 - -# we produce code like this: - -if s[0] <= 'a': - if s == "abc: goto L1 - elif s == "abbd": goto L1 -else: - if s[2] <= 'h': - if s == "hah": goto L2 - elif s == "gah": goto L3 -goto afterCase - -L1: - echo 1 - goto afterCase -L2: - echo 2 - goto afterCase -L3: - echo 3 - goto afterCase - -afterCase: ... - -]# - -# We split the set of strings into 2 sets of roughly the same size. -# The condition used for splitting is a (position, char) tuple. -# Every string of length > position for which s[position] <= char is in one -# set else it is in the other set. - -from std/sequtils import addUnique - -type - Key = (LitId, LabelId) - -proc splitValue(strings: BiTable[string]; a: openArray[Key]; position: int): (char, float) = - var cand: seq[char] = @[] - for t in items a: - let s = strings[t[0]] - if s.len > position: cand.addUnique s[position] - - result = ('\0', -1.0) - for disc in items cand: - var hits = 0 - for t in items a: - let s = strings[t[0]] - if s.len > position and s[position] <= disc: - inc hits - # the split is the better, the more `hits` is close to `a.len / 2`: - let grade = 100000.0 - abs(hits.float - a.len.float / 2.0) - if grade > result[1]: - result = (disc, grade) - -proc tryAllPositions(strings: BiTable[string]; a: openArray[Key]): (char, int) = - var m = 0 - for t in items a: - m = max(m, strings[t[0]].len) - - result = ('\0', -1) - var best = -1.0 - for i in 0 ..< m: - let current = splitValue(strings, a, i) - if current[1] > best: - best = current[1] - result = (current[0], i) - -type - SearchKind = enum - LinearSearch, SplitSearch - SearchResult* = object - case kind: SearchKind - of LinearSearch: - a: seq[Key] - of SplitSearch: - span: int - best: (char, int) - -proc emitLinearSearch(strings: BiTable[string]; a: openArray[Key]; dest: var seq[SearchResult]) = - var d = SearchResult(kind: LinearSearch, a: @[]) - for x in a: d.a.add x - dest.add d - -proc split(strings: BiTable[string]; a: openArray[Key]; dest: var seq[SearchResult]) = - if a.len <= 4: - emitLinearSearch strings, a, dest - else: - let best = tryAllPositions(strings, a) - var groupA: seq[Key] = @[] - var groupB: seq[Key] = @[] - for t in items a: - let s = strings[t[0]] - if s.len > best[1] and s[best[1]] <= best[0]: - groupA.add t - else: - groupB.add t - if groupA.len == 0 or groupB.len == 0: - emitLinearSearch strings, a, dest - else: - let toPatch = dest.len - dest.add SearchResult(kind: SplitSearch, span: 1, best: best) - split strings, groupA, dest - split strings, groupB, dest - let dist = dest.len - toPatch - assert dist > 0 - dest[toPatch].span = dist - -proc toProblemDescription(c: var ProcCon; n: PNode): (seq[Key], LabelId) = - result = (@[], newLabels(c.labelGen, n.len)) - assert n.kind == nkCaseStmt - for i in 1..<n.len: - let it = n[i] - let thisBranch = LabelId(result[1].int + i - 1) - if it.kind == nkOfBranch: - for j in 0..<it.len-1: - assert it[j].kind in {nkStrLit..nkTripleStrLit} - result[0].add (c.lit.strings.getOrIncl(it[j].strVal), thisBranch) - -proc decodeSolution(c: var ProcCon; dest: var Tree; s: seq[SearchResult]; i: int; - selector: Value; info: PackedLineInfo) = - case s[i].kind - of SplitSearch: - let thenA = i+1 - let elseA = thenA + (if s[thenA].kind == LinearSearch: 1 else: s[thenA].span) - let best = s[i].best - - let tmp = getTemp(c, Bool8Id, info) - buildTyped dest, info, Asgn, Bool8Id: - dest.copyTree tmp - buildTyped dest, info, Call, Bool8Id: - c.addUseCodegenProc dest, "nimStrAtLe", info - dest.copyTree selector - dest.addIntVal c.lit.numbers, info, c.m.nativeIntId, best[1] - dest.addIntVal c.lit.numbers, info, Char8Id, best[0].int - - template then() = - c.decodeSolution dest, s, thenA, selector, info - template otherwise() = - c.decodeSolution dest, s, elseA, selector, info - buildIfThenElse tmp, then, otherwise - freeTemp c, tmp - - of LinearSearch: - let tmp = getTemp(c, Bool8Id, info) - for x in s[i].a: - buildTyped dest, info, Asgn, Bool8Id: - dest.copyTree tmp - buildTyped dest, info, Call, Bool8Id: - c.addUseCodegenProc dest, "eqStrings", info - dest.copyTree selector - dest.addStrLit info, x[0] - buildIf tmp: - c.code.gotoLabel info, Goto, x[1] - freeTemp c, tmp - -proc genStringCase(c: var ProcCon; n: PNode; d: var Value) = - let (problem, firstBranch) = toProblemDescription(c, n) - var solution: seq[SearchResult] = @[] - split c.lit.strings, problem, solution - - # XXX Todo move complex case selector into a temporary. - let selector = c.genx(n[0]) - - let info = toLineInfo(c, n.info) - decodeSolution c, c.code, solution, 0, selector, info - - let lend = newLabel(c.labelGen) - c.code.addLabel info, Goto, lend - for i in 1..<n.len: - let it = n[i] - let thisBranch = LabelId(firstBranch.int + i - 1) - c.code.addLabel info, Label, thisBranch - if it.kind == nkOfBranch: - gen(c, it.lastSon, d) - c.code.addLabel info, Goto, lend - else: - gen(c, it.lastSon, d) - - c.code.addLabel info, Label, lend - freeTemp c, selector diff --git a/compiler/nir/types2ir.nim b/compiler/nir/types2ir.nim deleted file mode 100644 index 8d9583486..000000000 --- a/compiler/nir/types2ir.nim +++ /dev/null @@ -1,525 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2023 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -import std / [assertions, tables, sets] -import ".." / [ast, types, options, sighashes, modulegraphs] -import nirtypes - -type - TypesCon* = object - processed: Table[ItemId, TypeId] - processedByName: Table[string, TypeId] - recursionCheck: HashSet[ItemId] - conf: ConfigRef - stringType: TypeId - -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) - -template cached(c: var TypesCon; t: PType; body: untyped) = - result = c.processed.getOrDefault(t.itemId) - if result.int == 0: - body - c.processed[t.itemId] = result - -template cachedByName(c: var TypesCon; t: PType; body: untyped) = - let key = mangle(c, t) - result = c.processedByName.getOrDefault(key) - if result.int == 0: - body - c.processedByName[key] = result - -proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): 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, g, n[i], dest) - of nkRecCase: - assert(n[0].kind == nkSym) - collectFieldTypes(c, g, n[0], dest) - for i in 1..<n.len: - case n[i].kind - of nkOfBranch, nkElse: - collectFieldTypes c, g, lastSon(n[i]), dest - else: discard - of nkSym: - dest[n.sym.itemId] = typeToIr(c, g, n.sym.typ) - else: - assert false, "unknown node kind: " & $n.kind - -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, g, n[i], fieldTypes, unionId) - of nkRecCase: - assert(n[0].kind == nkSym) - 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(g, ObjectDecl) - g.addName "uo_" & $unionId & "_" & $i - objectToIr c, g, lastSon(n[i]), fieldTypes, unionId - sealType(g, subObj) - else: discard - sealType(g, u) - of nkSym: - 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; g: var TypeGraph; t: PType): TypeId = - if t.baseClass != nil: - # ensure we emitted the base type: - discard typeToIr(c, g, t.baseClass) - - var unionId = 0 - var fieldTypes = initTable[ItemId, TypeId]() - 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.baseClass != nil: - g.addNominalType(ObjectTy, mangle(c, t.baseClass)) - else: - g.addBuiltinType VoidId # object does not inherit - if not lacksMTypeField(t): - 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, g, t.n, fieldTypes, unionId - result = finishType(g, obj) - -proc objectHeaderToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = - result = g.nominalType(ObjectTy, mangle(c, t)) - -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, 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] - g.addField "f_" & $i, fieldTypes[i], accum.offset - - computeSizeAlign(c.conf, child) - accum.align(child.align) - accum.inc(int32(child.size)) - result = finishType(g, obj) - -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, g, t[i]) - let obj = openType(g, ProcTy) - - case t.callConv - 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, ccMember: g.addAnnotation "" - - for i in 0..<fieldTypes.len: - g.addType fieldTypes[i] - - if addEnv: - let a = openType(g, APtrTy) - g.addBuiltinType(VoidId) - sealType(g, a) - - if tfVarargs in t.flags: - g.addVarargs() - result = finishType(g, obj) - -proc nativeInt(c: TypesCon): TypeId = - case c.conf.target.intSize - of 2: result = Int16Id - of 4: result = Int32Id - else: result = Int64Id - -proc openArrayPayloadType*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = - let e = elementType(t) - let elementType = typeToIr(c, g, e) - let arr = g.openType AArrayPtrTy - g.addType elementType - result = finishType(g, arr) # LastArrayTy - -proc openArrayToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = - # object (a: ArrayPtr[T], len: int) - let e = elementType(t) - let mangledBase = mangle(c, e) - let typeName = "NimOpenArray" & mangledBase - - let elementType = typeToIr(c, g, e) - #assert elementType.int >= 0, typeToString(t) - - 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 - cap: int - data: UncheckedArray[char] - - NimStringV2 = object - len: int - p: ptr NimStrPayload - - ]# - let payload = strPayloadType(c, g) - - let str = openType(g, ObjectDecl) - g.addName "NimStringV2" - g.addSize c.conf.target.ptrSize*2 - g.addAlign c.conf.target.ptrSize - - g.addField "len", c.nativeInt, 0 - - 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(g, str) # ObjectDecl - -proc seqPayloadType(c: var TypesCon; g: var TypeGraph; t: PType): (string, TypeId) = - #[ - NimSeqPayload[T] = object - cap: int - data: UncheckedArray[T] - ]# - let e = elementType(t) - 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 - # DO NOT USE `finishType` here as it is an inner type. This is subtle and we - # probably need an even better API here. - sealType(g, arr) - result[1] = TypeId(arr) - - 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, g, t) - - let sq = openType(g, ObjectDecl) - g.addName "NimSeqV2" & mangledBase - g.addSize c.conf.getSize(t) - g.addAlign c.conf.getAlign(t) - - g.addField "len", c.nativeInt, 0 - - 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(g, sq) # ObjectDecl - - -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" & - # "void* ClE_0;$n} $1;$n" - let mangledBase = mangle(c, t) - let typeName = "NimClosure" & mangledBase - - let procType = procToIr(c, g, t, addEnv=true) - - let p = openType(g, ObjectDecl) - g.addName typeName - g.addSize c.conf.getSize(t) - g.addAlign c.conf.getAlign(t) - - let f = g.openType FieldDecl - g.addType procType - g.addOffset 0 - g.addName "ClP_0" - sealType(g, f) # FieldDecl - - let f2 = g.openType FieldDecl - let voidPtr = openType(g, APtrTy) - g.addBuiltinType(VoidId) - sealType(g, voidPtr) - - g.addOffset c.conf.target.ptrSize - g.addName "ClE_0" - sealType(g, f2) # FieldDecl - - result = finishType(g, p) # ObjectDecl - -proc bitsetBasetype*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = - let s = int(getSize(c.conf, t)) - case s - of 1: result = UInt8Id - of 2: result = UInt16Id - of 4: result = UInt32Id - of 8: result = UInt64Id - else: result = UInt8Id - -proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = - if t == nil: return VoidId - case t.kind - of tyInt: - case int(getSize(c.conf, t)) - of 2: result = Int16Id - of 4: result = Int32Id - else: result = Int64Id - of tyInt8: result = Int8Id - of tyInt16: result = Int16Id - of tyInt32: result = Int32Id - of tyInt64: result = Int64Id - of tyFloat: - case int(getSize(c.conf, t)) - of 4: result = Float32Id - else: result = Float64Id - of tyFloat32: result = Float32Id - of tyFloat64: result = Float64Id - of tyFloat128: result = getFloat128Type(g) - of tyUInt: - case int(getSize(c.conf, t)) - of 2: result = UInt16Id - of 4: result = UInt32Id - else: result = UInt64Id - of tyUInt8: result = UInt8Id - of tyUInt16: result = UInt16Id - of tyUInt32: result = UInt32Id - of tyUInt64: result = UInt64Id - of tyBool: result = Bool8Id - of tyChar: result = Char8Id - of tyVoid: result = VoidId - of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned, tyRange: - result = typeToIr(c, g, t.skipModifier) - of tyEnum: - if firstOrd(c.conf, t) < 0: - result = Int32Id - else: - case int(getSize(c.conf, t)) - of 1: result = UInt8Id - of 2: result = UInt16Id - of 4: result = Int32Id - of 8: result = Int64Id - else: result = Int32Id - of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic: - if t.len > 0: - result = typeToIr(c, g, t.skipModifier) - else: - result = TypeId(-1) - of tyFromExpr: - if t.n != nil and t.n.typ != nil: - 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, g, t.elementType) - let a = openType(g, ArrayTy) - g.addType(elemType) - g.addArrayLen n - g.addName mangle(c, t) - result = finishType(g, a) - of tyPtr, tyRef: - cached(c, t): - let e = t.elementType - if e.kind == tyUncheckedArray: - let elemType = typeToIr(c, g, e.elementType) - let a = openType(g, AArrayPtrTy) - g.addType(elemType) - result = finishType(g, a) - else: - let elemType = typeToIr(c, g, t.elementType) - let a = openType(g, APtrTy) - g.addType(elemType) - result = finishType(g, a) - of tyVar, tyLent: - cached(c, t): - let e = t.elementType - if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}: - # skip the modifier, `var openArray` is a (ptr, len) pair too: - result = typeToIr(c, g, e) - else: - 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 - of 1: result = UInt8Id - of 2: result = UInt16Id - of 4: result = UInt32Id - of 8: result = UInt64Id - else: - # array[U8, s] - cached(c, t): - let a = openType(g, ArrayTy) - g.addType(UInt8Id) - g.addArrayLen s - g.addName mangle(c, t) - 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(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, g, t) - else: - result = objectHeaderToIr(c, g, t) - of tyTuple: - cachedByName(c, t): - result = tupleToIr(c, g, t) - of tyProc: - cached(c, t): - if t.callConv == ccClosure: - result = closureToIr(c, g, t) - else: - result = procToIr(c, g, t) - of tyVarargs, tyOpenArray: - cached(c, t): - result = openArrayToIr(c, g, t) - of tyString: - if c.stringType.int < 0: - result = stringToIr(c, g) - c.stringType = result - else: - result = c.stringType - of tySequence: - cachedByName(c, t): - result = seqToIr(c, g, t) - of tyCstring: - cached(c, t): - 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, g, t.elementType) - 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]`: - result = VoidId - of tyNone, tyEmpty, tyTypeDesc, - tyGenericInvocation, tyProxy, tyBuiltInTypeClass, - tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass, - tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward: - result = TypeId(-1) diff --git a/compiler/options.nim b/compiler/options.nim index bdea506d2..975e21441 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -139,7 +139,6 @@ type backendCpp = "cpp" backendJs = "js" backendObjc = "objc" - backendNir = "nir" # backendNimscript = "nimscript" # this could actually work # backendLlvm = "llvm" # probably not well supported; was cmdCompileToLLVM @@ -147,7 +146,6 @@ type cmdNone # not yet processed command cmdUnknown # command unmapped cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS, - cmdCompileToNir, cmdCrun # compile and run in nimache cmdTcc # run the project via TCC backend cmdCheck # semantic checking for whole project @@ -176,7 +174,7 @@ type const cmdBackends* = {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, - cmdCompileToJS, cmdCrun, cmdCompileToNir} + cmdCompileToJS, cmdCrun} cmdDocLike* = {cmdDoc0, cmdDoc, cmdDoc2tex, cmdJsondoc0, cmdJsondoc, cmdCtags, cmdBuildindex} diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim index a44edbb7f..55e7fe892 100644 --- a/compiler/pipelines.nim +++ b/compiler/pipelines.nim @@ -13,7 +13,6 @@ when not defined(leanCompiler): import std/[syncio, objectdollar, assertions, tables, strutils, strtabs] import renderer import ic/replayer -import nir/nir proc setPipeLinePass*(graph: ModuleGraph; pass: PipelinePass) = graph.pipelinePass = pass @@ -45,10 +44,6 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext): result = nil of EvalPass, InterpreterPass: result = interpreterCode(bModule, semNode) - of NirReplPass: - result = runCode(bModule, semNode) - of NirPass: - result = nirBackend(bModule, semNode) of NonePass: raiseAssert "use setPipeLinePass to set a proper PipelinePass" @@ -111,8 +106,6 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator case graph.pipelinePass of CgenPass: setupCgen(graph, module, idgen) - of NirPass: - openNirBackend(graph, module, idgen) of JSgenPass: when not defined(leanCompiler): setupJSgen(graph, module, idgen) @@ -120,8 +113,6 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator nil of EvalPass, InterpreterPass: setupEvalGen(graph, module, idgen) - of NirReplPass: - setupNirReplGen(graph, module, idgen) of GenDependPass: setupDependPass(graph, module, idgen) of Docgen2Pass: @@ -209,10 +200,6 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator discard finalJSCodeGen(graph, bModule, finalNode) of EvalPass, InterpreterPass: discard interpreterCode(bModule, finalNode) - of NirReplPass: - discard runCode(bModule, finalNode) - of NirPass: - closeNirBackend(bModule, finalNode) of SemPass, GenDependPass: discard of Docgen2Pass, Docgen2TexPass: |