ast2ir.nim 89 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2023 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. import std / [assertions, tables, sets]
  10. import ".." / [ast, astalgo, types, options, lineinfos, msgs, magicsys,
  11. modulegraphs, renderer, transf, bitsets, trees, nimsets,
  12. expanddefaults]
  13. from ".." / lowerings import lowerSwap, lowerTupleUnpacking
  14. from ".." / pathutils import customPath
  15. import .. / ic / bitabs
  16. import nirtypes, nirinsts, nirlineinfos, nirslots, types2ir, nirfiles
  17. when defined(nimCompilerStacktraceHints):
  18. import std/stackframes
  19. type
  20. ModuleCon* = ref object
  21. nirm*: ref NirModule
  22. types: TypesCon
  23. module*: PSym
  24. graph*: ModuleGraph
  25. nativeIntId, nativeUIntId: TypeId
  26. strPayloadId: (TypeId, TypeId)
  27. idgen: IdGenerator
  28. processedProcs, pendingProcsAsSet: HashSet[ItemId]
  29. pendingProcs: seq[PSym] # procs we still need to generate code for
  30. pendingVarsAsSet: HashSet[ItemId]
  31. pendingVars: seq[PSym]
  32. noModularity*: bool
  33. inProc: int
  34. toSymId: Table[ItemId, SymId]
  35. symIdCounter: int32
  36. ProcCon* = object
  37. config*: ConfigRef
  38. lit: Literals
  39. lastFileKey: FileIndex
  40. lastFileVal: LitId
  41. labelGen: int
  42. exitLabel: LabelId
  43. #code*: Tree
  44. blocks: seq[(PSym, LabelId)]
  45. sm: SlotManager
  46. idgen: IdGenerator
  47. m: ModuleCon
  48. prc: PSym
  49. options: TOptions
  50. template code(c: ProcCon): Tree = c.m.nirm.code
  51. proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; module: PSym;
  52. nirm: ref NirModule): ModuleCon =
  53. #let lit = Literals() # must be shared
  54. result = ModuleCon(graph: graph, types: initTypesCon(config), nirm: nirm,
  55. idgen: idgen, module: module)
  56. case config.target.intSize
  57. of 2:
  58. result.nativeIntId = Int16Id
  59. result.nativeUIntId = UInt16Id
  60. of 4:
  61. result.nativeIntId = Int32Id
  62. result.nativeUIntId = UInt16Id
  63. else:
  64. result.nativeIntId = Int64Id
  65. result.nativeUIntId = UInt16Id
  66. result.strPayloadId = strPayloadPtrType(result.types, result.nirm.types)
  67. nirm.namespace = nirm.lit.strings.getOrIncl(customPath(toFullPath(config, module.info)))
  68. nirm.intbits = uint32(config.target.intSize * 8)
  69. proc initProcCon*(m: ModuleCon; prc: PSym; config: ConfigRef): ProcCon =
  70. result = ProcCon(m: m, sm: initSlotManager({}), prc: prc, config: config,
  71. lit: m.nirm.lit, idgen: m.idgen,
  72. options: if prc != nil: prc.options
  73. else: config.options)
  74. result.exitLabel = newLabel(result.labelGen)
  75. proc toLineInfo(c: var ProcCon; i: TLineInfo): PackedLineInfo =
  76. var val: LitId
  77. if c.lastFileKey == i.fileIndex:
  78. val = c.lastFileVal
  79. else:
  80. val = c.lit.strings.getOrIncl(toFullPath(c.config, i.fileIndex))
  81. # remember the entry:
  82. c.lastFileKey = i.fileIndex
  83. c.lastFileVal = val
  84. result = pack(c.m.nirm.man, val, int32 i.line, int32 i.col)
  85. proc bestEffort(c: ProcCon): TLineInfo =
  86. if c.prc != nil:
  87. c.prc.info
  88. else:
  89. c.m.module.info
  90. proc popBlock(c: var ProcCon; oldLen: int) =
  91. c.blocks.setLen(oldLen)
  92. template withBlock(labl: PSym; info: PackedLineInfo; asmLabl: LabelId; body: untyped) {.dirty.} =
  93. var oldLen {.gensym.} = c.blocks.len
  94. c.blocks.add (labl, asmLabl)
  95. body
  96. popBlock(c, oldLen)
  97. type
  98. GenFlag = enum
  99. gfAddrOf # load the address of the expression
  100. gfToOutParam # the expression is passed to an `out` parameter
  101. GenFlags = set[GenFlag]
  102. proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {})
  103. proc genScope(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) =
  104. openScope c.sm
  105. gen c, n, d, flags
  106. closeScope c.sm
  107. proc freeTemp(c: var ProcCon; tmp: Value) =
  108. let s = extractTemp(tmp)
  109. if s != SymId(-1):
  110. freeTemp(c.sm, s)
  111. proc freeTemps(c: var ProcCon; tmps: openArray[Value]) =
  112. for t in tmps: freeTemp(c, t)
  113. proc typeToIr(m: ModuleCon; t: PType): TypeId =
  114. typeToIr(m.types, m.nirm.types, t)
  115. proc allocTemp(c: var ProcCon; t: TypeId): SymId =
  116. if c.m.noModularity:
  117. result = allocTemp(c.sm, t, c.m.symIdCounter)
  118. else:
  119. result = allocTemp(c.sm, t, c.idgen.symId)
  120. const
  121. ListSymId = -1
  122. proc toSymId(c: var ProcCon; s: PSym): SymId =
  123. if c.m.noModularity:
  124. result = c.m.toSymId.getOrDefault(s.itemId, SymId(-1))
  125. if result.int < 0:
  126. inc c.m.symIdCounter
  127. result = SymId(c.m.symIdCounter)
  128. c.m.toSymId[s.itemId] = result
  129. when ListSymId != -1:
  130. if result.int == ListSymId or s.name.s == "echoBinSafe":
  131. echo result.int, " is ", s.name.s, " ", c.m.graph.config $ s.info, " ", s.flags
  132. writeStackTrace()
  133. else:
  134. result = SymId(s.itemId.item)
  135. proc getTemp(c: var ProcCon; n: PNode): Value =
  136. let info = toLineInfo(c, n.info)
  137. let t = typeToIr(c.m, n.typ)
  138. let tmp = allocTemp(c, t)
  139. c.code.addSummon info, tmp, t
  140. result = localToValue(info, tmp)
  141. proc getTemp(c: var ProcCon; t: TypeId; info: PackedLineInfo): Value =
  142. let tmp = allocTemp(c, t)
  143. c.code.addSummon info, tmp, t
  144. result = localToValue(info, tmp)
  145. proc gen(c: var ProcCon; n: PNode; flags: GenFlags = {}) =
  146. var tmp = default(Value)
  147. gen(c, n, tmp, flags)
  148. freeTemp c, tmp
  149. proc genScope(c: var ProcCon; n: PNode; flags: GenFlags = {}) =
  150. openScope c.sm
  151. gen c, n, flags
  152. closeScope c.sm
  153. proc genx(c: var ProcCon; n: PNode; flags: GenFlags = {}): Value =
  154. result = default(Value)
  155. gen(c, n, result, flags)
  156. assert Tree(result).len > 0, $n
  157. proc clearDest(c: var ProcCon; n: PNode; d: var Value) {.inline.} =
  158. when false:
  159. if n.typ.isNil or n.typ.kind == tyVoid:
  160. let s = extractTemp(d)
  161. if s != SymId(-1):
  162. freeLoc(c.sm, s)
  163. proc isNotOpr(n: PNode): bool =
  164. n.kind in nkCallKinds and n[0].kind == nkSym and n[0].sym.magic == mNot
  165. proc jmpBack(c: var ProcCon; n: PNode; lab: LabelId) =
  166. c.code.gotoLabel toLineInfo(c, n.info), GotoLoop, lab
  167. type
  168. JmpKind = enum opcFJmp, opcTJmp
  169. proc xjmp(c: var ProcCon; n: PNode; jk: JmpKind; v: Value): LabelId =
  170. result = newLabel(c.labelGen)
  171. let info = toLineInfo(c, n.info)
  172. buildTyped c.code, info, Select, Bool8Id:
  173. c.code.copyTree Tree(v)
  174. build c.code, info, SelectPair:
  175. build c.code, info, SelectValue:
  176. c.code.boolVal(c.lit.numbers, info, jk == opcTJmp)
  177. c.code.gotoLabel info, Goto, result
  178. proc patch(c: var ProcCon; n: PNode; L: LabelId) =
  179. addLabel c.code, toLineInfo(c, n.info), Label, L
  180. proc genWhile(c: var ProcCon; n: PNode) =
  181. # lab1:
  182. # cond, tmp
  183. # fjmp tmp, lab2
  184. # body
  185. # jmp lab1
  186. # lab2:
  187. let info = toLineInfo(c, n.info)
  188. let lab1 = c.code.addNewLabel(c.labelGen, info, LoopLabel)
  189. withBlock(nil, info, lab1):
  190. if isTrue(n[0]):
  191. c.gen(n[1])
  192. c.jmpBack(n, lab1)
  193. elif isNotOpr(n[0]):
  194. var tmp = c.genx(n[0][1])
  195. let lab2 = c.xjmp(n, opcTJmp, tmp)
  196. c.freeTemp(tmp)
  197. c.gen(n[1])
  198. c.jmpBack(n, lab1)
  199. c.patch(n, lab2)
  200. else:
  201. var tmp = c.genx(n[0])
  202. let lab2 = c.xjmp(n, opcFJmp, tmp)
  203. c.freeTemp(tmp)
  204. c.gen(n[1])
  205. c.jmpBack(n, lab1)
  206. c.patch(n, lab2)
  207. proc genBlock(c: var ProcCon; n: PNode; d: var Value) =
  208. openScope c.sm
  209. let info = toLineInfo(c, n.info)
  210. let lab1 = newLabel(c.labelGen)
  211. withBlock(n[0].sym, info, lab1):
  212. c.gen(n[1], d)
  213. c.code.addLabel(info, Label, lab1)
  214. closeScope c.sm
  215. c.clearDest(n, d)
  216. proc jumpTo(c: var ProcCon; n: PNode; L: LabelId) =
  217. c.code.addLabel(toLineInfo(c, n.info), Goto, L)
  218. proc genBreak(c: var ProcCon; n: PNode) =
  219. if n[0].kind == nkSym:
  220. for i in countdown(c.blocks.len-1, 0):
  221. if c.blocks[i][0] == n[0].sym:
  222. c.jumpTo n, c.blocks[i][1]
  223. return
  224. localError(c.config, n.info, "NIR problem: cannot find 'break' target")
  225. else:
  226. c.jumpTo n, c.blocks[c.blocks.high][1]
  227. proc genIf(c: var ProcCon; n: PNode; d: var Value) =
  228. # if (!expr1) goto lab1;
  229. # thenPart
  230. # goto LEnd
  231. # lab1:
  232. # if (!expr2) goto lab2;
  233. # thenPart2
  234. # goto LEnd
  235. # lab2:
  236. # elsePart
  237. # Lend:
  238. if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n)
  239. var ending = newLabel(c.labelGen)
  240. for i in 0..<n.len:
  241. var it = n[i]
  242. if it.len == 2:
  243. let info = toLineInfo(c, it[0].info)
  244. var elsePos: LabelId
  245. if isNotOpr(it[0]):
  246. let tmp = c.genx(it[0][1])
  247. elsePos = c.xjmp(it[0][1], opcTJmp, tmp) # if true
  248. c.freeTemp tmp
  249. else:
  250. let tmp = c.genx(it[0])
  251. elsePos = c.xjmp(it[0], opcFJmp, tmp) # if false
  252. c.freeTemp tmp
  253. c.clearDest(n, d)
  254. if isEmptyType(it[1].typ): # maybe noreturn call, don't touch `d`
  255. c.genScope(it[1])
  256. else:
  257. c.genScope(it[1], d) # then part
  258. if i < n.len-1:
  259. c.jumpTo it[1], ending
  260. c.patch(it, elsePos)
  261. else:
  262. c.clearDest(n, d)
  263. if isEmptyType(it[0].typ): # maybe noreturn call, don't touch `d`
  264. c.genScope(it[0])
  265. else:
  266. c.genScope(it[0], d)
  267. c.patch(n, ending)
  268. c.clearDest(n, d)
  269. proc tempToDest(c: var ProcCon; n: PNode; d: var Value; tmp: Value) =
  270. if isEmpty(d):
  271. d = tmp
  272. else:
  273. let info = toLineInfo(c, n.info)
  274. buildTyped c.code, info, Asgn, typeToIr(c.m, n.typ):
  275. c.code.copyTree d
  276. c.code.copyTree tmp
  277. freeTemp(c, tmp)
  278. proc genAndOr(c: var ProcCon; n: PNode; opc: JmpKind; d: var Value) =
  279. # asgn d, a
  280. # tjmp|fjmp lab1
  281. # asgn d, b
  282. # lab1:
  283. var tmp = getTemp(c, n)
  284. c.gen(n[1], tmp)
  285. let lab1 = c.xjmp(n, opc, tmp)
  286. c.gen(n[2], tmp)
  287. c.patch(n, lab1)
  288. tempToDest c, n, d, tmp
  289. proc unused(c: var ProcCon; n: PNode; x: Value) {.inline.} =
  290. if hasValue(x):
  291. #debug(n)
  292. localError(c.config, n.info, "not unused")
  293. proc caseValue(c: var ProcCon; n: PNode) =
  294. let info = toLineInfo(c, n.info)
  295. build c.code, info, SelectValue:
  296. let x = genx(c, n)
  297. c.code.copyTree x
  298. freeTemp(c, x)
  299. proc caseRange(c: var ProcCon; n: PNode) =
  300. let info = toLineInfo(c, n.info)
  301. build c.code, info, SelectRange:
  302. let x = genx(c, n[0])
  303. let y = genx(c, n[1])
  304. c.code.copyTree x
  305. c.code.copyTree y
  306. freeTemp(c, y)
  307. freeTemp(c, x)
  308. proc addUseCodegenProc(c: var ProcCon; dest: var Tree; name: string; info: PackedLineInfo) =
  309. let cp = getCompilerProc(c.m.graph, name)
  310. let theProc = c.genx newSymNode(cp)
  311. copyTree c.code, theProc
  312. template buildCond(useNegation: bool; cond: typed; body: untyped) =
  313. let lab = newLabel(c.labelGen)
  314. buildTyped c.code, info, Select, Bool8Id:
  315. c.code.copyTree cond
  316. build c.code, info, SelectPair:
  317. build c.code, info, SelectValue:
  318. c.code.boolVal(c.lit.numbers, info, useNegation)
  319. c.code.gotoLabel info, Goto, lab
  320. body
  321. c.code.addLabel info, Label, lab
  322. template buildIf(cond: typed; body: untyped) =
  323. buildCond false, cond, body
  324. template buildIfNot(cond: typed; body: untyped) =
  325. buildCond true, cond, body
  326. template buildIfThenElse(cond: typed; then, otherwise: untyped) =
  327. let lelse = newLabel(c.labelGen)
  328. let lend = newLabel(c.labelGen)
  329. buildTyped c.code, info, Select, Bool8Id:
  330. c.code.copyTree cond
  331. build c.code, info, SelectPair:
  332. build c.code, info, SelectValue:
  333. c.code.boolVal(c.lit.numbers, info, false)
  334. c.code.gotoLabel info, Goto, lelse
  335. then()
  336. c.code.gotoLabel info, Goto, lend
  337. c.code.addLabel info, Label, lelse
  338. otherwise()
  339. c.code.addLabel info, Label, lend
  340. include stringcases
  341. proc genCase(c: var ProcCon; n: PNode; d: var Value) =
  342. if not isEmptyType(n.typ):
  343. if isEmpty(d): d = getTemp(c, n)
  344. else:
  345. unused(c, n, d)
  346. if n[0].typ.skipTypes(abstractInst).kind == tyString:
  347. genStringCase(c, n, d)
  348. return
  349. var sections = newSeqOfCap[LabelId](n.len-1)
  350. let ending = newLabel(c.labelGen)
  351. let info = toLineInfo(c, n.info)
  352. let tmp = c.genx(n[0])
  353. buildTyped c.code, info, Select, typeToIr(c.m, n[0].typ):
  354. c.code.copyTree tmp
  355. for i in 1..<n.len:
  356. let section = newLabel(c.labelGen)
  357. sections.add section
  358. let it = n[i]
  359. let itinfo = toLineInfo(c, it.info)
  360. build c.code, itinfo, SelectPair:
  361. build c.code, itinfo, SelectList:
  362. for j in 0..<it.len-1:
  363. if it[j].kind == nkRange:
  364. caseRange c, it[j]
  365. else:
  366. caseValue c, it[j]
  367. c.code.addLabel itinfo, Goto, section
  368. c.freeTemp tmp
  369. for i in 1..<n.len:
  370. let it = n[i]
  371. let itinfo = toLineInfo(c, it.info)
  372. c.code.addLabel itinfo, Label, sections[i-1]
  373. c.gen it.lastSon
  374. if i != n.len-1:
  375. c.code.addLabel itinfo, Goto, ending
  376. c.code.addLabel info, Label, ending
  377. proc rawCall(c: var ProcCon; info: PackedLineInfo; opc: Opcode; t: TypeId; args: var openArray[Value]) =
  378. buildTyped c.code, info, opc, t:
  379. if opc in {CheckedCall, CheckedIndirectCall}:
  380. c.code.addLabel info, CheckedGoto, c.exitLabel
  381. for a in mitems(args):
  382. c.code.copyTree a
  383. freeTemp c, a
  384. proc canRaiseDisp(c: ProcCon; n: PNode): bool =
  385. # we assume things like sysFatal cannot raise themselves
  386. if n.kind == nkSym and {sfNeverRaises, sfImportc, sfCompilerProc} * n.sym.flags != {}:
  387. result = false
  388. elif optPanics in c.config.globalOptions or
  389. (n.kind == nkSym and sfSystemModule in getModule(n.sym).flags and
  390. sfSystemRaisesDefect notin n.sym.flags):
  391. # we know we can be strict:
  392. result = canRaise(n)
  393. else:
  394. # we have to be *very* conservative:
  395. result = canRaiseConservative(n)
  396. proc genCall(c: var ProcCon; n: PNode; d: var Value) =
  397. let canRaise = canRaiseDisp(c, n[0])
  398. let opc = if n[0].kind == nkSym and n[0].sym.kind in routineKinds:
  399. (if canRaise: CheckedCall else: Call)
  400. else:
  401. (if canRaise: CheckedIndirectCall else: IndirectCall)
  402. let info = toLineInfo(c, n.info)
  403. # In the IR we cannot nest calls. Thus we use two passes:
  404. var args: seq[Value] = @[]
  405. var t = n[0].typ
  406. if t != nil: t = t.skipTypes(abstractInst)
  407. args.add genx(c, n[0])
  408. for i in 1..<n.len:
  409. if t != nil and i < t.len:
  410. if isCompileTimeOnly(t[i]): discard
  411. elif isOutParam(t[i]): args.add genx(c, n[i], {gfToOutParam})
  412. else: args.add genx(c, n[i])
  413. else:
  414. args.add genx(c, n[i])
  415. let tb = typeToIr(c.m, n.typ)
  416. if not isEmptyType(n.typ):
  417. if isEmpty(d): d = getTemp(c, n)
  418. # XXX Handle problematic aliasing here: `a = f_canRaise(a)`.
  419. buildTyped c.code, info, Asgn, tb:
  420. c.code.copyTree d
  421. rawCall c, info, opc, tb, args
  422. else:
  423. rawCall c, info, opc, tb, args
  424. freeTemps c, args
  425. proc genRaise(c: var ProcCon; n: PNode) =
  426. let info = toLineInfo(c, n.info)
  427. let tb = typeToIr(c.m, n[0].typ)
  428. let d = genx(c, n[0])
  429. buildTyped c.code, info, SetExc, tb:
  430. c.code.copyTree d
  431. c.freeTemp(d)
  432. c.code.addLabel info, Goto, c.exitLabel
  433. proc genReturn(c: var ProcCon; n: PNode) =
  434. if n[0].kind != nkEmpty:
  435. gen(c, n[0])
  436. # XXX Block leave actions?
  437. let info = toLineInfo(c, n.info)
  438. c.code.addLabel info, Goto, c.exitLabel
  439. proc genTry(c: var ProcCon; n: PNode; d: var Value) =
  440. if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n)
  441. var endings: seq[LabelId] = @[]
  442. let ehPos = newLabel(c.labelGen)
  443. let oldExitLab = c.exitLabel
  444. c.exitLabel = ehPos
  445. if isEmptyType(n[0].typ): # maybe noreturn call, don't touch `d`
  446. c.gen(n[0])
  447. else:
  448. c.gen(n[0], d)
  449. c.clearDest(n, d)
  450. # Add a jump past the exception handling code
  451. let jumpToFinally = newLabel(c.labelGen)
  452. c.jumpTo n, jumpToFinally
  453. # This signals where the body ends and where the exception handling begins
  454. c.patch(n, ehPos)
  455. c.exitLabel = oldExitLab
  456. for i in 1..<n.len:
  457. let it = n[i]
  458. if it.kind != nkFinally:
  459. # first opcExcept contains the end label of the 'except' block:
  460. let endExcept = newLabel(c.labelGen)
  461. for j in 0..<it.len - 1:
  462. assert(it[j].kind == nkType)
  463. let typ = it[j].typ.skipTypes(abstractPtrs-{tyTypeDesc})
  464. let itinfo = toLineInfo(c, it[j].info)
  465. build c.code, itinfo, TestExc:
  466. c.code.addTyped itinfo, typeToIr(c.m, typ)
  467. if it.len == 1:
  468. let itinfo = toLineInfo(c, it.info)
  469. build c.code, itinfo, TestExc:
  470. c.code.addTyped itinfo, VoidId
  471. let body = it.lastSon
  472. if isEmptyType(body.typ): # maybe noreturn call, don't touch `d`
  473. c.gen(body)
  474. else:
  475. c.gen(body, d)
  476. c.clearDest(n, d)
  477. if i < n.len:
  478. endings.add newLabel(c.labelGen)
  479. c.patch(it, endExcept)
  480. let fin = lastSon(n)
  481. # we always generate an 'opcFinally' as that pops the safepoint
  482. # from the stack if no exception is raised in the body.
  483. c.patch(fin, jumpToFinally)
  484. #c.gABx(fin, opcFinally, 0, 0)
  485. for endPos in endings: c.patch(n, endPos)
  486. if fin.kind == nkFinally:
  487. c.gen(fin[0])
  488. c.clearDest(n, d)
  489. #c.gABx(fin, opcFinallyEnd, 0, 0)
  490. template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
  491. proc isGlobal(n: PNode): bool = n.kind == nkSym and isGlobal(n.sym)
  492. proc genField(c: var ProcCon; n: PNode; d: var Value) =
  493. var pos: int
  494. if n.kind != nkSym or n.sym.kind != skField:
  495. localError(c.config, n.info, "no field symbol")
  496. pos = 0
  497. else:
  498. pos = n.sym.position
  499. d.addImmediateVal toLineInfo(c, n.info), pos
  500. proc genIndex(c: var ProcCon; n: PNode; arr: PType; d: var Value) =
  501. let info = toLineInfo(c, n.info)
  502. if arr.skipTypes(abstractInst).kind == tyArray and
  503. (let offset = firstOrd(c.config, arr); offset != Zero):
  504. let x = c.genx(n)
  505. buildTyped d, info, Sub, c.m.nativeIntId:
  506. copyTree d.Tree, x
  507. d.addImmediateVal toLineInfo(c, n.info), toInt(offset)
  508. else:
  509. c.gen(n, d)
  510. if optBoundsCheck in c.options:
  511. let idx = move d
  512. build d, info, CheckedIndex:
  513. d.Tree.addLabel info, CheckedGoto, c.exitLabel
  514. copyTree d.Tree, idx
  515. let x = toInt64 lengthOrd(c.config, arr)
  516. d.addIntVal c.lit.numbers, info, c.m.nativeIntId, x
  517. proc rawGenNew(c: var ProcCon; d: Value; refType: PType; ninfo: TLineInfo; needsInit: bool) =
  518. assert refType.kind == tyRef
  519. let baseType = refType.elementType
  520. let info = toLineInfo(c, ninfo)
  521. let codegenProc = magicsys.getCompilerProc(c.m.graph,
  522. if needsInit: "nimNewObj" else: "nimNewObjUninit")
  523. let refTypeIr = typeToIr(c.m, refType)
  524. buildTyped c.code, info, Asgn, refTypeIr:
  525. copyTree c.code, d
  526. buildTyped c.code, info, Cast, refTypeIr:
  527. buildTyped c.code, info, Call, VoidPtrId:
  528. let theProc = c.genx newSymNode(codegenProc, ninfo)
  529. copyTree c.code, theProc
  530. c.code.addImmediateVal info, int(getSize(c.config, baseType))
  531. c.code.addImmediateVal info, int(getAlign(c.config, baseType))
  532. proc genNew(c: var ProcCon; n: PNode; needsInit: bool) =
  533. # If in doubt, always follow the blueprint of the C code generator for `mm:orc`.
  534. let refType = n[1].typ.skipTypes(abstractInstOwned)
  535. let d = genx(c, n[1])
  536. rawGenNew c, d, refType, n.info, needsInit
  537. freeTemp c, d
  538. proc genNewSeqOfCap(c: var ProcCon; n: PNode; d: var Value) =
  539. let info = toLineInfo(c, n.info)
  540. let seqtype = skipTypes(n.typ, abstractVarRange)
  541. let baseType = seqtype.elementType
  542. var a = c.genx(n[1])
  543. if isEmpty(d): d = getTemp(c, n)
  544. # $1.len = 0
  545. buildTyped c.code, info, Asgn, c.m.nativeIntId:
  546. buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype):
  547. copyTree c.code, d
  548. c.code.addImmediateVal info, 0
  549. c.code.addImmediateVal info, 0
  550. # $1.p = ($4*) #newSeqPayloadUninit($2, sizeof($3), NIM_ALIGNOF($3))
  551. let payloadPtr = seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[0]
  552. buildTyped c.code, info, Asgn, payloadPtr:
  553. # $1.p
  554. buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype):
  555. copyTree c.code, d
  556. c.code.addImmediateVal info, 1
  557. # ($4*) #newSeqPayloadUninit($2, sizeof($3), NIM_ALIGNOF($3))
  558. buildTyped c.code, info, Cast, payloadPtr:
  559. buildTyped c.code, info, Call, VoidPtrId:
  560. let codegenProc = magicsys.getCompilerProc(c.m.graph, "newSeqPayloadUninit")
  561. let theProc = c.genx newSymNode(codegenProc, n.info)
  562. copyTree c.code, theProc
  563. copyTree c.code, a
  564. c.code.addImmediateVal info, int(getSize(c.config, baseType))
  565. c.code.addImmediateVal info, int(getAlign(c.config, baseType))
  566. freeTemp c, a
  567. proc genNewSeqPayload(c: var ProcCon; info: PackedLineInfo; d, b: Value; seqtype: PType) =
  568. let baseType = seqtype.elementType
  569. # $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3))
  570. let payloadPtr = seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[0]
  571. # $1.len = $2
  572. buildTyped c.code, info, Asgn, c.m.nativeIntId:
  573. buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype):
  574. copyTree c.code, d
  575. c.code.addImmediateVal info, 0
  576. copyTree c.code, b
  577. buildTyped c.code, info, Asgn, payloadPtr:
  578. # $1.p
  579. buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype):
  580. copyTree c.code, d
  581. c.code.addImmediateVal info, 1
  582. # ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3))
  583. buildTyped c.code, info, Cast, payloadPtr:
  584. buildTyped c.code, info, Call, VoidPtrId:
  585. let codegenProc = magicsys.getCompilerProc(c.m.graph, "newSeqPayload")
  586. let theProc = c.genx newSymNode(codegenProc)
  587. copyTree c.code, theProc
  588. copyTree c.code, b
  589. c.code.addImmediateVal info, int(getSize(c.config, baseType))
  590. c.code.addImmediateVal info, int(getAlign(c.config, baseType))
  591. proc genNewSeq(c: var ProcCon; n: PNode) =
  592. let info = toLineInfo(c, n.info)
  593. let seqtype = skipTypes(n[1].typ, abstractVarRange)
  594. var d = c.genx(n[1])
  595. var b = c.genx(n[2])
  596. genNewSeqPayload(c, info, d, b, seqtype)
  597. freeTemp c, b
  598. freeTemp c, d
  599. template intoDest*(d: var Value; info: PackedLineInfo; typ: TypeId; body: untyped) =
  600. if typ == VoidId:
  601. body(c.code)
  602. elif isEmpty(d):
  603. body(Tree(d))
  604. else:
  605. buildTyped c.code, info, Asgn, typ:
  606. copyTree c.code, d
  607. body(c.code)
  608. template valueIntoDest(c: var ProcCon; info: PackedLineInfo; d: var Value; typ: PType; body: untyped) =
  609. if isEmpty(d):
  610. body(Tree d)
  611. else:
  612. buildTyped c.code, info, Asgn, typeToIr(c.m, typ):
  613. copyTree c.code, d
  614. body(c.code)
  615. template constrIntoDest(c: var ProcCon; info: PackedLineInfo; d: var Value; typ: PType; body: untyped) =
  616. var tmp = default(Value)
  617. body(Tree tmp)
  618. if isEmpty(d):
  619. d = tmp
  620. else:
  621. buildTyped c.code, info, Asgn, typeToIr(c.m, typ):
  622. copyTree c.code, d
  623. copyTree c.code, tmp
  624. proc genBinaryOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) =
  625. let info = toLineInfo(c, n.info)
  626. let tmp = c.genx(n[1])
  627. let tmp2 = c.genx(n[2])
  628. let t = typeToIr(c.m, n.typ)
  629. template body(target) =
  630. buildTyped target, info, opc, t:
  631. if opc in {CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedMod}:
  632. target.addLabel info, CheckedGoto, c.exitLabel
  633. copyTree target, tmp
  634. copyTree target, tmp2
  635. intoDest d, info, t, body
  636. c.freeTemp(tmp)
  637. c.freeTemp(tmp2)
  638. proc genCmpOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) =
  639. let info = toLineInfo(c, n.info)
  640. let tmp = c.genx(n[1])
  641. let tmp2 = c.genx(n[2])
  642. let t = typeToIr(c.m, n[1].typ)
  643. template body(target) =
  644. buildTyped target, info, opc, t:
  645. copyTree target, tmp
  646. copyTree target, tmp2
  647. intoDest d, info, Bool8Id, body
  648. c.freeTemp(tmp)
  649. c.freeTemp(tmp2)
  650. proc genUnaryOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) =
  651. let info = toLineInfo(c, n.info)
  652. let tmp = c.genx(n[1])
  653. let t = typeToIr(c.m, n.typ)
  654. template body(target) =
  655. buildTyped target, info, opc, t:
  656. copyTree target, tmp
  657. intoDest d, info, t, body
  658. c.freeTemp(tmp)
  659. proc genIncDec(c: var ProcCon; n: PNode; opc: Opcode) =
  660. let info = toLineInfo(c, n.info)
  661. let t = typeToIr(c.m, skipTypes(n[1].typ, abstractVar))
  662. let d = c.genx(n[1])
  663. let tmp = c.genx(n[2])
  664. # we produce code like: i = i + 1
  665. buildTyped c.code, info, Asgn, t:
  666. copyTree c.code, d
  667. buildTyped c.code, info, opc, t:
  668. if opc in {CheckedAdd, CheckedSub}:
  669. c.code.addLabel info, CheckedGoto, c.exitLabel
  670. copyTree c.code, d
  671. copyTree c.code, tmp
  672. c.freeTemp(tmp)
  673. #c.genNarrow(n[1], d)
  674. c.freeTemp(d)
  675. proc genArrayLen(c: var ProcCon; n: PNode; d: var Value) =
  676. #echo c.m.graph.config $ n.info, " ", n
  677. let info = toLineInfo(c, n.info)
  678. var a = n[1]
  679. #if a.kind == nkHiddenAddr: a = a[0]
  680. var typ = skipTypes(a.typ, abstractVar + tyUserTypeClasses)
  681. case typ.kind
  682. of tyOpenArray, tyVarargs:
  683. let xa = c.genx(a)
  684. template body(target) =
  685. buildTyped target, info, FieldAt, typeToIr(c.m, typ):
  686. copyTree target, xa
  687. target.addImmediateVal info, 1 # (p, len)-pair so len is at index 1
  688. intoDest d, info, c.m.nativeIntId, body
  689. of tyCstring:
  690. let xa = c.genx(a)
  691. if isEmpty(d): d = getTemp(c, n)
  692. buildTyped c.code, info, Call, c.m.nativeIntId:
  693. let codegenProc = magicsys.getCompilerProc(c.m.graph, "nimCStrLen")
  694. assert codegenProc != nil
  695. let theProc = c.genx newSymNode(codegenProc, n.info)
  696. copyTree c.code, theProc
  697. copyTree c.code, xa
  698. of tyString, tySequence:
  699. let xa = c.genx(a)
  700. if typ.kind == tySequence:
  701. # we go through a temporary here because people write bullshit code.
  702. if isEmpty(d): d = getTemp(c, n)
  703. template body(target) =
  704. buildTyped target, info, FieldAt, typeToIr(c.m, typ):
  705. copyTree target, xa
  706. target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
  707. intoDest d, info, c.m.nativeIntId, body
  708. of tyArray:
  709. template body(target) =
  710. target.addIntVal(c.lit.numbers, info, c.m.nativeIntId, toInt lengthOrd(c.config, typ))
  711. intoDest d, info, c.m.nativeIntId, body
  712. else: internalError(c.config, n.info, "genArrayLen()")
  713. proc genUnaryMinus(c: var ProcCon; n: PNode; d: var Value) =
  714. let info = toLineInfo(c, n.info)
  715. let tmp = c.genx(n[1])
  716. let t = typeToIr(c.m, n.typ)
  717. template body(target) =
  718. buildTyped target, info, Sub, t:
  719. # Little hack: This works because we know that `0.0` is all 0 bits:
  720. target.addIntVal(c.lit.numbers, info, t, 0)
  721. copyTree target, tmp
  722. intoDest d, info, t, body
  723. c.freeTemp(tmp)
  724. proc genHigh(c: var ProcCon; n: PNode; d: var Value) =
  725. let info = toLineInfo(c, n.info)
  726. let t = typeToIr(c.m, n.typ)
  727. var x = default(Value)
  728. genArrayLen(c, n, x)
  729. template body(target) =
  730. buildTyped target, info, Sub, t:
  731. copyTree target, x
  732. target.addIntVal(c.lit.numbers, info, t, 1)
  733. intoDest d, info, t, body
  734. c.freeTemp x
  735. proc genBinaryCp(c: var ProcCon; n: PNode; d: var Value; compilerProc: string) =
  736. let info = toLineInfo(c, n.info)
  737. let xa = c.genx(n[1])
  738. let xb = c.genx(n[2])
  739. if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n)
  740. let t = typeToIr(c.m, n.typ)
  741. template body(target) =
  742. buildTyped target, info, Call, t:
  743. let codegenProc = magicsys.getCompilerProc(c.m.graph, compilerProc)
  744. #assert codegenProc != nil, $n & " " & (c.m.graph.config $ n.info)
  745. let theProc = c.genx newSymNode(codegenProc, n.info)
  746. copyTree target, theProc
  747. copyTree target, xa
  748. copyTree target, xb
  749. intoDest d, info, t, body
  750. c.freeTemp xb
  751. c.freeTemp xa
  752. proc genUnaryCp(c: var ProcCon; n: PNode; d: var Value; compilerProc: string; argAt = 1) =
  753. let info = toLineInfo(c, n.info)
  754. let xa = c.genx(n[argAt])
  755. if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n)
  756. let t = typeToIr(c.m, n.typ)
  757. template body(target) =
  758. buildTyped target, info, Call, t:
  759. let codegenProc = magicsys.getCompilerProc(c.m.graph, compilerProc)
  760. let theProc = c.genx newSymNode(codegenProc, n.info)
  761. copyTree target, theProc
  762. copyTree target, xa
  763. intoDest d, info, t, body
  764. c.freeTemp xa
  765. proc genEnumToStr(c: var ProcCon; n: PNode; d: var Value) =
  766. let t = n[1].typ.skipTypes(abstractInst+{tyRange})
  767. let toStrProc = getToStringProc(c.m.graph, t)
  768. # XXX need to modify this logic for IC.
  769. var nb = copyTree(n)
  770. nb[0] = newSymNode(toStrProc)
  771. gen(c, nb, d)
  772. proc genOf(c: var ProcCon; n: PNode; d: var Value) =
  773. genUnaryOp c, n, d, TestOf
  774. template sizeOfLikeMsg(name): string =
  775. "'" & name & "' requires '.importc' types to be '.completeStruct'"
  776. proc genIsNil(c: var ProcCon; n: PNode; d: var Value) =
  777. let info = toLineInfo(c, n.info)
  778. let tmp = c.genx(n[1])
  779. let t = typeToIr(c.m, n[1].typ)
  780. template body(target) =
  781. buildTyped target, info, Eq, t:
  782. copyTree target, tmp
  783. addNilVal target, info, t
  784. intoDest d, info, Bool8Id, body
  785. c.freeTemp(tmp)
  786. proc fewCmps(conf: ConfigRef; s: PNode): bool =
  787. # this function estimates whether it is better to emit code
  788. # for constructing the set or generating a bunch of comparisons directly
  789. if s.kind != nkCurly:
  790. result = false
  791. elif (getSize(conf, s.typ) <= conf.target.intSize) and (nfAllConst in s.flags):
  792. result = false # it is better to emit the set generation code
  793. elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}:
  794. result = true # better not emit the set if int is basetype!
  795. else:
  796. result = s.len <= 8 # 8 seems to be a good value
  797. proc genInBitset(c: var ProcCon; n: PNode; d: var Value) =
  798. let info = toLineInfo(c, n.info)
  799. let a = c.genx(n[1])
  800. let b = c.genx(n[2])
  801. let t = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ)
  802. let setType = typeToIr(c.m, n[1].typ)
  803. let mask =
  804. case t
  805. of UInt8Id: 7
  806. of UInt16Id: 15
  807. of UInt32Id: 31
  808. else: 63
  809. let expansion = if t == UInt64Id: UInt64Id else: c.m.nativeUIntId
  810. # "(($1 &(1U<<((NU)($2)&7U)))!=0)" - or -
  811. # "(($1[(NU)($2)>>3] &(1U<<((NU)($2)&7U)))!=0)"
  812. template body(target) =
  813. buildTyped target, info, BoolNot, Bool8Id:
  814. buildTyped target, info, Eq, t:
  815. buildTyped target, info, BitAnd, t:
  816. if c.m.nirm.types[setType].kind != ArrayTy:
  817. copyTree target, a
  818. else:
  819. buildTyped target, info, ArrayAt, setType:
  820. copyTree target, a
  821. buildTyped target, info, BitShr, t:
  822. buildTyped target, info, Cast, expansion:
  823. copyTree target, b
  824. addIntVal target, c.lit.numbers, info, expansion, 3
  825. buildTyped target, info, BitShl, t:
  826. addIntVal target, c.lit.numbers, info, t, 1
  827. buildTyped target, info, BitAnd, t:
  828. buildTyped target, info, Cast, expansion:
  829. copyTree target, b
  830. addIntVal target, c.lit.numbers, info, expansion, mask
  831. addIntVal target, c.lit.numbers, info, t, 0
  832. intoDest d, info, t, body
  833. c.freeTemp(b)
  834. c.freeTemp(a)
  835. proc genInSet(c: var ProcCon; n: PNode; d: var Value) =
  836. let g {.cursor.} = c.m.graph
  837. if n[1].kind == nkCurly and fewCmps(g.config, n[1]):
  838. # a set constructor but not a constant set:
  839. # do not emit the set, but generate a bunch of comparisons; and if we do
  840. # so, we skip the unnecessary range check: This is a semantical extension
  841. # that code now relies on. :-/ XXX
  842. let elem = if n[2].kind in {nkChckRange, nkChckRange64}: n[2][0]
  843. else: n[2]
  844. let curly = n[1]
  845. var ex: PNode = nil
  846. for it in curly:
  847. var test: PNode
  848. if it.kind == nkRange:
  849. test = newTree(nkCall, g.operators.opAnd.newSymNode,
  850. newTree(nkCall, g.operators.opLe.newSymNode, it[0], elem), # a <= elem
  851. newTree(nkCall, g.operators.opLe.newSymNode, elem, it[1])
  852. )
  853. else:
  854. test = newTree(nkCall, g.operators.opEq.newSymNode, elem, it)
  855. test.typ = getSysType(g, it.info, tyBool)
  856. if ex == nil: ex = test
  857. else: ex = newTree(nkCall, g.operators.opOr.newSymNode, ex, test)
  858. if ex == nil:
  859. let info = toLineInfo(c, n.info)
  860. template body(target) =
  861. boolVal target, c.lit.numbers, info, false
  862. intoDest d, info, Bool8Id, body
  863. else:
  864. gen c, ex, d
  865. else:
  866. genInBitset c, n, d
  867. proc genCard(c: var ProcCon; n: PNode; d: var Value) =
  868. let info = toLineInfo(c, n.info)
  869. let a = c.genx(n[1])
  870. let t = typeToIr(c.m, n.typ)
  871. let setType = typeToIr(c.m, n[1].typ)
  872. if isEmpty(d): d = getTemp(c, n)
  873. buildTyped c.code, info, Asgn, t:
  874. copyTree c.code, d
  875. buildTyped c.code, info, Call, t:
  876. if c.m.nirm.types[setType].kind == ArrayTy:
  877. let codegenProc = magicsys.getCompilerProc(c.m.graph, "cardSet")
  878. let theProc = c.genx newSymNode(codegenProc, n.info)
  879. copyTree c.code, theProc
  880. buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, setType):
  881. copyTree c.code, a
  882. c.code.addImmediateVal info, int(getSize(c.config, n[1].typ))
  883. elif t == UInt64Id:
  884. let codegenProc = magicsys.getCompilerProc(c.m.graph, "countBits64")
  885. let theProc = c.genx newSymNode(codegenProc, n.info)
  886. copyTree c.code, theProc
  887. copyTree c.code, a
  888. else:
  889. let codegenProc = magicsys.getCompilerProc(c.m.graph, "countBits32")
  890. let theProc = c.genx newSymNode(codegenProc, n.info)
  891. copyTree c.code, theProc
  892. buildTyped c.code, info, Cast, UInt32Id:
  893. copyTree c.code, a
  894. freeTemp c, a
  895. proc genEqSet(c: var ProcCon; n: PNode; d: var Value) =
  896. let info = toLineInfo(c, n.info)
  897. let a = c.genx(n[1])
  898. let b = c.genx(n[2])
  899. let t = typeToIr(c.m, n.typ)
  900. let setType = typeToIr(c.m, n[1].typ)
  901. if c.m.nirm.types[setType].kind == ArrayTy:
  902. if isEmpty(d): d = getTemp(c, n)
  903. buildTyped c.code, info, Asgn, t:
  904. copyTree c.code, d
  905. buildTyped c.code, info, Eq, t:
  906. buildTyped c.code, info, Call, t:
  907. let codegenProc = magicsys.getCompilerProc(c.m.graph, "nimCmpMem")
  908. let theProc = c.genx newSymNode(codegenProc, n.info)
  909. copyTree c.code, theProc
  910. buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, setType):
  911. copyTree c.code, a
  912. buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, setType):
  913. copyTree c.code, b
  914. c.code.addImmediateVal info, int(getSize(c.config, n[1].typ))
  915. c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
  916. else:
  917. template body(target) =
  918. buildTyped target, info, Eq, setType:
  919. copyTree target, a
  920. copyTree target, b
  921. intoDest d, info, Bool8Id, body
  922. freeTemp c, b
  923. freeTemp c, a
  924. proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: int): (SymId, LabelId, LabelId) =
  925. let tmp = allocTemp(c, c.m.nativeIntId)
  926. c.code.addSummon info, tmp, c.m.nativeIntId
  927. buildTyped c.code, info, Asgn, c.m.nativeIntId:
  928. c.code.addSymUse info, tmp
  929. c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, first
  930. let lab1 = c.code.addNewLabel(c.labelGen, info, LoopLabel)
  931. result = (tmp, lab1, newLabel(c.labelGen))
  932. buildTyped c.code, info, Select, Bool8Id:
  933. buildTyped c.code, info, Lt, c.m.nativeIntId:
  934. c.code.addSymUse info, tmp
  935. c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, last
  936. build c.code, info, SelectPair:
  937. build c.code, info, SelectValue:
  938. c.code.boolVal(c.lit.numbers, info, false)
  939. c.code.gotoLabel info, Goto, result[2]
  940. proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: Value): (SymId, LabelId, LabelId) =
  941. let tmp = allocTemp(c, c.m.nativeIntId)
  942. c.code.addSummon info, tmp, c.m.nativeIntId
  943. buildTyped c.code, info, Asgn, c.m.nativeIntId:
  944. c.code.addSymUse info, tmp
  945. copyTree c.code, first
  946. let lab1 = c.code.addNewLabel(c.labelGen, info, LoopLabel)
  947. result = (tmp, lab1, newLabel(c.labelGen))
  948. buildTyped c.code, info, Select, Bool8Id:
  949. buildTyped c.code, info, Le, c.m.nativeIntId:
  950. c.code.addSymUse info, tmp
  951. copyTree c.code, last
  952. build c.code, info, SelectPair:
  953. build c.code, info, SelectValue:
  954. c.code.boolVal(c.lit.numbers, info, false)
  955. c.code.gotoLabel info, Goto, result[2]
  956. proc endLoop(c: var ProcCon; info: PackedLineInfo; s: SymId; back, exit: LabelId) =
  957. buildTyped c.code, info, Asgn, c.m.nativeIntId:
  958. c.code.addSymUse info, s
  959. buildTyped c.code, info, Add, c.m.nativeIntId:
  960. c.code.addSymUse info, s
  961. c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1
  962. c.code.addLabel info, GotoLoop, back
  963. c.code.addLabel info, Label, exit
  964. freeTemp(c.sm, s)
  965. proc genLeSet(c: var ProcCon; n: PNode; d: var Value) =
  966. let info = toLineInfo(c, n.info)
  967. let a = c.genx(n[1])
  968. let b = c.genx(n[2])
  969. let t = typeToIr(c.m, n.typ)
  970. let setType = typeToIr(c.m, n[1].typ)
  971. if c.m.nirm.types[setType].kind == ArrayTy:
  972. let elemType = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ)
  973. if isEmpty(d): d = getTemp(c, n)
  974. # "for ($1 = 0; $1 < $2; $1++):"
  975. # " $3 = (($4[$1] & ~ $5[$1]) == 0)"
  976. # " if (!$3) break;"
  977. let (idx, backLabel, endLabel) = beginCountLoop(c, info, 0, int(getSize(c.config, n[1].typ)))
  978. buildTyped c.code, info, Asgn, Bool8Id:
  979. copyTree c.code, d
  980. buildTyped c.code, info, Eq, elemType:
  981. buildTyped c.code, info, BitAnd, elemType:
  982. buildTyped c.code, info, ArrayAt, setType:
  983. copyTree c.code, a
  984. c.code.addSymUse info, idx
  985. buildTyped c.code, info, BitNot, elemType:
  986. buildTyped c.code, info, ArrayAt, setType:
  987. copyTree c.code, b
  988. c.code.addSymUse info, idx
  989. c.code.addIntVal c.lit.numbers, info, elemType, 0
  990. # if !$3: break
  991. buildTyped c.code, info, Select, Bool8Id:
  992. c.code.copyTree d
  993. build c.code, info, SelectPair:
  994. build c.code, info, SelectValue:
  995. c.code.boolVal(c.lit.numbers, info, false)
  996. c.code.gotoLabel info, Goto, endLabel
  997. endLoop(c, info, idx, backLabel, endLabel)
  998. else:
  999. # "(($1 & ~ $2)==0)"
  1000. template body(target) =
  1001. buildTyped target, info, Eq, setType:
  1002. buildTyped target, info, BitAnd, setType:
  1003. copyTree target, a
  1004. buildTyped target, info, BitNot, setType:
  1005. copyTree target, b
  1006. target.addIntVal c.lit.numbers, info, setType, 0
  1007. intoDest d, info, Bool8Id, body
  1008. freeTemp c, b
  1009. freeTemp c, a
  1010. proc genLtSet(c: var ProcCon; n: PNode; d: var Value) =
  1011. localError(c.m.graph.config, n.info, "`<` for sets not implemented")
  1012. proc genBinarySet(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
  1013. let info = toLineInfo(c, n.info)
  1014. let a = c.genx(n[1])
  1015. let b = c.genx(n[2])
  1016. let t = typeToIr(c.m, n.typ)
  1017. let setType = typeToIr(c.m, n[1].typ)
  1018. if c.m.nirm.types[setType].kind == ArrayTy:
  1019. let elemType = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ)
  1020. if isEmpty(d): d = getTemp(c, n)
  1021. # "for ($1 = 0; $1 < $2; $1++):"
  1022. # " $3 = (($4[$1] & ~ $5[$1]) == 0)"
  1023. # " if (!$3) break;"
  1024. let (idx, backLabel, endLabel) = beginCountLoop(c, info, 0, int(getSize(c.config, n[1].typ)))
  1025. buildTyped c.code, info, Asgn, elemType:
  1026. buildTyped c.code, info, ArrayAt, setType:
  1027. copyTree c.code, d
  1028. c.code.addSymUse info, idx
  1029. buildTyped c.code, info, (if m == mPlusSet: BitOr else: BitAnd), elemType:
  1030. buildTyped c.code, info, ArrayAt, setType:
  1031. copyTree c.code, a
  1032. c.code.addSymUse info, idx
  1033. if m == mMinusSet:
  1034. buildTyped c.code, info, BitNot, elemType:
  1035. buildTyped c.code, info, ArrayAt, setType:
  1036. copyTree c.code, b
  1037. c.code.addSymUse info, idx
  1038. else:
  1039. buildTyped c.code, info, ArrayAt, setType:
  1040. copyTree c.code, b
  1041. c.code.addSymUse info, idx
  1042. endLoop(c, info, idx, backLabel, endLabel)
  1043. else:
  1044. # "(($1 & ~ $2)==0)"
  1045. template body(target) =
  1046. buildTyped target, info, (if m == mPlusSet: BitOr else: BitAnd), setType:
  1047. copyTree target, a
  1048. if m == mMinusSet:
  1049. buildTyped target, info, BitNot, setType:
  1050. copyTree target, b
  1051. else:
  1052. copyTree target, b
  1053. intoDest d, info, setType, body
  1054. freeTemp c, b
  1055. freeTemp c, a
  1056. proc genInclExcl(c: var ProcCon; n: PNode; m: TMagic) =
  1057. let info = toLineInfo(c, n.info)
  1058. let a = c.genx(n[1])
  1059. let b = c.genx(n[2])
  1060. let setType = typeToIr(c.m, n[1].typ)
  1061. let t = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ)
  1062. let mask =
  1063. case t
  1064. of UInt8Id: 7
  1065. of UInt16Id: 15
  1066. of UInt32Id: 31
  1067. else: 63
  1068. buildTyped c.code, info, Asgn, setType:
  1069. if c.m.nirm.types[setType].kind == ArrayTy:
  1070. if m == mIncl:
  1071. # $1[(NU)($2)>>3] |=(1U<<($2&7U))
  1072. buildTyped c.code, info, ArrayAt, setType:
  1073. copyTree c.code, a
  1074. buildTyped c.code, info, BitShr, t:
  1075. buildTyped c.code, info, Cast, c.m.nativeUIntId:
  1076. copyTree c.code, b
  1077. addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
  1078. buildTyped c.code, info, BitOr, t:
  1079. buildTyped c.code, info, ArrayAt, setType:
  1080. copyTree c.code, a
  1081. buildTyped c.code, info, BitShr, t:
  1082. buildTyped c.code, info, Cast, c.m.nativeUIntId:
  1083. copyTree c.code, b
  1084. addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
  1085. buildTyped c.code, info, BitShl, t:
  1086. c.code.addIntVal c.lit.numbers, info, t, 1
  1087. buildTyped c.code, info, BitAnd, t:
  1088. copyTree c.code, b
  1089. c.code.addIntVal c.lit.numbers, info, t, 7
  1090. else:
  1091. # $1[(NU)($2)>>3] &= ~(1U<<($2&7U))
  1092. buildTyped c.code, info, ArrayAt, setType:
  1093. copyTree c.code, a
  1094. buildTyped c.code, info, BitShr, t:
  1095. buildTyped c.code, info, Cast, c.m.nativeUIntId:
  1096. copyTree c.code, b
  1097. addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
  1098. buildTyped c.code, info, BitAnd, t:
  1099. buildTyped c.code, info, ArrayAt, setType:
  1100. copyTree c.code, a
  1101. buildTyped c.code, info, BitShr, t:
  1102. buildTyped c.code, info, Cast, c.m.nativeUIntId:
  1103. copyTree c.code, b
  1104. addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
  1105. buildTyped c.code, info, BitNot, t:
  1106. buildTyped c.code, info, BitShl, t:
  1107. c.code.addIntVal c.lit.numbers, info, t, 1
  1108. buildTyped c.code, info, BitAnd, t:
  1109. copyTree c.code, b
  1110. c.code.addIntVal c.lit.numbers, info, t, 7
  1111. else:
  1112. copyTree c.code, a
  1113. if m == mIncl:
  1114. # $1 |= ((NU8)1)<<(($2) & 7)
  1115. buildTyped c.code, info, BitOr, setType:
  1116. copyTree c.code, a
  1117. buildTyped c.code, info, BitShl, t:
  1118. c.code.addIntVal c.lit.numbers, info, t, 1
  1119. buildTyped c.code, info, BitAnd, t:
  1120. copyTree c.code, b
  1121. c.code.addIntVal c.lit.numbers, info, t, mask
  1122. else:
  1123. # $1 &= ~(((NU8)1) << (($2) & 7))
  1124. buildTyped c.code, info, BitAnd, setType:
  1125. copyTree c.code, a
  1126. buildTyped c.code, info, BitNot, t:
  1127. buildTyped c.code, info, BitShl, t:
  1128. c.code.addIntVal c.lit.numbers, info, t, 1
  1129. buildTyped c.code, info, BitAnd, t:
  1130. copyTree c.code, b
  1131. c.code.addIntVal c.lit.numbers, info, t, mask
  1132. freeTemp c, b
  1133. freeTemp c, a
  1134. proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) =
  1135. # example: { a..b, c, d, e, f..g }
  1136. # we have to emit an expression of the form:
  1137. # nimZeroMem(tmp, sizeof(tmp)); inclRange(tmp, a, b); incl(tmp, c);
  1138. # incl(tmp, d); incl(tmp, e); inclRange(tmp, f, g);
  1139. let info = toLineInfo(c, n.info)
  1140. let setType = typeToIr(c.m, n.typ)
  1141. let size = int(getSize(c.config, n.typ))
  1142. let t = bitsetBasetype(c.m.types, c.m.nirm.types, n.typ)
  1143. let mask =
  1144. case t
  1145. of UInt8Id: 7
  1146. of UInt16Id: 15
  1147. of UInt32Id: 31
  1148. else: 63
  1149. if isEmpty(d): d = getTemp(c, n)
  1150. if c.m.nirm.types[setType].kind != ArrayTy:
  1151. buildTyped c.code, info, Asgn, setType:
  1152. copyTree c.code, d
  1153. c.code.addIntVal c.lit.numbers, info, t, 0
  1154. for it in n:
  1155. if it.kind == nkRange:
  1156. let a = genx(c, it[0])
  1157. let b = genx(c, it[1])
  1158. let (idx, backLabel, endLabel) = beginCountLoop(c, info, a, b)
  1159. buildTyped c.code, info, Asgn, setType:
  1160. copyTree c.code, d
  1161. buildTyped c.code, info, BitAnd, setType:
  1162. copyTree c.code, d
  1163. buildTyped c.code, info, BitNot, t:
  1164. buildTyped c.code, info, BitShl, t:
  1165. c.code.addIntVal c.lit.numbers, info, t, 1
  1166. buildTyped c.code, info, BitAnd, t:
  1167. c.code.addSymUse info, idx
  1168. c.code.addIntVal c.lit.numbers, info, t, mask
  1169. endLoop(c, info, idx, backLabel, endLabel)
  1170. freeTemp c, b
  1171. freeTemp c, a
  1172. else:
  1173. let a = genx(c, it)
  1174. buildTyped c.code, info, Asgn, setType:
  1175. copyTree c.code, d
  1176. buildTyped c.code, info, BitAnd, setType:
  1177. copyTree c.code, d
  1178. buildTyped c.code, info, BitNot, t:
  1179. buildTyped c.code, info, BitShl, t:
  1180. c.code.addIntVal c.lit.numbers, info, t, 1
  1181. buildTyped c.code, info, BitAnd, t:
  1182. copyTree c.code, a
  1183. c.code.addIntVal c.lit.numbers, info, t, mask
  1184. freeTemp c, a
  1185. else:
  1186. # init loop:
  1187. let (idx, backLabel, endLabel) = beginCountLoop(c, info, 0, size)
  1188. buildTyped c.code, info, Asgn, t:
  1189. copyTree c.code, d
  1190. c.code.addIntVal c.lit.numbers, info, t, 0
  1191. endLoop(c, info, idx, backLabel, endLabel)
  1192. # incl elements:
  1193. for it in n:
  1194. if it.kind == nkRange:
  1195. let a = genx(c, it[0])
  1196. let b = genx(c, it[1])
  1197. let (idx, backLabel, endLabel) = beginCountLoop(c, info, a, b)
  1198. buildTyped c.code, info, Asgn, t:
  1199. buildTyped c.code, info, ArrayAt, setType:
  1200. copyTree c.code, d
  1201. buildTyped c.code, info, BitShr, t:
  1202. buildTyped c.code, info, Cast, c.m.nativeUIntId:
  1203. c.code.addSymUse info, idx
  1204. addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
  1205. buildTyped c.code, info, BitOr, t:
  1206. buildTyped c.code, info, ArrayAt, setType:
  1207. copyTree c.code, d
  1208. buildTyped c.code, info, BitShr, t:
  1209. buildTyped c.code, info, Cast, c.m.nativeUIntId:
  1210. c.code.addSymUse info, idx
  1211. addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
  1212. buildTyped c.code, info, BitShl, t:
  1213. c.code.addIntVal c.lit.numbers, info, t, 1
  1214. buildTyped c.code, info, BitAnd, t:
  1215. c.code.addSymUse info, idx
  1216. c.code.addIntVal c.lit.numbers, info, t, 7
  1217. endLoop(c, info, idx, backLabel, endLabel)
  1218. freeTemp c, b
  1219. freeTemp c, a
  1220. else:
  1221. let a = genx(c, it)
  1222. # $1[(NU)($2)>>3] |=(1U<<($2&7U))
  1223. buildTyped c.code, info, Asgn, t:
  1224. buildTyped c.code, info, ArrayAt, setType:
  1225. copyTree c.code, d
  1226. buildTyped c.code, info, BitShr, t:
  1227. buildTyped c.code, info, Cast, c.m.nativeUIntId:
  1228. copyTree c.code, a
  1229. addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
  1230. buildTyped c.code, info, BitOr, t:
  1231. buildTyped c.code, info, ArrayAt, setType:
  1232. copyTree c.code, d
  1233. buildTyped c.code, info, BitShr, t:
  1234. buildTyped c.code, info, Cast, c.m.nativeUIntId:
  1235. copyTree c.code, a
  1236. addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
  1237. buildTyped c.code, info, BitShl, t:
  1238. c.code.addIntVal c.lit.numbers, info, t, 1
  1239. buildTyped c.code, info, BitAnd, t:
  1240. copyTree c.code, a
  1241. c.code.addIntVal c.lit.numbers, info, t, 7
  1242. freeTemp c, a
  1243. proc genSetConstr(c: var ProcCon; n: PNode; d: var Value) =
  1244. if isDeepConstExpr(n):
  1245. let info = toLineInfo(c, n.info)
  1246. let setType = typeToIr(c.m, n.typ)
  1247. let size = int(getSize(c.config, n.typ))
  1248. let cs = toBitSet(c.config, n)
  1249. if c.m.nirm.types[setType].kind != ArrayTy:
  1250. template body(target) =
  1251. target.addIntVal c.lit.numbers, info, setType, cast[BiggestInt](bitSetToWord(cs, size))
  1252. intoDest d, info, setType, body
  1253. else:
  1254. let t = bitsetBasetype(c.m.types, c.m.nirm.types, n.typ)
  1255. template body(target) =
  1256. buildTyped target, info, ArrayConstr, setType:
  1257. for i in 0..high(cs):
  1258. target.addIntVal c.lit.numbers, info, t, int64 cs[i]
  1259. intoDest d, info, setType, body
  1260. else:
  1261. genSetConstrDyn c, n, d
  1262. proc genStrConcat(c: var ProcCon; n: PNode; d: var Value) =
  1263. let info = toLineInfo(c, n.info)
  1264. # <Nim code>
  1265. # s = "Hello " & name & ", how do you feel?" & 'z'
  1266. #
  1267. # <generated code>
  1268. # {
  1269. # string tmp0;
  1270. # ...
  1271. # tmp0 = rawNewString(6 + 17 + 1 + s2->len);
  1272. # // we cannot generate s = rawNewString(...) here, because
  1273. # // ``s`` may be used on the right side of the expression
  1274. # appendString(tmp0, strlit_1);
  1275. # appendString(tmp0, name);
  1276. # appendString(tmp0, strlit_2);
  1277. # appendChar(tmp0, 'z');
  1278. # asgn(s, tmp0);
  1279. # }
  1280. var args: seq[Value] = @[]
  1281. var argsRuntimeLen: seq[Value] = @[]
  1282. var precomputedLen = 0
  1283. for i in 1 ..< n.len:
  1284. let it = n[i]
  1285. args.add genx(c, it)
  1286. if skipTypes(it.typ, abstractVarRange).kind == tyChar:
  1287. inc precomputedLen
  1288. elif it.kind in {nkStrLit..nkTripleStrLit}:
  1289. inc precomputedLen, it.strVal.len
  1290. else:
  1291. argsRuntimeLen.add args[^1]
  1292. # generate length computation:
  1293. var tmpLen = allocTemp(c, c.m.nativeIntId)
  1294. buildTyped c.code, info, Asgn, c.m.nativeIntId:
  1295. c.code.addSymUse info, tmpLen
  1296. c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, precomputedLen
  1297. for a in mitems(argsRuntimeLen):
  1298. buildTyped c.code, info, Asgn, c.m.nativeIntId:
  1299. c.code.addSymUse info, tmpLen
  1300. buildTyped c.code, info, CheckedAdd, c.m.nativeIntId:
  1301. c.code.addLabel info, CheckedGoto, c.exitLabel
  1302. c.code.addSymUse info, tmpLen
  1303. buildTyped c.code, info, FieldAt, typeToIr(c.m, n.typ):
  1304. copyTree c.code, a
  1305. c.code.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
  1306. var tmpStr = getTemp(c, n)
  1307. # ^ because of aliasing, we always go through a temporary
  1308. let t = typeToIr(c.m, n.typ)
  1309. buildTyped c.code, info, Asgn, t:
  1310. copyTree c.code, tmpStr
  1311. buildTyped c.code, info, Call, t:
  1312. let codegenProc = magicsys.getCompilerProc(c.m.graph, "rawNewString")
  1313. #assert codegenProc != nil, $n & " " & (c.m.graph.config $ n.info)
  1314. let theProc = c.genx newSymNode(codegenProc, n.info)
  1315. copyTree c.code, theProc
  1316. c.code.addSymUse info, tmpLen
  1317. freeTemp c.sm, tmpLen
  1318. for i in 1 ..< n.len:
  1319. let it = n[i]
  1320. let isChar = skipTypes(it.typ, abstractVarRange).kind == tyChar
  1321. buildTyped c.code, info, Call, VoidId:
  1322. let codegenProc = magicsys.getCompilerProc(c.m.graph,
  1323. (if isChar: "appendChar" else: "appendString"))
  1324. #assert codegenProc != nil, $n & " " & (c.m.graph.config $ n.info)
  1325. let theProc = c.genx newSymNode(codegenProc, n.info)
  1326. copyTree c.code, theProc
  1327. buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, t):
  1328. copyTree c.code, tmpStr
  1329. copyTree c.code, args[i-1]
  1330. freeTemp c, args[i-1]
  1331. if isEmpty(d):
  1332. d = tmpStr
  1333. else:
  1334. # XXX Test that this does not cause memory leaks!
  1335. buildTyped c.code, info, Asgn, t:
  1336. copyTree c.code, d
  1337. copyTree c.code, tmpStr
  1338. proc genDefault(c: var ProcCon; n: PNode; d: var Value) =
  1339. let m = expandDefault(n.typ, n.info)
  1340. gen c, m, d
  1341. proc genWasMoved(c: var ProcCon; n: PNode) =
  1342. let n1 = n[1].skipAddr
  1343. # XXX We need a way to replicate this logic or better yet a better
  1344. # solution for injectdestructors.nim:
  1345. #if c.withinBlockLeaveActions > 0 and notYetAlive(n1):
  1346. var d = c.genx(n1)
  1347. assert not isEmpty(d)
  1348. let m = expandDefault(n1.typ, n1.info)
  1349. gen c, m, d
  1350. proc genMove(c: var ProcCon; n: PNode; d: var Value) =
  1351. let info = toLineInfo(c, n.info)
  1352. let n1 = n[1].skipAddr
  1353. var a = c.genx(n1)
  1354. if n.len == 4:
  1355. # generated by liftdestructors:
  1356. let src = c.genx(n[2])
  1357. # if ($1.p == $2.p) goto lab1
  1358. let lab1 = newLabel(c.labelGen)
  1359. let n1t = typeToIr(c.m, n1.typ)
  1360. let payloadType = seqPayloadPtrType(c.m.types, c.m.nirm.types, n1.typ)[0]
  1361. buildTyped c.code, info, Select, Bool8Id:
  1362. buildTyped c.code, info, Eq, payloadType:
  1363. buildTyped c.code, info, FieldAt, n1t:
  1364. copyTree c.code, a
  1365. c.code.addImmediateVal info, 1 # (len, p)-pair
  1366. buildTyped c.code, info, FieldAt, n1t:
  1367. copyTree c.code, src
  1368. c.code.addImmediateVal info, 1 # (len, p)-pair
  1369. build c.code, info, SelectPair:
  1370. build c.code, info, SelectValue:
  1371. c.code.boolVal(c.lit.numbers, info, true)
  1372. c.code.gotoLabel info, Goto, lab1
  1373. gen(c, n[3])
  1374. c.patch n, lab1
  1375. buildTyped c.code, info, Asgn, typeToIr(c.m, n1.typ):
  1376. copyTree c.code, a
  1377. copyTree c.code, src
  1378. else:
  1379. if isEmpty(d): d = getTemp(c, n)
  1380. buildTyped c.code, info, Asgn, typeToIr(c.m, n1.typ):
  1381. copyTree c.code, d
  1382. copyTree c.code, a
  1383. var op = getAttachedOp(c.m.graph, n.typ, attachedWasMoved)
  1384. if op == nil or skipTypes(n1.typ, abstractVar+{tyStatic}).kind in {tyOpenArray, tyVarargs}:
  1385. let m = expandDefault(n1.typ, n1.info)
  1386. gen c, m, a
  1387. else:
  1388. var opB = c.genx(newSymNode(op))
  1389. buildTyped c.code, info, Call, typeToIr(c.m, n.typ):
  1390. copyTree c.code, opB
  1391. buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, typeToIr(c.m, n1.typ)):
  1392. copyTree c.code, a
  1393. template fieldAt(x: Value; i: int; t: TypeId): Tree =
  1394. var result = default(Tree)
  1395. buildTyped result, info, FieldAt, t:
  1396. copyTree result, x
  1397. result.addImmediateVal info, i
  1398. result
  1399. template eqNil(x: Tree; t: TypeId): Tree =
  1400. var result = default(Tree)
  1401. buildTyped result, info, Eq, t:
  1402. copyTree result, x
  1403. result.addNilVal info, t
  1404. result
  1405. template eqZero(x: Tree): Tree =
  1406. var result = default(Tree)
  1407. buildTyped result, info, Eq, c.m.nativeIntId:
  1408. copyTree result, x
  1409. result.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
  1410. result
  1411. template bitOp(x: Tree; opc: Opcode; y: int): Tree =
  1412. var result = default(Tree)
  1413. buildTyped result, info, opc, c.m.nativeIntId:
  1414. copyTree result, x
  1415. result.addIntVal c.lit.numbers, info, c.m.nativeIntId, y
  1416. result
  1417. proc genDestroySeq(c: var ProcCon; n: PNode; t: PType) =
  1418. let info = toLineInfo(c, n.info)
  1419. let strLitFlag = 1 shl (c.m.graph.config.target.intSize * 8 - 2) # see also NIM_STRLIT_FLAG
  1420. let x = c.genx(n[1])
  1421. let baseType = t.elementType
  1422. let seqType = typeToIr(c.m, t)
  1423. let p = fieldAt(x, 0, seqType)
  1424. # if $1.p != nil and ($1.p.cap and NIM_STRLIT_FLAG) == 0:
  1425. # alignedDealloc($1.p, NIM_ALIGNOF($2))
  1426. buildIfNot p.eqNil(seqType):
  1427. buildIf fieldAt(Value(p), 0, seqPayloadPtrType(c.m.types, c.m.nirm.types, t)[0]).bitOp(BitAnd, 0).eqZero():
  1428. let codegenProc = getCompilerProc(c.m.graph, "alignedDealloc")
  1429. buildTyped c.code, info, Call, VoidId:
  1430. let theProc = c.genx newSymNode(codegenProc, n.info)
  1431. copyTree c.code, theProc
  1432. copyTree c.code, p
  1433. c.code.addImmediateVal info, int(getAlign(c.config, baseType))
  1434. freeTemp c, x
  1435. proc genDestroy(c: var ProcCon; n: PNode) =
  1436. let t = n[1].typ.skipTypes(abstractInst)
  1437. case t.kind
  1438. of tyString:
  1439. var unused = default(Value)
  1440. genUnaryCp(c, n, unused, "nimDestroyStrV1")
  1441. of tySequence:
  1442. genDestroySeq(c, n, t)
  1443. else: discard "nothing to do"
  1444. type
  1445. IndexFor = enum
  1446. ForSeq, ForStr, ForOpenArray, ForArray
  1447. proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor; arr: PType): Value =
  1448. if optBoundsCheck in c.options:
  1449. let info = toLineInfo(c, n.info)
  1450. result = default(Value)
  1451. let idx = genx(c, n)
  1452. build result, info, CheckedIndex:
  1453. result.Tree.addLabel info, CheckedGoto, c.exitLabel
  1454. copyTree result.Tree, idx
  1455. case kind
  1456. of ForSeq, ForStr:
  1457. buildTyped result, info, FieldAt, typeToIr(c.m, arr):
  1458. copyTree result.Tree, a
  1459. result.addImmediateVal info, 0 # (len, p)-pair
  1460. of ForOpenArray:
  1461. buildTyped result, info, FieldAt, typeToIr(c.m, arr):
  1462. copyTree result.Tree, a
  1463. result.addImmediateVal info, 1 # (p, len)-pair
  1464. of ForArray:
  1465. let x = toInt64 lengthOrd(c.config, arr)
  1466. result.addIntVal c.lit.numbers, info, c.m.nativeIntId, x
  1467. freeTemp c, idx
  1468. else:
  1469. result = genx(c, n)
  1470. proc addSliceFields(c: var ProcCon; target: var Tree; info: PackedLineInfo;
  1471. x: Value; n: PNode; arrType: PType) =
  1472. let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.elementType))
  1473. case arrType.kind
  1474. of tyString, tySequence:
  1475. let checkKind = if arrType.kind == tyString: ForStr else: ForSeq
  1476. let pay = if checkKind == ForStr: c.m.strPayloadId
  1477. else: seqPayloadPtrType(c.m.types, c.m.nirm.types, arrType)
  1478. let y = genIndexCheck(c, n[2], x, checkKind, arrType)
  1479. let z = genIndexCheck(c, n[3], x, checkKind, arrType)
  1480. buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ):
  1481. target.addImmediateVal info, 0
  1482. buildTyped target, info, AddrOf, elemType:
  1483. buildTyped target, info, DerefArrayAt, pay[1]:
  1484. buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
  1485. copyTree target, x
  1486. target.addImmediateVal info, 1 # (len, p)-pair
  1487. copyTree target, y
  1488. # len:
  1489. target.addImmediateVal info, 1
  1490. buildTyped target, info, Add, c.m.nativeIntId:
  1491. buildTyped target, info, Sub, c.m.nativeIntId:
  1492. copyTree target, z
  1493. copyTree target, y
  1494. target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1
  1495. freeTemp c, z
  1496. freeTemp c, y
  1497. of tyArray:
  1498. # XXX This evaluates the index check for `y` twice.
  1499. # This check is also still insufficient for non-zero based arrays.
  1500. let y = genIndexCheck(c, n[2], x, ForArray, arrType)
  1501. let z = genIndexCheck(c, n[3], x, ForArray, arrType)
  1502. buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ):
  1503. target.addImmediateVal info, 0
  1504. buildTyped target, info, AddrOf, elemType:
  1505. buildTyped target, info, ArrayAt, typeToIr(c.m, arrType):
  1506. copyTree target, x
  1507. copyTree target, y
  1508. target.addImmediateVal info, 1
  1509. buildTyped target, info, Add, c.m.nativeIntId:
  1510. buildTyped target, info, Sub, c.m.nativeIntId:
  1511. copyTree target, z
  1512. copyTree target, y
  1513. target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1
  1514. freeTemp c, z
  1515. freeTemp c, y
  1516. of tyOpenArray:
  1517. # XXX This evaluates the index check for `y` twice.
  1518. let y = genIndexCheck(c, n[2], x, ForOpenArray, arrType)
  1519. let z = genIndexCheck(c, n[3], x, ForOpenArray, arrType)
  1520. let pay = openArrayPayloadType(c.m.types, c.m.nirm.types, arrType)
  1521. buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ):
  1522. target.addImmediateVal info, 0
  1523. buildTyped target, info, AddrOf, elemType:
  1524. buildTyped target, info, DerefArrayAt, pay:
  1525. buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
  1526. copyTree target, x
  1527. target.addImmediateVal info, 0 # (p, len)-pair
  1528. copyTree target, y
  1529. target.addImmediateVal info, 1
  1530. buildTyped target, info, Add, c.m.nativeIntId:
  1531. buildTyped target, info, Sub, c.m.nativeIntId:
  1532. copyTree target, z
  1533. copyTree target, y
  1534. target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1
  1535. freeTemp c, z
  1536. freeTemp c, y
  1537. else:
  1538. raiseAssert "addSliceFields: " & typeToString(arrType)
  1539. proc genSlice(c: var ProcCon; n: PNode; d: var Value) =
  1540. let info = toLineInfo(c, n.info)
  1541. let x = c.genx(n[1])
  1542. let arrType = n[1].typ.skipTypes(abstractVar)
  1543. template body(target) =
  1544. c.addSliceFields target, info, x, n, arrType
  1545. valueIntoDest c, info, d, arrType, body
  1546. freeTemp c, x
  1547. proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
  1548. case m
  1549. of mAnd: c.genAndOr(n, opcFJmp, d)
  1550. of mOr: c.genAndOr(n, opcTJmp, d)
  1551. of mPred, mSubI: c.genBinaryOp(n, d, if optOverflowCheck in c.options: CheckedSub else: Sub)
  1552. of mSucc, mAddI: c.genBinaryOp(n, d, if optOverflowCheck in c.options: CheckedAdd else: Add)
  1553. of mInc:
  1554. unused(c, n, d)
  1555. c.genIncDec(n, if optOverflowCheck in c.options: CheckedAdd else: Add)
  1556. of mDec:
  1557. unused(c, n, d)
  1558. c.genIncDec(n, if optOverflowCheck in c.options: CheckedSub else: Sub)
  1559. of mOrd, mChr, mUnown:
  1560. c.gen(n[1], d)
  1561. of generatedMagics:
  1562. genCall(c, n, d)
  1563. of mNew, mNewFinalize:
  1564. unused(c, n, d)
  1565. c.genNew(n, needsInit = true)
  1566. of mNewSeq:
  1567. unused(c, n, d)
  1568. c.genNewSeq(n)
  1569. of mNewSeqOfCap: c.genNewSeqOfCap(n, d)
  1570. of mNewString, mNewStringOfCap, mExit: c.genCall(n, d)
  1571. of mLengthOpenArray, mLengthArray, mLengthSeq, mLengthStr:
  1572. genArrayLen(c, n, d)
  1573. of mMulI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedMul else: Mul)
  1574. of mDivI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedDiv else: Div)
  1575. of mModI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedMod else: Mod)
  1576. of mAddF64: genBinaryOp(c, n, d, Add)
  1577. of mSubF64: genBinaryOp(c, n, d, Sub)
  1578. of mMulF64: genBinaryOp(c, n, d, Mul)
  1579. of mDivF64: genBinaryOp(c, n, d, Div)
  1580. of mShrI: genBinaryOp(c, n, d, BitShr)
  1581. of mShlI: genBinaryOp(c, n, d, BitShl)
  1582. of mAshrI: genBinaryOp(c, n, d, BitShr)
  1583. of mBitandI: genBinaryOp(c, n, d, BitAnd)
  1584. of mBitorI: genBinaryOp(c, n, d, BitOr)
  1585. of mBitxorI: genBinaryOp(c, n, d, BitXor)
  1586. of mAddU: genBinaryOp(c, n, d, Add)
  1587. of mSubU: genBinaryOp(c, n, d, Sub)
  1588. of mMulU: genBinaryOp(c, n, d, Mul)
  1589. of mDivU: genBinaryOp(c, n, d, Div)
  1590. of mModU: genBinaryOp(c, n, d, Mod)
  1591. of mEqI, mEqB, mEqEnum, mEqCh:
  1592. genCmpOp(c, n, d, Eq)
  1593. of mLeI, mLeEnum, mLeCh, mLeB:
  1594. genCmpOp(c, n, d, Le)
  1595. of mLtI, mLtEnum, mLtCh, mLtB:
  1596. genCmpOp(c, n, d, Lt)
  1597. of mEqF64: genCmpOp(c, n, d, Eq)
  1598. of mLeF64: genCmpOp(c, n, d, Le)
  1599. of mLtF64: genCmpOp(c, n, d, Lt)
  1600. of mLePtr, mLeU: genCmpOp(c, n, d, Le)
  1601. of mLtPtr, mLtU: genCmpOp(c, n, d, Lt)
  1602. of mEqProc, mEqRef:
  1603. genCmpOp(c, n, d, Eq)
  1604. of mXor: genBinaryOp(c, n, d, BitXor)
  1605. of mNot: genUnaryOp(c, n, d, BoolNot)
  1606. of mUnaryMinusI, mUnaryMinusI64:
  1607. genUnaryMinus(c, n, d)
  1608. #genNarrow(c, n, d)
  1609. of mUnaryMinusF64: genUnaryMinus(c, n, d)
  1610. of mUnaryPlusI, mUnaryPlusF64: gen(c, n[1], d)
  1611. of mBitnotI:
  1612. genUnaryOp(c, n, d, BitNot)
  1613. when false:
  1614. # XXX genNarrowU modified, do not narrow signed types
  1615. let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
  1616. let size = getSize(c.config, t)
  1617. if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
  1618. c.gABC(n, opcNarrowU, d, TRegister(size*8))
  1619. of mStrToStr, mEnsureMove: c.gen n[1], d
  1620. of mIntToStr: genUnaryCp(c, n, d, "nimIntToStr")
  1621. of mInt64ToStr: genUnaryCp(c, n, d, "nimInt64ToStr")
  1622. of mBoolToStr: genUnaryCp(c, n, d, "nimBoolToStr")
  1623. of mCharToStr: genUnaryCp(c, n, d, "nimCharToStr")
  1624. of mFloatToStr:
  1625. if n[1].typ.skipTypes(abstractInst).kind == tyFloat32:
  1626. genUnaryCp(c, n, d, "nimFloat32ToStr")
  1627. else:
  1628. genUnaryCp(c, n, d, "nimFloatToStr")
  1629. of mCStrToStr: genUnaryCp(c, n, d, "cstrToNimstr")
  1630. of mEnumToStr: genEnumToStr(c, n, d)
  1631. of mEqStr: genBinaryCp(c, n, d, "eqStrings")
  1632. of mEqCString: genCall(c, n, d)
  1633. of mLeStr: genBinaryCp(c, n, d, "leStrings")
  1634. of mLtStr: genBinaryCp(c, n, d, "ltStrings")
  1635. of mSetLengthStr:
  1636. unused(c, n, d)
  1637. let nb = copyTree(n)
  1638. nb[1] = makeAddr(nb[1], c.m.idgen)
  1639. genBinaryCp(c, nb, d, "setLengthStrV2")
  1640. of mSetLengthSeq:
  1641. unused(c, n, d)
  1642. let nb = copyTree(n)
  1643. nb[1] = makeAddr(nb[1], c.m.idgen)
  1644. genCall(c, nb, d)
  1645. of mSwap:
  1646. unused(c, n, d)
  1647. c.gen(lowerSwap(c.m.graph, n, c.m.idgen,
  1648. if c.prc == nil: c.m.module else: c.prc), d)
  1649. of mParseBiggestFloat:
  1650. genCall c, n, d
  1651. of mHigh:
  1652. c.genHigh n, d
  1653. of mEcho:
  1654. unused(c, n, d)
  1655. genUnaryCp c, n, d, "echoBinSafe"
  1656. of mAppendStrCh:
  1657. unused(c, n, d)
  1658. let nb = copyTree(n)
  1659. nb[1] = makeAddr(nb[1], c.m.idgen)
  1660. genBinaryCp(c, nb, d, "nimAddCharV1")
  1661. of mMinI, mMaxI, mAbsI, mDotDot:
  1662. c.genCall(n, d)
  1663. of mSizeOf:
  1664. localError(c.config, n.info, sizeOfLikeMsg("sizeof"))
  1665. of mAlignOf:
  1666. localError(c.config, n.info, sizeOfLikeMsg("alignof"))
  1667. of mOffsetOf:
  1668. localError(c.config, n.info, sizeOfLikeMsg("offsetof"))
  1669. of mRunnableExamples:
  1670. discard "just ignore any call to runnableExamples"
  1671. of mOf: genOf(c, n, d)
  1672. of mAppendStrStr:
  1673. unused(c, n, d)
  1674. let nb = copyTree(n)
  1675. nb[1] = makeAddr(nb[1], c.m.idgen)
  1676. genBinaryCp(c, nb, d, "nimAddStrV1")
  1677. of mAppendSeqElem:
  1678. unused(c, n, d)
  1679. let nb = copyTree(n)
  1680. nb[1] = makeAddr(nb[1], c.m.idgen)
  1681. genCall(c, nb, d)
  1682. of mIsNil: genIsNil(c, n, d)
  1683. of mInSet: genInSet(c, n, d)
  1684. of mCard: genCard(c, n, d)
  1685. of mEqSet: genEqSet(c, n, d)
  1686. of mLeSet: genLeSet(c, n, d)
  1687. of mLtSet: genLtSet(c, n, d)
  1688. of mMulSet: genBinarySet(c, n, d, m)
  1689. of mPlusSet: genBinarySet(c, n, d, m)
  1690. of mMinusSet: genBinarySet(c, n, d, m)
  1691. of mIncl, mExcl:
  1692. unused(c, n, d)
  1693. genInclExcl(c, n, m)
  1694. of mConStrStr: genStrConcat(c, n, d)
  1695. of mDefault, mZeroDefault:
  1696. genDefault c, n, d
  1697. of mMove: genMove(c, n, d)
  1698. of mWasMoved, mReset:
  1699. unused(c, n, d)
  1700. genWasMoved(c, n)
  1701. of mDestroy: genDestroy(c, n)
  1702. #of mAccessEnv: unaryExpr(d, n, d, "$1.ClE_0")
  1703. #of mAccessTypeField: genAccessTypeField(c, n, d)
  1704. of mSlice: genSlice(c, n, d)
  1705. of mTrace: discard "no code to generate"
  1706. else:
  1707. # mGCref, mGCunref: unused by ORC
  1708. globalError(c.config, n.info, "cannot generate code for: " & $m)
  1709. proc canElimAddr(n: PNode; idgen: IdGenerator): PNode =
  1710. result = nil
  1711. case n[0].kind
  1712. of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
  1713. var m = n[0][0]
  1714. if m.kind in {nkDerefExpr, nkHiddenDeref}:
  1715. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  1716. result = copyNode(n[0])
  1717. result.add m[0]
  1718. if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  1719. result.typ = n.typ
  1720. elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
  1721. result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen)
  1722. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  1723. var m = n[0][1]
  1724. if m.kind in {nkDerefExpr, nkHiddenDeref}:
  1725. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  1726. result = copyNode(n[0])
  1727. result.add n[0][0]
  1728. result.add m[0]
  1729. if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  1730. result.typ = n.typ
  1731. elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
  1732. result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen)
  1733. else:
  1734. if n[0].kind in {nkDerefExpr, nkHiddenDeref}:
  1735. # addr ( deref ( x )) --> x
  1736. result = n[0][0]
  1737. proc genAddr(c: var ProcCon; n: PNode; d: var Value, flags: GenFlags) =
  1738. if (let m = canElimAddr(n, c.m.idgen); m != nil):
  1739. gen(c, m, d, flags)
  1740. return
  1741. let info = toLineInfo(c, n.info)
  1742. let tmp = c.genx(n[0], flags)
  1743. template body(target) =
  1744. buildTyped target, info, AddrOf, typeToIr(c.m, n.typ):
  1745. copyTree target, tmp
  1746. valueIntoDest c, info, d, n.typ, body
  1747. freeTemp c, tmp
  1748. proc genDeref(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
  1749. let info = toLineInfo(c, n.info)
  1750. let tmp = c.genx(n[0], flags)
  1751. template body(target) =
  1752. buildTyped target, info, Load, typeToIr(c.m, n.typ):
  1753. copyTree target, tmp
  1754. valueIntoDest c, info, d, n.typ, body
  1755. freeTemp c, tmp
  1756. proc addAddrOfFirstElem(c: var ProcCon; target: var Tree; info: PackedLineInfo; tmp: Value; typ: PType) =
  1757. let arrType = typ.skipTypes(abstractVar)
  1758. let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.elementType))
  1759. case arrType.kind
  1760. of tyString:
  1761. let t = typeToIr(c.m, typ)
  1762. target.addImmediateVal info, 0
  1763. buildTyped target, info, AddrOf, elemType:
  1764. buildTyped target, info, DerefArrayAt, c.m.strPayloadId[1]:
  1765. buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
  1766. copyTree target, tmp
  1767. target.addImmediateVal info, 1 # (len, p)-pair
  1768. target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
  1769. # len:
  1770. target.addImmediateVal info, 1
  1771. buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
  1772. copyTree target, tmp
  1773. target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
  1774. of tySequence:
  1775. let t = typeToIr(c.m, typ)
  1776. target.addImmediateVal info, 0
  1777. buildTyped target, info, AddrOf, elemType:
  1778. buildTyped target, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, typ)[1]:
  1779. buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
  1780. copyTree target, tmp
  1781. target.addImmediateVal info, 1 # (len, p)-pair
  1782. target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
  1783. # len:
  1784. target.addImmediateVal info, 1
  1785. buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
  1786. copyTree target, tmp
  1787. target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
  1788. of tyArray:
  1789. let t = typeToIr(c.m, arrType)
  1790. target.addImmediateVal info, 0
  1791. buildTyped target, info, AddrOf, elemType:
  1792. buildTyped target, info, ArrayAt, t:
  1793. copyTree target, tmp
  1794. target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
  1795. target.addImmediateVal info, 1
  1796. target.addIntVal(c.lit.numbers, info, c.m.nativeIntId, toInt lengthOrd(c.config, arrType))
  1797. else:
  1798. raiseAssert "addAddrOfFirstElem: " & typeToString(typ)
  1799. proc genToOpenArrayConv(c: var ProcCon; arg: PNode; d: var Value; flags: GenFlags; destType: PType) =
  1800. let info = toLineInfo(c, arg.info)
  1801. let tmp = c.genx(arg, flags)
  1802. let arrType = destType.skipTypes(abstractVar)
  1803. template body(target) =
  1804. buildTyped target, info, ObjConstr, typeToIr(c.m, arrType):
  1805. c.addAddrOfFirstElem target, info, tmp, arg.typ
  1806. valueIntoDest c, info, d, arrType, body
  1807. freeTemp c, tmp
  1808. proc genConv(c: var ProcCon; n, arg: PNode; d: var Value; flags: GenFlags; opc: Opcode) =
  1809. let targetType = n.typ.skipTypes({tyDistinct})
  1810. let argType = arg.typ.skipTypes({tyDistinct})
  1811. if sameBackendType(targetType, argType) or (
  1812. argType.kind == tyProc and targetType.kind == argType.kind):
  1813. # don't do anything for lambda lifting conversions:
  1814. gen c, arg, d
  1815. return
  1816. if opc != Cast and targetType.skipTypes({tyVar, tyLent}).kind in {tyOpenArray, tyVarargs} and
  1817. argType.skipTypes({tyVar, tyLent}).kind notin {tyOpenArray, tyVarargs}:
  1818. genToOpenArrayConv c, arg, d, flags, n.typ
  1819. return
  1820. let info = toLineInfo(c, n.info)
  1821. let tmp = c.genx(arg, flags)
  1822. template body(target) =
  1823. buildTyped target, info, opc, typeToIr(c.m, n.typ):
  1824. if opc == CheckedObjConv:
  1825. target.addLabel info, CheckedGoto, c.exitLabel
  1826. copyTree target, tmp
  1827. valueIntoDest c, info, d, n.typ, body
  1828. freeTemp c, tmp
  1829. proc genObjOrTupleConstr(c: var ProcCon; n: PNode; d: var Value; t: PType) =
  1830. # XXX x = (x.old, 22) produces wrong code ... stupid self assignments
  1831. let info = toLineInfo(c, n.info)
  1832. template body(target) =
  1833. buildTyped target, info, ObjConstr, typeToIr(c.m, t):
  1834. for i in ord(n.kind == nkObjConstr)..<n.len:
  1835. let it = n[i]
  1836. if it.kind == nkExprColonExpr:
  1837. genField(c, it[0], Value target)
  1838. let tmp = c.genx(it[1])
  1839. copyTree target, tmp
  1840. c.freeTemp(tmp)
  1841. else:
  1842. let tmp = c.genx(it)
  1843. target.addImmediateVal info, i
  1844. copyTree target, tmp
  1845. c.freeTemp(tmp)
  1846. if isException(t):
  1847. target.addImmediateVal info, 1 # "name" field is at position after the "parent". See system.nim
  1848. target.addStrVal c.lit.strings, info, t.skipTypes(abstractInst).sym.name.s
  1849. constrIntoDest c, info, d, t, body
  1850. proc genRefObjConstr(c: var ProcCon; n: PNode; d: var Value) =
  1851. if isEmpty(d): d = getTemp(c, n)
  1852. let info = toLineInfo(c, n.info)
  1853. let refType = n.typ.skipTypes(abstractInstOwned)
  1854. let objType = refType.elementType
  1855. rawGenNew(c, d, refType, n.info, needsInit = nfAllFieldsSet notin n.flags)
  1856. var deref = default(Value)
  1857. deref.buildTyped info, Load, typeToIr(c.m, objType):
  1858. deref.Tree.copyTree d
  1859. genObjOrTupleConstr c, n, deref, objType
  1860. proc genSeqConstr(c: var ProcCon; n: PNode; d: var Value) =
  1861. if isEmpty(d): d = getTemp(c, n)
  1862. let info = toLineInfo(c, n.info)
  1863. let seqtype = skipTypes(n.typ, abstractVarRange)
  1864. let baseType = seqtype.elementType
  1865. var b = default(Value)
  1866. b.addIntVal c.lit.numbers, info, c.m.nativeIntId, n.len
  1867. genNewSeqPayload(c, info, d, b, seqtype)
  1868. for i in 0..<n.len:
  1869. var dd = default(Value)
  1870. buildTyped dd, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[1]:
  1871. buildTyped dd, info, FieldAt, typeToIr(c.m, seqtype):
  1872. copyTree Tree(dd), d
  1873. dd.addImmediateVal info, 1 # (len, p)-pair
  1874. dd.addIntVal c.lit.numbers, info, c.m.nativeIntId, i
  1875. gen(c, n[i], dd)
  1876. freeTemp c, d
  1877. proc genArrayConstr(c: var ProcCon; n: PNode, d: var Value) =
  1878. let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
  1879. if seqType.kind == tySequence:
  1880. genSeqConstr(c, n, d)
  1881. return
  1882. let info = toLineInfo(c, n.info)
  1883. template body(target) =
  1884. buildTyped target, info, ArrayConstr, typeToIr(c.m, n.typ):
  1885. for i in 0..<n.len:
  1886. let tmp = c.genx(n[i])
  1887. copyTree target, tmp
  1888. c.freeTemp(tmp)
  1889. constrIntoDest c, info, d, n.typ, body
  1890. proc genAsgn2(c: var ProcCon; a, b: PNode) =
  1891. assert a != nil
  1892. assert b != nil
  1893. var d = c.genx(a)
  1894. c.gen b, d
  1895. proc irModule(c: var ProcCon; owner: PSym): string =
  1896. #if owner == c.m.module: "" else:
  1897. customPath(toFullPath(c.config, owner.info))
  1898. proc fromForeignModule(c: ProcCon; s: PSym): bool {.inline.} =
  1899. result = ast.originatingModule(s) != c.m.module and not c.m.noModularity
  1900. proc genForeignVar(c: var ProcCon; s: PSym) =
  1901. var opc: Opcode
  1902. if s.kind == skConst:
  1903. opc = SummonConst
  1904. elif sfThread in s.flags:
  1905. opc = SummonThreadLocal
  1906. else:
  1907. assert sfGlobal in s.flags
  1908. opc = SummonGlobal
  1909. let t = typeToIr(c.m, s.typ)
  1910. let info = toLineInfo(c, s.info)
  1911. build c.code, info, ForeignDecl:
  1912. buildTyped c.code, info, opc, t:
  1913. build c.code, info, ModuleSymUse:
  1914. c.code.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(s))
  1915. c.code.addImmediateVal info, s.itemId.item.int
  1916. proc genVarSection(c: var ProcCon; n: PNode) =
  1917. for a in n:
  1918. if a.kind == nkCommentStmt: continue
  1919. #assert(a[0].kind == nkSym) can happen for transformed vars
  1920. if a.kind == nkVarTuple:
  1921. c.gen(lowerTupleUnpacking(c.m.graph, a, c.m.idgen, c.prc))
  1922. else:
  1923. var vn = a[0]
  1924. if vn.kind == nkPragmaExpr: vn = vn[0]
  1925. if vn.kind == nkSym:
  1926. let s = vn.sym
  1927. if s.kind == skConst:
  1928. if dontInlineConstant(n, s.astdef):
  1929. let symId = toSymId(c, s)
  1930. c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(s.name.s)
  1931. let val = c.genx(s.astdef)
  1932. let info = toLineInfo(c, a.info)
  1933. buildTyped c.code, info, SummonConst, typeToIr(c.m, s.typ):
  1934. c.code.addSymDef info, symId
  1935. c.code.copyTree val
  1936. freeTemp c, val
  1937. else:
  1938. var opc: Opcode
  1939. if sfThread in s.flags:
  1940. opc = SummonThreadLocal
  1941. elif sfGlobal in s.flags:
  1942. opc = SummonGlobal
  1943. else:
  1944. opc = Summon
  1945. #assert t.int >= 0, typeToString(s.typ) & (c.config $ n.info)
  1946. let symId = toSymId(c, s)
  1947. c.code.addSummon toLineInfo(c, a.info), symId, typeToIr(c.m, s.typ), opc
  1948. c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(s.name.s)
  1949. if a[2].kind != nkEmpty:
  1950. genAsgn2(c, vn, a[2])
  1951. else:
  1952. if a[2].kind == nkEmpty:
  1953. genAsgn2(c, vn, expandDefault(vn.typ, vn.info))
  1954. else:
  1955. genAsgn2(c, vn, a[2])
  1956. proc genAsgn(c: var ProcCon; n: PNode) =
  1957. var d = c.genx(n[0])
  1958. c.gen n[1], d
  1959. proc convStrToCStr(c: var ProcCon; n: PNode; d: var Value) =
  1960. genUnaryCp(c, n, d, "nimToCStringConv", argAt = 0)
  1961. proc convCStrToStr(c: var ProcCon; n: PNode; d: var Value) =
  1962. genUnaryCp(c, n, d, "cstrToNimstr", argAt = 0)
  1963. proc genRdVar(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
  1964. let info = toLineInfo(c, n.info)
  1965. let s = n.sym
  1966. if fromForeignModule(c, s):
  1967. if s.kind in {skVar, skConst, skLet} and not c.m.pendingVarsAsSet.containsOrIncl(s.itemId):
  1968. c.m.pendingVars.add s
  1969. template body(target) =
  1970. build target, info, ModuleSymUse:
  1971. target.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(s))
  1972. target.addImmediateVal info, s.itemId.item.int
  1973. valueIntoDest c, info, d, s.typ, body
  1974. else:
  1975. template body(target) =
  1976. target.addSymUse info, toSymId(c, s)
  1977. valueIntoDest c, info, d, s.typ, body
  1978. proc genSym(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) =
  1979. let s = n.sym
  1980. case s.kind
  1981. of skConst:
  1982. if dontInlineConstant(n, s.astdef):
  1983. genRdVar(c, n, d, flags)
  1984. else:
  1985. gen(c, s.astdef, d, flags)
  1986. of skVar, skForVar, skTemp, skLet, skResult, skParam:
  1987. genRdVar(c, n, d, flags)
  1988. of skProc, skFunc, skConverter, skMethod, skIterator:
  1989. if not c.m.noModularity:
  1990. # anon and generic procs have no AST so we need to remember not to forget
  1991. # to emit these:
  1992. if not c.m.processedProcs.contains(s.itemId):
  1993. if not c.m.pendingProcsAsSet.containsOrIncl(s.itemId):
  1994. c.m.pendingProcs.add s
  1995. genRdVar(c, n, d, flags)
  1996. of skEnumField:
  1997. let info = toLineInfo(c, n.info)
  1998. template body(target) =
  1999. target.addIntVal c.lit.numbers, info, typeToIr(c.m, n.typ), s.position
  2000. valueIntoDest c, info, d, n.typ, body
  2001. else:
  2002. localError(c.config, n.info, "cannot generate code for: " & s.name.s)
  2003. proc genNumericLit(c: var ProcCon; n: PNode; d: var Value; bits: int64) =
  2004. let info = toLineInfo(c, n.info)
  2005. template body(target) =
  2006. target.addIntVal c.lit.numbers, info, typeToIr(c.m, n.typ), bits
  2007. valueIntoDest c, info, d, n.typ, body
  2008. proc genStringLit(c: var ProcCon; n: PNode; d: var Value) =
  2009. let info = toLineInfo(c, n.info)
  2010. template body(target) =
  2011. target.addStrVal c.lit.strings, info, n.strVal
  2012. valueIntoDest c, info, d, n.typ, body
  2013. proc genNilLit(c: var ProcCon; n: PNode; d: var Value) =
  2014. let info = toLineInfo(c, n.info)
  2015. template body(target) =
  2016. target.addNilVal info, typeToIr(c.m, n.typ)
  2017. valueIntoDest c, info, d, n.typ, body
  2018. proc genRangeCheck(c: var ProcCon; n: PNode; d: var Value) =
  2019. if optRangeCheck in c.options:
  2020. let info = toLineInfo(c, n.info)
  2021. let tmp = c.genx n[0]
  2022. let a = c.genx n[1]
  2023. let b = c.genx n[2]
  2024. template body(target) =
  2025. buildTyped target, info, CheckedRange, typeToIr(c.m, n.typ):
  2026. target.addLabel info, CheckedGoto, c.exitLabel
  2027. copyTree target, tmp
  2028. copyTree target, a
  2029. copyTree target, b
  2030. valueIntoDest c, info, d, n.typ, body
  2031. freeTemp c, tmp
  2032. freeTemp c, a
  2033. freeTemp c, b
  2034. else:
  2035. gen c, n[0], d
  2036. proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
  2037. let arrayType = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc})
  2038. let arrayKind = arrayType.kind
  2039. let info = toLineInfo(c, n.info)
  2040. case arrayKind
  2041. of tyString:
  2042. let a = genx(c, n[0], flags)
  2043. let b = genIndexCheck(c, n[1], a, ForStr, arrayType)
  2044. let t = typeToIr(c.m, n.typ)
  2045. template body(target) =
  2046. buildTyped target, info, DerefArrayAt, c.m.strPayloadId[1]:
  2047. buildTyped target, info, FieldAt, typeToIr(c.m, arrayType):
  2048. copyTree target, a
  2049. target.addImmediateVal info, 1 # (len, p)-pair
  2050. copyTree target, b
  2051. intoDest d, info, t, body
  2052. freeTemp c, b
  2053. freeTemp c, a
  2054. of tyCstring, tyPtr, tyUncheckedArray:
  2055. let a = genx(c, n[0], flags)
  2056. let b = genx(c, n[1])
  2057. template body(target) =
  2058. buildTyped target, info, DerefArrayAt, typeToIr(c.m, arrayType):
  2059. copyTree target, a
  2060. copyTree target, b
  2061. valueIntoDest c, info, d, n.typ, body
  2062. freeTemp c, b
  2063. freeTemp c, a
  2064. of tyTuple:
  2065. let a = genx(c, n[0], flags)
  2066. let b = int n[1].intVal
  2067. template body(target) =
  2068. buildTyped target, info, FieldAt, typeToIr(c.m, arrayType):
  2069. copyTree target, a
  2070. target.addImmediateVal info, b
  2071. valueIntoDest c, info, d, n.typ, body
  2072. freeTemp c, a
  2073. of tyOpenArray, tyVarargs:
  2074. let a = genx(c, n[0], flags)
  2075. let b = genIndexCheck(c, n[1], a, ForOpenArray, arrayType)
  2076. let t = typeToIr(c.m, n.typ)
  2077. template body(target) =
  2078. buildTyped target, info, DerefArrayAt, openArrayPayloadType(c.m.types, c.m.nirm.types, n[0].typ):
  2079. buildTyped target, info, FieldAt, typeToIr(c.m, arrayType):
  2080. copyTree target, a
  2081. target.addImmediateVal info, 0 # (p, len)-pair
  2082. copyTree target, b
  2083. intoDest d, info, t, body
  2084. freeTemp c, b
  2085. freeTemp c, a
  2086. of tyArray:
  2087. let a = genx(c, n[0], flags)
  2088. var b = default(Value)
  2089. genIndex(c, n[1], n[0].typ, b)
  2090. template body(target) =
  2091. buildTyped target, info, ArrayAt, typeToIr(c.m, arrayType):
  2092. copyTree target, a
  2093. copyTree target, b
  2094. valueIntoDest c, info, d, n.typ, body
  2095. freeTemp c, b
  2096. freeTemp c, a
  2097. of tySequence:
  2098. let a = genx(c, n[0], flags)
  2099. let b = genIndexCheck(c, n[1], a, ForSeq, arrayType)
  2100. let t = typeToIr(c.m, n.typ)
  2101. template body(target) =
  2102. buildTyped target, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, n[0].typ)[1]:
  2103. buildTyped target, info, FieldAt, t:
  2104. copyTree target, a
  2105. target.addImmediateVal info, 1 # (len, p)-pair
  2106. copyTree target, b
  2107. intoDest d, info, t, body
  2108. freeTemp c, b
  2109. freeTemp c, a
  2110. else:
  2111. localError c.config, n.info, "invalid type for nkBracketExpr: " & $arrayKind
  2112. proc genObjAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
  2113. let info = toLineInfo(c, n.info)
  2114. var n0 = n[0]
  2115. var opc = FieldAt
  2116. if n0.kind == nkDotExpr:
  2117. # obj[].a --> DerefFieldAt instead of FieldAt:
  2118. n0 = n[0]
  2119. opc = DerefFieldAt
  2120. let a = genx(c, n0, flags)
  2121. template body(target) =
  2122. buildTyped target, info, opc, typeToIr(c.m, n0.typ):
  2123. copyTree target, a
  2124. genField c, n[1], Value(target)
  2125. valueIntoDest c, info, d, n.typ, body
  2126. freeTemp c, a
  2127. proc genParams(c: var ProcCon; params: PNode; prc: PSym): PSym =
  2128. result = nil
  2129. if params.len > 0 and resultPos < prc.ast.len:
  2130. let resNode = prc.ast[resultPos]
  2131. result = resNode.sym # get result symbol
  2132. c.code.addSummon toLineInfo(c, result.info), toSymId(c, result),
  2133. typeToIr(c.m, result.typ), SummonResult
  2134. elif prc.typ.len > 0 and not isEmptyType(prc.typ.returnType) and not isCompileTimeOnly(prc.typ.returnType):
  2135. # happens for procs without bodies:
  2136. let t = typeToIr(c.m, prc.typ.returnType)
  2137. let tmp = allocTemp(c, t)
  2138. c.code.addSummon toLineInfo(c, params.info), tmp, t, SummonResult
  2139. for i in 1..<params.len:
  2140. let s = params[i].sym
  2141. if not isCompileTimeOnly(s.typ):
  2142. let t = typeToIr(c.m, s.typ)
  2143. assert t.int != -1, typeToString(s.typ)
  2144. let symId = toSymId(c, s)
  2145. c.code.addSummon toLineInfo(c, params[i].info), symId, t, SummonParam
  2146. c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(s.name.s)
  2147. proc addCallConv(c: var ProcCon; info: PackedLineInfo; callConv: TCallingConvention) =
  2148. template ann(s: untyped) = c.code.addPragmaId info, s
  2149. case callConv
  2150. of ccNimCall, ccFastCall, ccClosure: ann FastCall
  2151. of ccStdCall: ann StdCall
  2152. of ccCDecl: ann CDeclCall
  2153. of ccSafeCall: ann SafeCall
  2154. of ccSysCall: ann SysCall
  2155. of ccInline: ann InlineCall
  2156. of ccNoInline: ann NoinlineCall
  2157. of ccThisCall: ann ThisCall
  2158. of ccNoConvention: ann NoCall
  2159. proc genProc(cOuter: var ProcCon; prc: PSym) =
  2160. if prc.magic notin generatedMagics: return
  2161. if cOuter.m.processedProcs.containsOrIncl(prc.itemId):
  2162. return
  2163. #assert cOuter.m.inProc == 0, " in nested proc! " & prc.name.s
  2164. if cOuter.m.inProc > 0:
  2165. if not cOuter.m.pendingProcsAsSet.containsOrIncl(prc.itemId):
  2166. cOuter.m.pendingProcs.add prc
  2167. return
  2168. inc cOuter.m.inProc
  2169. var c = initProcCon(cOuter.m, prc, cOuter.m.graph.config)
  2170. let body =
  2171. if not fromForeignModule(c, prc):
  2172. transformBody(c.m.graph, c.m.idgen, prc, {useCache, keepOpenArrayConversions})
  2173. else:
  2174. nil
  2175. let info = toLineInfo(c, prc.info)
  2176. build c.code, info, (if body != nil: ProcDecl else: ForeignProcDecl):
  2177. if body != nil:
  2178. let symId = toSymId(c, prc)
  2179. addSymDef c.code, info, symId
  2180. c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(prc.name.s)
  2181. else:
  2182. build c.code, info, ModuleSymUse:
  2183. c.code.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(prc))
  2184. c.code.addImmediateVal info, prc.itemId.item.int
  2185. addCallConv c, info, prc.typ.callConv
  2186. if sfCompilerProc in prc.flags:
  2187. build c.code, info, PragmaPair:
  2188. c.code.addPragmaId info, CoreName
  2189. c.code.addStrVal c.lit.strings, info, prc.name.s
  2190. if {sfImportc, sfExportc} * prc.flags != {}:
  2191. build c.code, info, PragmaPair:
  2192. c.code.addPragmaId info, ExternName
  2193. c.code.addStrVal c.lit.strings, info, prc.loc.r
  2194. if sfImportc in prc.flags:
  2195. if lfHeader in prc. loc.flags:
  2196. assert(prc. annex != nil)
  2197. let str = getStr(prc. annex.path)
  2198. build c.code, info, PragmaPair:
  2199. c.code.addPragmaId info, HeaderImport
  2200. c.code.addStrVal c.lit.strings, info, str
  2201. elif lfDynamicLib in prc. loc.flags:
  2202. assert(prc. annex != nil)
  2203. let str = getStr(prc. annex.path)
  2204. build c.code, info, PragmaPair:
  2205. c.code.addPragmaId info, DllImport
  2206. c.code.addStrVal c.lit.strings, info, str
  2207. elif sfExportc in prc.flags:
  2208. if lfDynamicLib in prc. loc.flags:
  2209. c.code.addPragmaId info, DllExport
  2210. else:
  2211. c.code.addPragmaId info, ObjExport
  2212. let resultSym = genParams(c, prc.typ.n, prc)
  2213. if body != nil:
  2214. gen(c, body)
  2215. patch c, body, c.exitLabel
  2216. if resultSym != nil:
  2217. build c.code, info, Ret:
  2218. c.code.addSymUse info, toSymId(c, resultSym)
  2219. else:
  2220. build c.code, info, Ret:
  2221. c.code.addNop info
  2222. #copyTree cOuter.code, c.code
  2223. dec cOuter.m.inProc
  2224. proc genProc(cOuter: var ProcCon; n: PNode) =
  2225. if n.len == 0 or n[namePos].kind != nkSym: return
  2226. let prc = n[namePos].sym
  2227. if isGenericRoutineStrict(prc) or isCompileTimeProc(prc) or sfForward in prc.flags: return
  2228. genProc cOuter, prc
  2229. proc genClosureCall(c: var ProcCon; n: PNode; d: var Value) =
  2230. let typ = skipTypes(n[0].typ, abstractInstOwned)
  2231. if tfIterator in typ.flags:
  2232. const PatIter = "$1.ClP_0($3, $1.ClE_0)" # we know the env exists
  2233. else:
  2234. const PatProc = "$1.ClE_0? $1.ClP_0($3, $1.ClE_0):(($4)($1.ClP_0))($2)"
  2235. proc genComplexCall(c: var ProcCon; n: PNode; d: var Value) =
  2236. if n[0].typ != nil and n[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure:
  2237. # XXX genClosureCall p, n, d
  2238. genCall c, n, d
  2239. else:
  2240. genCall c, n, d
  2241. proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) =
  2242. when defined(nimCompilerStacktraceHints):
  2243. setFrameMsg c.config$n.info & " " & $n.kind & " " & $flags
  2244. case n.kind
  2245. of nkSym: genSym(c, n, d, flags)
  2246. of nkCallKinds:
  2247. if n[0].kind == nkSym:
  2248. let s = n[0].sym
  2249. if s.magic != mNone:
  2250. genMagic(c, n, d, s.magic)
  2251. elif s.kind == skMethod:
  2252. localError(c.config, n.info, "cannot call method " & s.name.s &
  2253. " at compile time")
  2254. else:
  2255. genComplexCall(c, n, d)
  2256. else:
  2257. genComplexCall(c, n, d)
  2258. of nkCharLit..nkInt64Lit, nkUIntLit..nkUInt64Lit:
  2259. genNumericLit(c, n, d, n.intVal)
  2260. of nkFloatLit..nkFloat128Lit:
  2261. genNumericLit(c, n, d, cast[int64](n.floatVal))
  2262. of nkStrLit..nkTripleStrLit:
  2263. genStringLit(c, n, d)
  2264. of nkNilLit:
  2265. if not n.typ.isEmptyType: genNilLit(c, n, d)
  2266. else: unused(c, n, d)
  2267. of nkAsgn, nkFastAsgn, nkSinkAsgn:
  2268. unused(c, n, d)
  2269. genAsgn(c, n)
  2270. of nkDotExpr: genObjAccess(c, n, d, flags)
  2271. of nkCheckedFieldExpr: genObjAccess(c, n[0], d, flags)
  2272. of nkBracketExpr: genArrAccess(c, n, d, flags)
  2273. of nkDerefExpr, nkHiddenDeref: genDeref(c, n, d, flags)
  2274. of nkAddr, nkHiddenAddr: genAddr(c, n, d, flags)
  2275. of nkIfStmt, nkIfExpr: genIf(c, n, d)
  2276. of nkWhenStmt:
  2277. # This is "when nimvm" node. Chose the first branch.
  2278. gen(c, n[0][1], d)
  2279. of nkCaseStmt: genCase(c, n, d)
  2280. of nkWhileStmt:
  2281. unused(c, n, d)
  2282. genWhile(c, n)
  2283. of nkBlockExpr, nkBlockStmt: genBlock(c, n, d)
  2284. of nkReturnStmt: genReturn(c, n)
  2285. of nkRaiseStmt: genRaise(c, n)
  2286. of nkBreakStmt: genBreak(c, n)
  2287. of nkTryStmt, nkHiddenTryStmt: genTry(c, n, d)
  2288. of nkStmtList:
  2289. #unused(c, n, d)
  2290. # XXX Fix this bug properly, lexim triggers it
  2291. for x in n: gen(c, x)
  2292. of nkStmtListExpr:
  2293. for i in 0..<n.len-1: gen(c, n[i])
  2294. gen(c, n[^1], d, flags)
  2295. of nkPragmaBlock:
  2296. gen(c, n.lastSon, d, flags)
  2297. of nkDiscardStmt:
  2298. unused(c, n, d)
  2299. gen(c, n[0], d)
  2300. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  2301. genConv(c, n, n[1], d, flags, NumberConv) # misnomer?
  2302. of nkObjDownConv:
  2303. genConv(c, n, n[0], d, flags, ObjConv)
  2304. of nkObjUpConv:
  2305. genConv(c, n, n[0], d, flags, CheckedObjConv)
  2306. of nkVarSection, nkLetSection, nkConstSection:
  2307. unused(c, n, d)
  2308. genVarSection(c, n)
  2309. of nkLambdaKinds:
  2310. #let s = n[namePos].sym
  2311. #discard genProc(c, s)
  2312. gen(c, newSymNode(n[namePos].sym), d)
  2313. of nkChckRangeF, nkChckRange64, nkChckRange:
  2314. genRangeCheck(c, n, d)
  2315. of declarativeDefs - {nkIteratorDef}:
  2316. unused(c, n, d)
  2317. genProc(c, n)
  2318. of nkEmpty, nkCommentStmt, nkTypeSection, nkPragma,
  2319. nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt,
  2320. nkMixinStmt, nkBindStmt, nkMacroDef, nkIteratorDef:
  2321. unused(c, n, d)
  2322. of nkStringToCString: convStrToCStr(c, n, d)
  2323. of nkCStringToString: convCStrToStr(c, n, d)
  2324. of nkBracket: genArrayConstr(c, n, d)
  2325. of nkCurly: genSetConstr(c, n, d)
  2326. of nkObjConstr:
  2327. if n.typ.skipTypes(abstractInstOwned).kind == tyRef:
  2328. genRefObjConstr(c, n, d)
  2329. else:
  2330. genObjOrTupleConstr(c, n, d, n.typ)
  2331. of nkPar, nkClosure, nkTupleConstr:
  2332. genObjOrTupleConstr(c, n, d, n.typ)
  2333. of nkCast:
  2334. genConv(c, n, n[1], d, flags, Cast)
  2335. of nkComesFrom:
  2336. discard "XXX to implement for better stack traces"
  2337. #of nkState: genState(c, n)
  2338. #of nkGotoState: genGotoState(c, n)
  2339. #of nkBreakState: genBreakState(c, n, d)
  2340. else:
  2341. localError(c.config, n.info, "cannot generate IR code for " & $n)
  2342. proc genPendingProcs(c: var ProcCon) =
  2343. while c.m.pendingProcs.len > 0 or c.m.pendingVars.len > 0:
  2344. let procs = move(c.m.pendingProcs)
  2345. for v in procs:
  2346. genProc(c, v)
  2347. let vars = move(c.m.pendingVars)
  2348. for v in vars:
  2349. genForeignVar(c, v)
  2350. proc genStmt*(c: var ProcCon; n: PNode): NodePos =
  2351. result = NodePos c.code.len
  2352. var d = default(Value)
  2353. c.gen(n, d)
  2354. unused c, n, d
  2355. genPendingProcs c
  2356. proc genExpr*(c: var ProcCon; n: PNode, requiresValue = true): int =
  2357. result = c.code.len
  2358. var d = default(Value)
  2359. c.gen(n, d)
  2360. genPendingProcs c
  2361. if isEmpty d:
  2362. if requiresValue:
  2363. globalError(c.config, n.info, "VM problem: d register is not set")