123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646 |
- #
- #
- # 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 mIntToStr: genUnaryCp(c, n, d, "nimIntToStr")
- of mInt64ToStr: genUnaryCp(c, n, d, "nimInt64ToStr")
- of mBoolToStr: genUnaryCp(c, n, d, "nimBoolToStr")
- of mCharToStr: genUnaryCp(c, n, d, "nimCharToStr")
- of mFloatToStr:
- if n[1].typ.skipTypes(abstractInst).kind == tyFloat32:
- genUnaryCp(c, n, d, "nimFloat32ToStr")
- else:
- genUnaryCp(c, n, d, "nimFloatToStr")
- of mCStrToStr: genUnaryCp(c, n, d, "cstrToNimstr")
- of mEnumToStr: genEnumToStr(c, n, d)
- of mEqStr: genBinaryCp(c, n, d, "eqStrings")
- of mEqCString: genCall(c, n, d)
- of mLeStr: genBinaryCp(c, n, d, "leStrings")
- of mLtStr: genBinaryCp(c, n, d, "ltStrings")
- of mSetLengthStr:
- unused(c, n, d)
- let nb = copyTree(n)
- nb[1] = makeAddr(nb[1], c.m.idgen)
- genBinaryCp(c, nb, d, "setLengthStrV2")
- of mSetLengthSeq:
- unused(c, n, d)
- let nb = copyTree(n)
- nb[1] = makeAddr(nb[1], c.m.idgen)
- genCall(c, nb, d)
- of mSwap:
- unused(c, n, d)
- c.gen(lowerSwap(c.m.graph, n, c.m.idgen,
- if c.prc == nil: c.m.module else: c.prc), d)
- of mParseBiggestFloat:
- genCall c, n, d
- of mHigh:
- c.genHigh n, d
- of mEcho:
- unused(c, n, d)
- genUnaryCp c, n, d, "echoBinSafe"
- of mAppendStrCh:
- unused(c, n, d)
- let nb = copyTree(n)
- nb[1] = makeAddr(nb[1], c.m.idgen)
- genBinaryCp(c, nb, d, "nimAddCharV1")
- of mMinI, mMaxI, mAbsI, mDotDot:
- c.genCall(n, d)
- of mSizeOf:
- localError(c.config, n.info, sizeOfLikeMsg("sizeof"))
- of mAlignOf:
- localError(c.config, n.info, sizeOfLikeMsg("alignof"))
- of mOffsetOf:
- localError(c.config, n.info, sizeOfLikeMsg("offsetof"))
- of mRunnableExamples:
- discard "just ignore any call to runnableExamples"
- of mOf: genOf(c, n, d)
- of mAppendStrStr:
- unused(c, n, d)
- let nb = copyTree(n)
- nb[1] = makeAddr(nb[1], c.m.idgen)
- genBinaryCp(c, nb, d, "nimAddStrV1")
- of mAppendSeqElem:
- unused(c, n, d)
- let nb = copyTree(n)
- nb[1] = makeAddr(nb[1], c.m.idgen)
- genCall(c, nb, d)
- of mIsNil: genIsNil(c, n, d)
- of mInSet: genInSet(c, n, d)
- of mCard: genCard(c, n, d)
- of mEqSet: genEqSet(c, n, d)
- of mLeSet: genLeSet(c, n, d)
- of mLtSet: genLtSet(c, n, d)
- of mMulSet: genBinarySet(c, n, d, m)
- of mPlusSet: genBinarySet(c, n, d, m)
- of mMinusSet: genBinarySet(c, n, d, m)
- of mIncl, mExcl:
- unused(c, n, d)
- genInclExcl(c, n, m)
- of mConStrStr: genStrConcat(c, n, d)
- of mDefault, mZeroDefault:
- genDefault c, n, d
- of mMove: genMove(c, n, d)
- of mWasMoved, mReset:
- unused(c, n, d)
- genWasMoved(c, n)
- of mDestroy: genDestroy(c, n)
- #of mAccessEnv: unaryExpr(d, n, d, "$1.ClE_0")
- #of mAccessTypeField: genAccessTypeField(c, n, d)
- of mSlice: genSlice(c, n, d)
- of mTrace: discard "no code to generate"
- else:
- # mGCref, mGCunref: unused by ORC
- globalError(c.config, n.info, "cannot generate code for: " & $m)
- 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: 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")
|