12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639 |
- #
- #
- # 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")
|