# # # 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, guards, renderer, transf, bitsets, trees, nimsets, expanddefaults] from ".." / lowerings import lowerSwap, lowerTupleUnpacking from ".." / pathutils import customPath import .. / ic / bitabs import nirtypes, nirinsts, nirlineinfos, nirslots, types2ir when defined(nimCompilerStacktraceHints): import std/stackframes type ModuleCon* = ref object strings*: BiTable[string] integers*: BiTable[int64] man*: LineInfoManager types*: TypesCon slotGenerator: ref int module*: PSym graph*: ModuleGraph nativeIntId, nativeUIntId: TypeId idgen: IdGenerator pendingProcs: Table[ItemId, PSym] # procs we still need to generate code for ProcCon* = object config: ConfigRef lastFileKey: FileIndex lastFileVal: LitId labelGen: int exitLabel: LabelId code*: Tree blocks: seq[(PSym, LabelId)] sm: SlotManager locGen: int m: ModuleCon prc: PSym options: TOptions proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; module: PSym): ModuleCon = result = ModuleCon(graph: graph, types: initTypesCon(config), slotGenerator: new(int), 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 proc initProcCon*(m: ModuleCon; prc: PSym; config: ConfigRef): ProcCon = ProcCon(m: m, sm: initSlotManager({}, m.slotGenerator), prc: prc, config: config, options: if prc != nil: prc.options else: config.options) proc toLineInfo(c: var ProcCon; i: TLineInfo): PackedLineInfo = var val: LitId if c.lastFileKey == i.fileIndex: val = c.lastFileVal else: val = c.m.strings.getOrIncl(toFullPath(c.config, i.fileIndex)) # remember the entry: c.lastFileKey = i.fileIndex c.lastFileVal = val result = pack(c.m.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 getTemp(c: var ProcCon; n: PNode): Value = let info = toLineInfo(c, n.info) let t = typeToIr(c.m.types, n.typ) let tmp = allocTemp(c.sm, t) c.code.addSummon info, tmp, t result = localToValue(info, tmp) template withTemp(tmp, n, body: untyped) {.dirty.} = var tmp = getTemp(c, n) body c.freeTemp(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(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..>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.types.g[setType].kind != ArrayTy: copyTree target, a else: buildTyped target, info, ArrayAt, t: copyTree target, a buildTyped target, info, BitShr, t: buildTyped target, info, Cast, expansion: copyTree target, b addIntVal target, c.m.integers, info, expansion, 3 buildTyped target, info, BitShl, t: addIntVal target, c.m.integers, info, t, 1 buildTyped target, info, BitAnd, t: buildTyped target, info, Cast, expansion: copyTree target, b addIntVal target, c.m.integers, info, expansion, mask addIntVal target, c.m.integers, 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, 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.types, n.typ) let setType = typeToIr(c.m.types, n[1].typ) if isEmpty(d): d = getTemp(c, n) buildTyped c.code, info, Asgn, t: copyTree c.code, d buildTyped c.code, info, Call, t: if c.m.types.g[setType].kind == ArrayTy: let codegenProc = magicsys.getCompilerProc(c.m.graph, "cardSet") let theProc = c.genx newSymNode(codegenProc, n.info) copyTree c.code, theProc buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.types.g, setType): 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.types, n.typ) let setType = typeToIr(c.m.types, n[1].typ) if c.m.types.g[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.types.g, setType): copyTree c.code, a buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.types.g, setType): copyTree c.code, b c.code.addImmediateVal info, int(getSize(c.config, n[1].typ)) c.code.addIntVal c.m.integers, 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.sm, 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.m.integers, 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.m.integers, info, c.m.nativeIntId, last build c.code, info, SelectPair: build c.code, info, SelectValue: c.code.boolVal(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.sm, 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(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.m.integers, 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.types, n.typ) let setType = typeToIr(c.m.types, n[1].typ) if c.m.types.g[setType].kind == ArrayTy: let elemType = bitsetBasetype(c.m.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, elemType: copyTree c.code, a c.code.addSymUse info, idx buildTyped c.code, info, BitNot, elemType: buildTyped c.code, info, ArrayAt, elemType: copyTree c.code, b c.code.addSymUse info, idx c.code.addIntVal c.m.integers, 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(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.m.integers, 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.types, n.typ) let setType = typeToIr(c.m.types, n[1].typ) if c.m.types.g[setType].kind == ArrayTy: let elemType = bitsetBasetype(c.m.types, n[1].typ) if isEmpty(d): d = getTemp(c, n) # "for ($1 = 0; $1 < $2; $1++):" # " $3 = (($4[$1] & ~ $5[$1]) == 0)" # " if (!$3) break;" let (idx, backLabel, endLabel) = beginCountLoop(c, info, 0, int(getSize(c.config, n[1].typ))) buildTyped c.code, info, Asgn, elemType: buildTyped c.code, info, ArrayAt, elemType: copyTree c.code, d c.code.addSymUse info, idx buildTyped c.code, info, (if m == mPlusSet: BitOr else: BitAnd), elemType: buildTyped c.code, info, ArrayAt, elemType: copyTree c.code, a c.code.addSymUse info, idx if m == mMinusSet: buildTyped c.code, info, BitNot, elemType: buildTyped c.code, info, ArrayAt, elemType: copyTree c.code, b c.code.addSymUse info, idx else: buildTyped c.code, info, ArrayAt, elemType: 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.types, n[1].typ) let t = bitsetBasetype(c.m.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.types.g[setType].kind == ArrayTy: if m == mIncl: # $1[(NU)($2)>>3] |=(1U<<($2&7U)) buildTyped c.code, info, ArrayAt, t: 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.m.integers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitOr, t: buildTyped c.code, info, ArrayAt, t: 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.m.integers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitShl, t: c.code.addIntVal c.m.integers, info, t, 1 buildTyped c.code, info, BitAnd, t: copyTree c.code, b c.code.addIntVal c.m.integers, info, t, 7 else: # $1[(NU)($2)>>3] &= ~(1U<<($2&7U)) buildTyped c.code, info, ArrayAt, t: 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.m.integers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitAnd, t: buildTyped c.code, info, ArrayAt, t: 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.m.integers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitNot, t: buildTyped c.code, info, BitShl, t: c.code.addIntVal c.m.integers, info, t, 1 buildTyped c.code, info, BitAnd, t: copyTree c.code, b c.code.addIntVal c.m.integers, 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.m.integers, info, t, 1 buildTyped c.code, info, BitAnd, t: copyTree c.code, b c.code.addIntVal c.m.integers, 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.m.integers, info, t, 1 buildTyped c.code, info, BitAnd, t: copyTree c.code, b c.code.addIntVal c.m.integers, 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.types, n.typ) let size = int(getSize(c.config, n.typ)) let t = bitsetBasetype(c.m.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.types.g[setType].kind != ArrayTy: buildTyped c.code, info, Asgn, setType: copyTree c.code, d c.code.addIntVal c.m.integers, 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.m.integers, info, t, 1 buildTyped c.code, info, BitAnd, t: c.code.addSymUse info, idx c.code.addIntVal c.m.integers, 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.m.integers, info, t, 1 buildTyped c.code, info, BitAnd, t: copyTree c.code, a c.code.addIntVal c.m.integers, 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.m.integers, 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, t: 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.m.integers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitOr, t: buildTyped c.code, info, ArrayAt, t: 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.m.integers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitShl, t: c.code.addIntVal c.m.integers, info, t, 1 buildTyped c.code, info, BitAnd, t: c.code.addSymUse info, idx c.code.addIntVal c.m.integers, 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, t: 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.m.integers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitOr, t: buildTyped c.code, info, ArrayAt, t: 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.m.integers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitShl, t: c.code.addIntVal c.m.integers, info, t, 1 buildTyped c.code, info, BitAnd, t: copyTree c.code, a c.code.addIntVal c.m.integers, 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.types, n.typ) let size = int(getSize(c.config, n.typ)) let cs = toBitSet(c.config, n) if c.m.types.g[setType].kind != ArrayTy: template body(target) = target.addIntVal c.m.integers, info, setType, cast[BiggestInt](bitSetToWord(cs, size)) intoDest d, info, setType, body else: let t = bitsetBasetype(c.m.types, n.typ) template body(target) = buildTyped target, info, ArrayConstr, setType: for i in 0..high(cs): target.addIntVal c.m.integers, 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) # # s = "Hello " & name & ", how do you feel?" & 'z' # # # { # 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 precomputedLen = 0 for i in 1 ..< n.len: let it = n[i] if skipTypes(it.typ, abstractVarRange).kind == tyChar: inc precomputedLen elif it.kind in {nkStrLit..nkTripleStrLit}: inc precomputedLen, it.strVal.len args.add genx(c, it) # generate length computation: var tmpLen = allocTemp(c.sm, c.m.nativeIntId) buildTyped c.code, info, Asgn, c.m.nativeIntId: c.code.addSymUse info, tmpLen c.code.addIntVal c.m.integers, info, c.m.nativeIntId, precomputedLen for a in mitems(args): buildTyped c.code, info, Asgn, c.m.nativeIntId: c.code.addSymUse info, tmpLen buildTyped c.code, info, CheckedAdd, c.m.nativeIntId: c.code.addSymUse info, tmpLen buildTyped c.code, info, FieldAt, c.m.nativeIntId: copyTree c.code, a c.code.addImmediateVal info, 0 # (len, p)-pair so len is at index 0 var tmpStr = getTemp(c, n) # ^ because of aliasing, we always go through a temporary let t = typeToIr(c.m.types, n.typ) 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.types.g, 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 payloadType = seqPayloadPtrType(c.m.types, n1.typ) buildTyped c.code, info, Select, Bool8Id: buildTyped c.code, info, Eq, payloadType: buildTyped c.code, info, FieldAt, payloadType: copyTree c.code, a c.code.addImmediateVal info, 1 # (len, p)-pair buildTyped c.code, info, FieldAt, payloadType: copyTree c.code, src c.code.addImmediateVal info, 1 # (len, p)-pair build c.code, info, SelectPair: build c.code, info, SelectValue: c.code.boolVal(info, true) c.code.gotoLabel info, Goto, lab1 gen(c, n[3]) c.patch n, lab1 buildTyped c.code, info, Asgn, typeToIr(c.m.types, n1.typ): copyTree c.code, a copyTree c.code, src else: if isEmpty(d): d = getTemp(c, n) buildTyped c.code, info, Asgn, typeToIr(c.m.types, n1.typ): copyTree c.code, d copyTree c.code, a var op = getAttachedOp(c.m.graph, n.typ, attachedWasMoved) if op == nil or skipTypes(n1.typ, abstractVar+{tyStatic}).kind in {tyOpenArray, tyVarargs}: let m = expandDefault(n1.typ, n1.info) gen c, m, a else: var opB = c.genx(newSymNode(op)) buildTyped c.code, info, Call, typeToIr(c.m.types, n.typ): copyTree c.code, opB buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.types.g, typeToIr(c.m.types, n1.typ)): copyTree c.code, a proc genDestroy(c: var ProcCon; n: PNode) = let t = n[1].typ.skipTypes(abstractInst) case t.kind of tyString: var unused = default(Value) genUnaryCp(c, n, unused, "nimDestroyStrV1") of tySequence: #[ var a = initLocExpr(c, arg) linefmt(c, cpsStmts, "if ($1.p && ($1.p->cap & NIM_STRLIT_FLAG) == 0) {$n" & " #alignedDealloc($1.p, NIM_ALIGNOF($2));$n" & "}$n", [rdLoc(a), getTypeDesc(c.module, t.lastSon)]) ]# globalError(c.config, n.info, "not implemented: =destroy for seqs") else: discard "nothing to do" proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) = case m of mAnd: c.genAndOr(n, opcFJmp, d) of mOr: c.genAndOr(n, opcTJmp, d) of mPred, mSubI: c.genBinaryOp(n, d, CheckedSub) of mSucc, mAddI: c.genBinaryOp(n, d, CheckedAdd) of mInc: unused(c, n, d) c.genIncDec(n, CheckedAdd) of mDec: unused(c, n, d) c.genIncDec(n, CheckedSub) of mOrd, mChr, mArrToSeq, 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, CheckedMul) of mDivI: genBinaryOp(c, n, d, CheckedDiv) of mModI: genBinaryOp(c, n, d, CheckedMod) of mAddF64: genBinaryOp(c, n, d, Add) of mSubF64: genBinaryOp(c, n, d, Sub) of mMulF64: genBinaryOp(c, n, d, Mul) 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 mIntToStr: genUnaryCp(c, n, d, "nimIntToStr") of mInt64ToStr: genUnaryCp(c, n, d, "nimInt64ToStr") of mBoolToStr: genUnaryCp(c, n, d, "nimBoolToStr") of mCharToStr: genUnaryCp(c, n, d, "nimCharToStr") of mFloatToStr: if n[1].typ.skipTypes(abstractInst).kind == tyFloat32: genUnaryCp(c, n, d, "nimFloat32ToStr") else: genUnaryCp(c, n, d, "nimFloatToStr") 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, mReset: unused(c, n, d) genWasMoved(c, n) of mDestroy: genDestroy(c, n) #of mAccessEnv: unaryExpr(d, n, d, "$1.ClE_0") #of mAccessTypeField: genAccessTypeField(c, n, d) #of mSlice: genSlice(c, n, d) of mTrace: discard "no code to generate" else: # mGCref, mGCunref: unused by ORC globalError(c.config, n.info, "cannot generate code for: " & $m) #[ of mRepr: genUnaryABC(c, n, d, opcRepr) of mNodeId: c.genUnaryABC(n, d, opcNodeId) of mExpandToAst: if n.len != 2: globalError(c.config, n.info, "expandToAst requires 1 argument") let arg = n[1] if arg.kind in nkCallKinds: #if arg[0].kind != nkSym or arg[0].sym.kind notin {skTemplate, skMacro}: # "ExpandToAst: expanded symbol is no macro or template" if isEmpty(d): d = c.getTemp(n) c.genCall(arg, d) # do not call clearDest(n, d) here as getAst has a meta-type as such # produces a value else: globalError(c.config, n.info, "expandToAst requires a call expression") of mParseExprToAst: genBinaryABC(c, n, d, opcParseExprToAst) of mParseStmtToAst: genBinaryABC(c, n, d, opcParseStmtToAst) of mTypeTrait: let tmp = c.genx(n[1]) if isEmpty(d): d = c.getTemp(n) c.gABx(n, opcSetType, tmp, c.genType(n[1].typ)) c.gABC(n, opcTypeTrait, d, tmp) c.freeTemp(tmp) of mSlurp: genUnaryABC(c, n, d, opcSlurp) of mNLen: genUnaryABI(c, n, d, opcLenSeq, nimNodeFlag) of mGetImpl: genUnaryABC(c, n, d, opcGetImpl) of mGetImplTransf: genUnaryABC(c, n, d, opcGetImplTransf) of mSymOwner: genUnaryABC(c, n, d, opcSymOwner) of mSymIsInstantiationOf: genBinaryABC(c, n, d, opcSymIsInstantiationOf) of mNChild: genBinaryABC(c, n, d, opcNChild) of mNAdd: genBinaryABC(c, n, d, opcNAdd) of mNAddMultiple: genBinaryABC(c, n, d, opcNAddMultiple) of mNKind: genUnaryABC(c, n, d, opcNKind) of mNSymKind: genUnaryABC(c, n, d, opcNSymKind) of mNccValue: genUnaryABC(c, n, d, opcNccValue) of mNccInc: genBinaryABC(c, n, d, opcNccInc) of mNcsAdd: genBinaryABC(c, n, d, opcNcsAdd) of mNcsIncl: genBinaryABC(c, n, d, opcNcsIncl) of mNcsLen: genUnaryABC(c, n, d, opcNcsLen) of mNcsAt: genBinaryABC(c, n, d, opcNcsAt) of mNctLen: genUnaryABC(c, n, d, opcNctLen) of mNctGet: genBinaryABC(c, n, d, opcNctGet) of mNctHasNext: genBinaryABC(c, n, d, opcNctHasNext) of mNctNext: genBinaryABC(c, n, d, opcNctNext) of mNIntVal: genUnaryABC(c, n, d, opcNIntVal) of mNFloatVal: genUnaryABC(c, n, d, opcNFloatVal) of mNSymbol: genUnaryABC(c, n, d, opcNSymbol) of mNIdent: genUnaryABC(c, n, d, opcNIdent) of mNGetType: let tmp = c.genx(n[1]) if isEmpty(d): d = c.getTemp(n) let rc = case n[0].sym.name.s: of "getType": 0 of "typeKind": 1 of "getTypeInst": 2 else: 3 # "getTypeImpl" c.gABC(n, opcNGetType, d, tmp, rc) c.freeTemp(tmp) #genUnaryABC(c, n, d, opcNGetType) of mNSizeOf: let imm = case n[0].sym.name.s: of "getSize": 0 of "getAlign": 1 else: 2 # "getOffset" c.genUnaryABI(n, d, opcNGetSize, imm) of mNStrVal: genUnaryABC(c, n, d, opcNStrVal) of mNSigHash: genUnaryABC(c, n , d, opcNSigHash) of mNSetIntVal: unused(c, n, d) genBinaryStmt(c, n, opcNSetIntVal) of mNSetFloatVal: unused(c, n, d) genBinaryStmt(c, n, opcNSetFloatVal) of mNSetSymbol: unused(c, n, d) genBinaryStmt(c, n, opcNSetSymbol) of mNSetIdent: unused(c, n, d) genBinaryStmt(c, n, opcNSetIdent) of mNSetStrVal: unused(c, n, d) genBinaryStmt(c, n, opcNSetStrVal) of mNNewNimNode: genBinaryABC(c, n, d, opcNNewNimNode) of mNCopyNimNode: genUnaryABC(c, n, d, opcNCopyNimNode) of mNCopyNimTree: genUnaryABC(c, n, d, opcNCopyNimTree) of mNBindSym: genBindSym(c, n, d) of mStrToIdent: genUnaryABC(c, n, d, opcStrToIdent) of mEqIdent: genBinaryABC(c, n, d, opcEqIdent) of mEqNimrodNode: genBinaryABC(c, n, d, opcEqNimNode) of mSameNodeType: genBinaryABC(c, n, d, opcSameNodeType) of mNLineInfo: case n[0].sym.name.s of "getFile": genUnaryABI(c, n, d, opcNGetLineInfo, 0) of "getLine": genUnaryABI(c, n, d, opcNGetLineInfo, 1) of "getColumn": genUnaryABI(c, n, d, opcNGetLineInfo, 2) of "copyLineInfo": internalAssert c.config, n.len == 3 unused(c, n, d) genBinaryStmt(c, n, opcNCopyLineInfo) of "setLine": internalAssert c.config, n.len == 3 unused(c, n, d) genBinaryStmt(c, n, opcNSetLineInfoLine) of "setColumn": internalAssert c.config, n.len == 3 unused(c, n, d) genBinaryStmt(c, n, opcNSetLineInfoColumn) of "setFile": internalAssert c.config, n.len == 3 unused(c, n, d) genBinaryStmt(c, n, opcNSetLineInfoFile) else: internalAssert c.config, false of mNHint: unused(c, n, d) genBinaryStmt(c, n, opcNHint) of mNWarning: unused(c, n, d) genBinaryStmt(c, n, opcNWarning) of mNError: if n.len <= 1: # query error condition: c.gABC(n, opcQueryErrorFlag, d) else: # setter unused(c, n, d) genBinaryStmt(c, n, opcNError) of mNCallSite: if isEmpty(d): d = c.getTemp(n) c.gABC(n, opcCallSite, d) of mNGenSym: genBinaryABC(c, n, d, opcGenSym) ]# 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] 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.types, typ): copyTree c.code, d body(c.code) 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.types, 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.types, 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.types.g, typeToIr(c.m.types, arrType.lastSon)) case arrType.kind of tyString: let t = typeToIr(c.m.types, typ.lastSon) target.addImmediateVal info, 0 buildTyped target, info, AddrOf, elemType: buildTyped target, info, ArrayAt, t: buildTyped target, info, FieldAt, strPayloadPtrType(c.m.types): copyTree target, tmp target.addImmediateVal info, 1 # (len, p)-pair target.addIntVal c.m.integers, info, c.m.nativeIntId, 0 # len: target.addImmediateVal info, 1 buildTyped target, info, FieldAt, c.m.nativeIntId: copyTree target, tmp target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0 of tySequence: let t = typeToIr(c.m.types, typ.lastSon) target.addImmediateVal info, 0 buildTyped target, info, AddrOf, elemType: buildTyped target, info, ArrayAt, t: buildTyped target, info, FieldAt, seqPayloadPtrType(c.m.types, typ): copyTree target, tmp target.addImmediateVal info, 1 # (len, p)-pair target.addIntVal c.m.integers, info, c.m.nativeIntId, 0 # len: target.addImmediateVal info, 1 buildTyped target, info, FieldAt, c.m.nativeIntId: copyTree target, tmp target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0 of tyArray: let t = typeToIr(c.m.types, typ.lastSon) target.addImmediateVal info, 0 buildTyped target, info, AddrOf, elemType: buildTyped target, info, ArrayAt, t: copyTree target, tmp target.addIntVal c.m.integers, info, c.m.nativeIntId, 0 target.addImmediateVal info, 1 target.addIntVal(c.m.integers, info, c.m.nativeIntId, toInt lengthOrd(c.config, typ)) else: raiseAssert "addAddrOfFirstElem: " & typeToString(typ) proc genToOpenArrayConv(c: var ProcCon; arg: PNode; d: var Value; flags: GenFlags; destType: PType) = let info = toLineInfo(c, arg.info) let tmp = c.genx(arg, flags) let arrType = destType.skipTypes(abstractVar) template body(target) = buildTyped target, info, ObjConstr, typeToIr(c.m.types, arrType): c.addAddrOfFirstElem target, info, tmp, arg.typ valueIntoDest c, info, d, arrType, body freeTemp c, tmp proc genConv(c: var ProcCon; n, arg: PNode; d: var Value; flags: GenFlags; opc: Opcode) = let targetType = n.typ.skipTypes({tyDistinct}) let argType = arg.typ.skipTypes({tyDistinct}) 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.types, 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) = # XXX x = (x.old, 22) produces wrong code ... stupid self assignments let info = toLineInfo(c, n.info) template body(target) = buildTyped target, info, ObjConstr, typeToIr(c.m.types, n.typ): for i in ord(n.kind == nkObjConstr)..