vmgen.nim 78 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module implements the code generator for the VM.
  10. # Important things to remember:
  11. # - The VM does not distinguish between definitions ('var x = y') and
  12. # assignments ('x = y'). For simple data types that fit into a register
  13. # this doesn't matter. However it matters for strings and other complex
  14. # types that use the 'node' field; the reason is that slots are
  15. # re-used in a register based VM. Example:
  16. #
  17. #.. code-block:: nim
  18. # let s = a & b # no matter what, create fresh node
  19. # s = a & b # no matter what, keep the node
  20. #
  21. # Also *stores* into non-temporary memory need to perform deep copies:
  22. # a.b = x.y
  23. # We used to generate opcAsgn for the *load* of 'x.y' but this is clearly
  24. # wrong! We need to produce opcAsgn (the copy) for the *store*. This also
  25. # solves the opcLdConst vs opcAsgnConst issue. Of course whether we need
  26. # this copy depends on the involved types.
  27. import tables
  28. import
  29. strutils, ast, types, msgs, renderer, vmdef,
  30. intsets, magicsys, options, lowerings, lineinfos, transf, astmsgs
  31. from modulegraphs import getBody
  32. when defined(nimCompilerStacktraceHints):
  33. import std/stackframes
  34. const
  35. debugEchoCode* = defined(nimVMDebug)
  36. when debugEchoCode:
  37. import std/private/asciitables
  38. when hasFFI:
  39. import evalffi
  40. type
  41. TGenFlag = enum
  42. gfNode # Affects how variables are loaded - always loads as rkNode
  43. gfNodeAddr # Affects how variables are loaded - always loads as rkNodeAddr
  44. gfIsParam # do not deepcopy parameters, they are immutable
  45. TGenFlags = set[TGenFlag]
  46. proc debugInfo(c: PCtx; info: TLineInfo): string =
  47. result = toFileLineCol(c.config, info)
  48. proc codeListing(c: PCtx, result: var string, start=0; last = -1) =
  49. ## for debugging purposes
  50. # first iteration: compute all necessary labels:
  51. var jumpTargets = initIntSet()
  52. let last = if last < 0: c.code.len-1 else: min(last, c.code.len-1)
  53. for i in start..last:
  54. let x = c.code[i]
  55. if x.opcode in relativeJumps:
  56. jumpTargets.incl(i+x.regBx-wordExcess)
  57. template toStr(opc: TOpcode): string = ($opc).substr(3)
  58. result.add "code listing:\n"
  59. var i = start
  60. while i <= last:
  61. if i in jumpTargets: result.addf("L$1:\n", i)
  62. let x = c.code[i]
  63. result.add($i)
  64. let opc = opcode(x)
  65. if opc in {opcIndCall, opcIndCallAsgn}:
  66. result.addf("\t$#\tr$#, r$#, nargs:$#", opc.toStr, x.regA,
  67. x.regB, x.regC)
  68. elif opc in {opcConv, opcCast}:
  69. let y = c.code[i+1]
  70. let z = c.code[i+2]
  71. result.addf("\t$#\tr$#, r$#, $#, $#", opc.toStr, x.regA, x.regB,
  72. c.types[y.regBx-wordExcess].typeToString,
  73. c.types[z.regBx-wordExcess].typeToString)
  74. inc i, 2
  75. elif opc < firstABxInstr:
  76. result.addf("\t$#\tr$#, r$#, r$#", opc.toStr, x.regA,
  77. x.regB, x.regC)
  78. elif opc in relativeJumps + {opcTry}:
  79. result.addf("\t$#\tr$#, L$#", opc.toStr, x.regA,
  80. i+x.regBx-wordExcess)
  81. elif opc in {opcExcept}:
  82. let idx = x.regBx-wordExcess
  83. result.addf("\t$#\t$#, $#", opc.toStr, x.regA, $idx)
  84. elif opc in {opcLdConst, opcAsgnConst}:
  85. let idx = x.regBx-wordExcess
  86. result.addf("\t$#\tr$#, $# ($#)", opc.toStr, x.regA,
  87. c.constants[idx].renderTree, $idx)
  88. elif opc in {opcMarshalLoad, opcMarshalStore}:
  89. let y = c.code[i+1]
  90. result.addf("\t$#\tr$#, r$#, $#", opc.toStr, x.regA, x.regB,
  91. c.types[y.regBx-wordExcess].typeToString)
  92. inc i
  93. else:
  94. result.addf("\t$#\tr$#, $#", opc.toStr, x.regA, x.regBx-wordExcess)
  95. result.add("\t# ")
  96. result.add(debugInfo(c, c.debug[i]))
  97. result.add("\n")
  98. inc i
  99. when debugEchoCode:
  100. result = result.alignTable
  101. proc echoCode*(c: PCtx; start=0; last = -1) {.deprecated.} =
  102. var buf = ""
  103. codeListing(c, buf, start, last)
  104. echo buf
  105. proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) =
  106. ## Takes the registers `b` and `c`, applies the operation `opc` to them, and
  107. ## stores the result into register `a`
  108. ## The node is needed for debug information
  109. assert opc.ord < 255
  110. let ins = (opc.TInstrType or (a.TInstrType shl regAShift) or
  111. (b.TInstrType shl regBShift) or
  112. (c.TInstrType shl regCShift)).TInstr
  113. when false:
  114. if ctx.code.len == 43:
  115. writeStackTrace()
  116. echo "generating ", opc
  117. ctx.code.add(ins)
  118. ctx.debug.add(n.info)
  119. proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
  120. # Takes the `b` register and the immediate `imm`, applies the operation `opc`,
  121. # and stores the output value into `a`.
  122. # `imm` is signed and must be within [-128, 127]
  123. if imm >= -128 and imm <= 127:
  124. let ins = (opc.TInstrType or (a.TInstrType shl regAShift) or
  125. (b.TInstrType shl regBShift) or
  126. (imm+byteExcess).TInstrType shl regCShift).TInstr
  127. c.code.add(ins)
  128. c.debug.add(n.info)
  129. else:
  130. localError(c.config, n.info,
  131. "VM: immediate value does not fit into an int8")
  132. proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
  133. # Applies `opc` to `bx` and stores it into register `a`
  134. # `bx` must be signed and in the range [regBxMin, regBxMax]
  135. when false:
  136. if c.code.len == 43:
  137. writeStackTrace()
  138. echo "generating ", opc
  139. if bx >= regBxMin-1 and bx <= regBxMax:
  140. let ins = (opc.TInstrType or a.TInstrType shl regAShift or
  141. (bx+wordExcess).TInstrType shl regBxShift).TInstr
  142. c.code.add(ins)
  143. c.debug.add(n.info)
  144. else:
  145. localError(c.config, n.info,
  146. "VM: immediate value does not fit into regBx")
  147. proc xjmp(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0): TPosition =
  148. #assert opc in {opcJmp, opcFJmp, opcTJmp}
  149. result = TPosition(c.code.len)
  150. gABx(c, n, opc, a, 0)
  151. proc genLabel(c: PCtx): TPosition =
  152. result = TPosition(c.code.len)
  153. #c.jumpTargets.incl(c.code.len)
  154. proc jmpBack(c: PCtx, n: PNode, p = TPosition(0)) =
  155. let dist = p.int - c.code.len
  156. internalAssert(c.config, regBxMin < dist and dist < regBxMax)
  157. gABx(c, n, opcJmpBack, 0, dist)
  158. proc patch(c: PCtx, p: TPosition) =
  159. # patch with current index
  160. let p = p.int
  161. let diff = c.code.len - p
  162. #c.jumpTargets.incl(c.code.len)
  163. internalAssert(c.config, regBxMin < diff and diff < regBxMax)
  164. let oldInstr = c.code[p]
  165. # opcode and regA stay the same:
  166. c.code[p] = ((oldInstr.TInstrType and regBxMask).TInstrType or
  167. TInstrType(diff+wordExcess) shl regBxShift).TInstr
  168. proc getSlotKind(t: PType): TSlotKind =
  169. case t.skipTypes(abstractRange-{tyTypeDesc}).kind
  170. of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64:
  171. slotTempInt
  172. of tyString, tyCstring:
  173. slotTempStr
  174. of tyFloat..tyFloat128:
  175. slotTempFloat
  176. else:
  177. slotTempComplex
  178. const
  179. HighRegisterPressure = 40
  180. proc bestEffort(c: PCtx): TLineInfo =
  181. if c.prc != nil and c.prc.sym != nil:
  182. c.prc.sym.info
  183. else:
  184. c.module.info
  185. proc getFreeRegister(cc: PCtx; k: TSlotKind; start: int): TRegister =
  186. let c = cc.prc
  187. # we prefer the same slot kind here for efficiency. Unfortunately for
  188. # discardable return types we may not know the desired type. This can happen
  189. # for e.g. mNAdd[Multiple]:
  190. for i in start..c.regInfo.len-1:
  191. if c.regInfo[i].kind == k and not c.regInfo[i].inUse:
  192. c.regInfo[i].inUse = true
  193. return TRegister(i)
  194. # if register pressure is high, we re-use more aggressively:
  195. if c.regInfo.len >= high(TRegister):
  196. for i in start..c.regInfo.len-1:
  197. if not c.regInfo[i].inUse:
  198. c.regInfo[i] = (inUse: true, kind: k)
  199. return TRegister(i)
  200. if c.regInfo.len >= high(TRegister):
  201. globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
  202. result = TRegister(max(c.regInfo.len, start))
  203. c.regInfo.setLen int(result)+1
  204. c.regInfo[result] = (inUse: true, kind: k)
  205. proc getTemp(cc: PCtx; tt: PType): TRegister =
  206. let typ = tt.skipTypesOrNil({tyStatic})
  207. # we prefer the same slot kind here for efficiency. Unfortunately for
  208. # discardable return types we may not know the desired type. This can happen
  209. # for e.g. mNAdd[Multiple]:
  210. let k = if typ.isNil: slotTempComplex else: typ.getSlotKind
  211. result = getFreeRegister(cc, k, start = 0)
  212. when false:
  213. # enable this to find "register" leaks:
  214. if result == 4:
  215. echo "begin ---------------"
  216. writeStackTrace()
  217. echo "end ----------------"
  218. proc freeTemp(c: PCtx; r: TRegister) =
  219. let c = c.prc
  220. if c.regInfo[r].kind in {slotSomeTemp..slotTempComplex}:
  221. # this seems to cause https://github.com/nim-lang/Nim/issues/10647
  222. c.regInfo[r].inUse = false
  223. proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister =
  224. # if register pressure is high, we re-use more aggressively:
  225. let c = cc.prc
  226. # we could also customize via the following (with proper caching in ConfigRef):
  227. # let highRegisterPressure = cc.config.getConfigVar("vm.highRegisterPressure", "40").parseInt
  228. if c.regInfo.len >= HighRegisterPressure or c.regInfo.len+n >= high(TRegister):
  229. for i in 0..c.regInfo.len-n:
  230. if not c.regInfo[i].inUse:
  231. block search:
  232. for j in i+1..i+n-1:
  233. if c.regInfo[j].inUse: break search
  234. result = TRegister(i)
  235. for k in result..result+n-1: c.regInfo[k] = (inUse: true, kind: kind)
  236. return
  237. if c.regInfo.len+n >= high(TRegister):
  238. globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
  239. result = TRegister(c.regInfo.len)
  240. setLen c.regInfo, c.regInfo.len+n
  241. for k in result..result+n-1: c.regInfo[k] = (inUse: true, kind: kind)
  242. proc freeTempRange(c: PCtx; start: TRegister, n: int) =
  243. for i in start..start+n-1: c.freeTemp(TRegister(i))
  244. template withTemp(tmp, typ, body: untyped) {.dirty.} =
  245. var tmp = getTemp(c, typ)
  246. body
  247. c.freeTemp(tmp)
  248. proc popBlock(c: PCtx; oldLen: int) =
  249. for f in c.prc.blocks[oldLen].fixups:
  250. c.patch(f)
  251. c.prc.blocks.setLen(oldLen)
  252. template withBlock(labl: PSym; body: untyped) {.dirty.} =
  253. var oldLen {.gensym.} = c.prc.blocks.len
  254. c.prc.blocks.add TBlock(label: labl, fixups: @[])
  255. body
  256. popBlock(c, oldLen)
  257. proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {})
  258. proc gen(c: PCtx; n: PNode; dest: TRegister; flags: TGenFlags = {}) =
  259. var d: TDest = dest
  260. gen(c, n, d, flags)
  261. #internalAssert c.config, d == dest # issue #7407
  262. proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) =
  263. var tmp: TDest = -1
  264. gen(c, n, tmp, flags)
  265. if tmp >= 0:
  266. freeTemp(c, tmp)
  267. #if n.typ.isEmptyType: internalAssert tmp < 0
  268. proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
  269. var tmp: TDest = -1
  270. gen(c, n, tmp, flags)
  271. #internalAssert c.config, tmp >= 0 # 'nim check' does not like this internalAssert.
  272. if tmp >= 0:
  273. result = TRegister(tmp)
  274. proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} =
  275. # stmt is different from 'void' in meta programming contexts.
  276. # So we only set dest to -1 if 'void':
  277. if dest >= 0 and (n.typ.isNil or n.typ.kind == tyVoid):
  278. c.freeTemp(dest)
  279. dest = -1
  280. proc isNotOpr(n: PNode): bool =
  281. n.kind in nkCallKinds and n[0].kind == nkSym and
  282. n[0].sym.magic == mNot
  283. proc isTrue(n: PNode): bool =
  284. n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
  285. n.kind == nkIntLit and n.intVal != 0
  286. proc genWhile(c: PCtx; n: PNode) =
  287. # lab1:
  288. # cond, tmp
  289. # fjmp tmp, lab2
  290. # body
  291. # jmp lab1
  292. # lab2:
  293. let lab1 = c.genLabel
  294. withBlock(nil):
  295. if isTrue(n[0]):
  296. c.gen(n[1])
  297. c.jmpBack(n, lab1)
  298. elif isNotOpr(n[0]):
  299. var tmp = c.genx(n[0][1])
  300. let lab2 = c.xjmp(n, opcTJmp, tmp)
  301. c.freeTemp(tmp)
  302. c.gen(n[1])
  303. c.jmpBack(n, lab1)
  304. c.patch(lab2)
  305. else:
  306. var tmp = c.genx(n[0])
  307. let lab2 = c.xjmp(n, opcFJmp, tmp)
  308. c.freeTemp(tmp)
  309. c.gen(n[1])
  310. c.jmpBack(n, lab1)
  311. c.patch(lab2)
  312. proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
  313. let oldRegisterCount = c.prc.regInfo.len
  314. withBlock(n[0].sym):
  315. c.gen(n[1], dest)
  316. for i in oldRegisterCount..<c.prc.regInfo.len:
  317. #if c.prc.regInfo[i].kind in {slotFixedVar, slotFixedLet}:
  318. if i != dest:
  319. when not defined(release):
  320. if c.prc.regInfo[i].inUse and c.prc.regInfo[i].kind in {slotTempUnknown,
  321. slotTempInt,
  322. slotTempFloat,
  323. slotTempStr,
  324. slotTempComplex}:
  325. doAssert false, "leaking temporary " & $i & " " & $c.prc.regInfo[i].kind
  326. c.prc.regInfo[i] = (inUse: false, kind: slotEmpty)
  327. c.clearDest(n, dest)
  328. proc genBreak(c: PCtx; n: PNode) =
  329. let lab1 = c.xjmp(n, opcJmp)
  330. if n[0].kind == nkSym:
  331. #echo cast[int](n[0].sym)
  332. for i in countdown(c.prc.blocks.len-1, 0):
  333. if c.prc.blocks[i].label == n[0].sym:
  334. c.prc.blocks[i].fixups.add lab1
  335. return
  336. globalError(c.config, n.info, "VM problem: cannot find 'break' target")
  337. else:
  338. c.prc.blocks[c.prc.blocks.high].fixups.add lab1
  339. proc genIf(c: PCtx, n: PNode; dest: var TDest) =
  340. # if (!expr1) goto lab1;
  341. # thenPart
  342. # goto LEnd
  343. # lab1:
  344. # if (!expr2) goto lab2;
  345. # thenPart2
  346. # goto LEnd
  347. # lab2:
  348. # elsePart
  349. # Lend:
  350. if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
  351. var endings: seq[TPosition] = @[]
  352. for i in 0..<n.len:
  353. var it = n[i]
  354. if it.len == 2:
  355. withTemp(tmp, it[0].typ):
  356. var elsePos: TPosition
  357. if isNotOpr(it[0]):
  358. c.gen(it[0][1], tmp)
  359. elsePos = c.xjmp(it[0][1], opcTJmp, tmp) # if true
  360. else:
  361. c.gen(it[0], tmp)
  362. elsePos = c.xjmp(it[0], opcFJmp, tmp) # if false
  363. c.clearDest(n, dest)
  364. c.gen(it[1], dest) # then part
  365. if i < n.len-1:
  366. endings.add(c.xjmp(it[1], opcJmp, 0))
  367. c.patch(elsePos)
  368. else:
  369. c.clearDest(n, dest)
  370. c.gen(it[0], dest)
  371. for endPos in endings: c.patch(endPos)
  372. c.clearDest(n, dest)
  373. proc isTemp(c: PCtx; dest: TDest): bool =
  374. result = dest >= 0 and c.prc.regInfo[dest].kind >= slotTempUnknown
  375. proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
  376. # asgn dest, a
  377. # tjmp|fjmp lab1
  378. # asgn dest, b
  379. # lab1:
  380. let copyBack = dest < 0 or not isTemp(c, dest)
  381. let tmp = if copyBack:
  382. getTemp(c, n.typ)
  383. else:
  384. TRegister dest
  385. c.gen(n[1], tmp)
  386. let lab1 = c.xjmp(n, opc, tmp)
  387. c.gen(n[2], tmp)
  388. c.patch(lab1)
  389. if dest < 0:
  390. dest = tmp
  391. elif copyBack:
  392. c.gABC(n, opcAsgnInt, dest, tmp)
  393. freeTemp(c, tmp)
  394. proc rawGenLiteral(c: PCtx; n: PNode): int =
  395. result = c.constants.len
  396. #assert(n.kind != nkCall)
  397. n.flags.incl nfAllConst
  398. c.constants.add n
  399. internalAssert c.config, result < regBxMax
  400. proc sameConstant*(a, b: PNode): bool =
  401. result = false
  402. if a == b:
  403. result = true
  404. elif a != nil and b != nil and a.kind == b.kind:
  405. case a.kind
  406. of nkSym: result = a.sym == b.sym
  407. of nkIdent: result = a.ident.id == b.ident.id
  408. of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
  409. of nkFloatLit..nkFloat64Lit:
  410. result = cast[uint64](a.floatVal) == cast[uint64](b.floatVal)
  411. # refs bug #16469
  412. # if we wanted to only distinguish 0.0 vs -0.0:
  413. # if a.floatVal == 0.0: result = cast[uint64](a.floatVal) == cast[uint64](b.floatVal)
  414. # else: result = a.floatVal == b.floatVal
  415. of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
  416. of nkType, nkNilLit: result = a.typ == b.typ
  417. of nkEmpty: result = true
  418. else:
  419. if a.len == b.len:
  420. for i in 0..<a.len:
  421. if not sameConstant(a[i], b[i]): return
  422. result = true
  423. proc genLiteral(c: PCtx; n: PNode): int =
  424. # types do not matter here:
  425. for i in 0..<c.constants.len:
  426. if sameConstant(c.constants[i], n): return i
  427. result = rawGenLiteral(c, n)
  428. proc unused(c: PCtx; n: PNode; x: TDest) {.inline.} =
  429. if x >= 0:
  430. #debug(n)
  431. globalError(c.config, n.info, "not unused")
  432. proc genCase(c: PCtx; n: PNode; dest: var TDest) =
  433. # if (!expr1) goto lab1;
  434. # thenPart
  435. # goto LEnd
  436. # lab1:
  437. # if (!expr2) goto lab2;
  438. # thenPart2
  439. # goto LEnd
  440. # lab2:
  441. # elsePart
  442. # Lend:
  443. if not isEmptyType(n.typ):
  444. if dest < 0: dest = getTemp(c, n.typ)
  445. else:
  446. unused(c, n, dest)
  447. var endings: seq[TPosition] = @[]
  448. withTemp(tmp, n[0].typ):
  449. c.gen(n[0], tmp)
  450. # branch tmp, codeIdx
  451. # fjmp elseLabel
  452. for i in 1..<n.len:
  453. let it = n[i]
  454. if it.len == 1:
  455. # else stmt:
  456. if it[0].kind != nkNilLit or it[0].typ != nil:
  457. # an nkNilLit with nil for typ implies there is no else branch, this
  458. # avoids unused related errors as we've already consumed the dest
  459. c.gen(it[0], dest)
  460. else:
  461. let b = rawGenLiteral(c, it)
  462. c.gABx(it, opcBranch, tmp, b)
  463. let elsePos = c.xjmp(it.lastSon, opcFJmp, tmp)
  464. c.gen(it.lastSon, dest)
  465. if i < n.len-1:
  466. endings.add(c.xjmp(it.lastSon, opcJmp, 0))
  467. c.patch(elsePos)
  468. c.clearDest(n, dest)
  469. for endPos in endings: c.patch(endPos)
  470. proc genType(c: PCtx; typ: PType): int =
  471. for i, t in c.types:
  472. if sameType(t, typ): return i
  473. result = c.types.len
  474. c.types.add(typ)
  475. internalAssert(c.config, result <= regBxMax)
  476. proc genTry(c: PCtx; n: PNode; dest: var TDest) =
  477. if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
  478. var endings: seq[TPosition] = @[]
  479. let ehPos = c.xjmp(n, opcTry, 0)
  480. c.gen(n[0], dest)
  481. c.clearDest(n, dest)
  482. # Add a jump past the exception handling code
  483. let jumpToFinally = c.xjmp(n, opcJmp, 0)
  484. # This signals where the body ends and where the exception handling begins
  485. c.patch(ehPos)
  486. for i in 1..<n.len:
  487. let it = n[i]
  488. if it.kind != nkFinally:
  489. # first opcExcept contains the end label of the 'except' block:
  490. let endExcept = c.xjmp(it, opcExcept, 0)
  491. for j in 0..<it.len - 1:
  492. assert(it[j].kind == nkType)
  493. let typ = it[j].typ.skipTypes(abstractPtrs-{tyTypeDesc})
  494. c.gABx(it, opcExcept, 0, c.genType(typ))
  495. if it.len == 1:
  496. # general except section:
  497. c.gABx(it, opcExcept, 0, 0)
  498. c.gen(it.lastSon, dest)
  499. c.clearDest(n, dest)
  500. if i < n.len:
  501. endings.add(c.xjmp(it, opcJmp, 0))
  502. c.patch(endExcept)
  503. let fin = lastSon(n)
  504. # we always generate an 'opcFinally' as that pops the safepoint
  505. # from the stack if no exception is raised in the body.
  506. c.patch(jumpToFinally)
  507. c.gABx(fin, opcFinally, 0, 0)
  508. for endPos in endings: c.patch(endPos)
  509. if fin.kind == nkFinally:
  510. c.gen(fin[0])
  511. c.clearDest(n, dest)
  512. c.gABx(fin, opcFinallyEnd, 0, 0)
  513. proc genRaise(c: PCtx; n: PNode) =
  514. let dest = genx(c, n[0])
  515. c.gABC(n, opcRaise, dest)
  516. c.freeTemp(dest)
  517. proc genReturn(c: PCtx; n: PNode) =
  518. if n[0].kind != nkEmpty:
  519. gen(c, n[0])
  520. c.gABC(n, opcRet)
  521. proc genLit(c: PCtx; n: PNode; dest: var TDest) =
  522. # opcLdConst is now always valid. We produce the necessary copy in the
  523. # assignments now:
  524. #var opc = opcLdConst
  525. if dest < 0: dest = c.getTemp(n.typ)
  526. #elif c.prc.regInfo[dest].kind == slotFixedVar: opc = opcAsgnConst
  527. let lit = genLiteral(c, n)
  528. c.gABx(n, opcLdConst, dest, lit)
  529. proc genCall(c: PCtx; n: PNode; dest: var TDest) =
  530. # it can happen that due to inlining we have a 'n' that should be
  531. # treated as a constant (see issue #537).
  532. #if n.typ != nil and n.typ.sym != nil and n.typ.sym.magic == mPNimrodNode:
  533. # genLit(c, n, dest)
  534. # return
  535. # bug #10901: do not produce code for wrong call expressions:
  536. if n.len == 0 or n[0].typ.isNil: return
  537. if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
  538. let x = c.getTempRange(n.len, slotTempUnknown)
  539. # varargs need 'opcSetType' for the FFI support:
  540. let fntyp = skipTypes(n[0].typ, abstractInst)
  541. for i in 0..<n.len:
  542. var r: TRegister = x+i
  543. c.gen(n[i], r, {gfIsParam})
  544. if i >= fntyp.len:
  545. internalAssert c.config, tfVarargs in fntyp.flags
  546. c.gABx(n, opcSetType, r, c.genType(n[i].typ))
  547. if dest < 0:
  548. c.gABC(n, opcIndCall, 0, x, n.len)
  549. else:
  550. c.gABC(n, opcIndCallAsgn, dest, x, n.len)
  551. c.freeTempRange(x, n.len)
  552. template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
  553. proc isGlobal(n: PNode): bool = n.kind == nkSym and isGlobal(n.sym)
  554. proc needsAsgnPatch(n: PNode): bool =
  555. n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr,
  556. nkDerefExpr, nkHiddenDeref} or (n.kind == nkSym and n.sym.isGlobal)
  557. proc genField(c: PCtx; n: PNode): TRegister =
  558. if n.kind != nkSym or n.sym.kind != skField:
  559. globalError(c.config, n.info, "no field symbol")
  560. let s = n.sym
  561. if s.position > high(typeof(result)):
  562. globalError(c.config, n.info,
  563. "too large offset! cannot generate code for: " & s.name.s)
  564. result = s.position
  565. proc genIndex(c: PCtx; n: PNode; arr: PType): TRegister =
  566. if arr.skipTypes(abstractInst).kind == tyArray and (let x = firstOrd(c.config, arr);
  567. x != Zero):
  568. let tmp = c.genx(n)
  569. # freeing the temporary here means we can produce: regA = regA - Imm
  570. c.freeTemp(tmp)
  571. result = c.getTemp(n.typ)
  572. c.gABI(n, opcSubImmInt, result, tmp, toInt(x))
  573. else:
  574. result = c.genx(n)
  575. proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags)
  576. proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
  577. case le.kind
  578. of nkBracketExpr:
  579. let dest = c.genx(le[0], {gfNode})
  580. let idx = c.genIndex(le[1], le[0].typ)
  581. c.gABC(le, opcWrArr, dest, idx, value)
  582. c.freeTemp(dest)
  583. c.freeTemp(idx)
  584. of nkCheckedFieldExpr:
  585. var objR: TDest = -1
  586. genCheckedObjAccessAux(c, le, objR, {gfNode})
  587. let idx = genField(c, le[0][1])
  588. c.gABC(le[0], opcWrObj, objR, idx, value)
  589. c.freeTemp(objR)
  590. of nkDotExpr:
  591. let dest = c.genx(le[0], {gfNode})
  592. let idx = genField(c, le[1])
  593. c.gABC(le, opcWrObj, dest, idx, value)
  594. c.freeTemp(dest)
  595. of nkDerefExpr, nkHiddenDeref:
  596. let dest = c.genx(le[0], {gfNode})
  597. c.gABC(le, opcWrDeref, dest, 0, value)
  598. c.freeTemp(dest)
  599. of nkSym:
  600. if le.sym.isGlobal:
  601. let dest = c.genx(le, {gfNodeAddr})
  602. c.gABC(le, opcWrDeref, dest, 0, value)
  603. c.freeTemp(dest)
  604. else:
  605. discard
  606. proc genNew(c: PCtx; n: PNode) =
  607. let dest = if needsAsgnPatch(n[1]): c.getTemp(n[1].typ)
  608. else: c.genx(n[1])
  609. # we use the ref's base type here as the VM conflates 'ref object'
  610. # and 'object' since internally we already have a pointer.
  611. c.gABx(n, opcNew, dest,
  612. c.genType(n[1].typ.skipTypes(abstractVar-{tyTypeDesc})[0]))
  613. c.genAsgnPatch(n[1], dest)
  614. c.freeTemp(dest)
  615. proc genNewSeq(c: PCtx; n: PNode) =
  616. let t = n[1].typ
  617. let dest = if needsAsgnPatch(n[1]): c.getTemp(t)
  618. else: c.genx(n[1])
  619. let tmp = c.genx(n[2])
  620. c.gABx(n, opcNewSeq, dest, c.genType(t.skipTypes(
  621. abstractVar-{tyTypeDesc})))
  622. c.gABx(n, opcNewSeq, tmp, 0)
  623. c.freeTemp(tmp)
  624. c.genAsgnPatch(n[1], dest)
  625. c.freeTemp(dest)
  626. proc genNewSeqOfCap(c: PCtx; n: PNode; dest: var TDest) =
  627. let t = n.typ
  628. if dest < 0:
  629. dest = c.getTemp(n.typ)
  630. let tmp = c.getTemp(n[1].typ)
  631. c.gABx(n, opcLdNull, dest, c.genType(t))
  632. c.gABx(n, opcLdImmInt, tmp, 0)
  633. c.gABx(n, opcNewSeq, dest, c.genType(t.skipTypes(
  634. abstractVar-{tyTypeDesc})))
  635. c.gABx(n, opcNewSeq, tmp, 0)
  636. c.freeTemp(tmp)
  637. proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  638. let tmp = c.genx(n[1])
  639. if dest < 0: dest = c.getTemp(n.typ)
  640. c.gABC(n, opc, dest, tmp)
  641. c.freeTemp(tmp)
  642. proc genUnaryABI(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; imm: BiggestInt=0) =
  643. let tmp = c.genx(n[1])
  644. if dest < 0: dest = c.getTemp(n.typ)
  645. c.gABI(n, opc, dest, tmp, imm)
  646. c.freeTemp(tmp)
  647. proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  648. let
  649. tmp = c.genx(n[1])
  650. tmp2 = c.genx(n[2])
  651. if dest < 0: dest = c.getTemp(n.typ)
  652. c.gABC(n, opc, dest, tmp, tmp2)
  653. c.freeTemp(tmp)
  654. c.freeTemp(tmp2)
  655. proc genBinaryABCD(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  656. let
  657. tmp = c.genx(n[1])
  658. tmp2 = c.genx(n[2])
  659. tmp3 = c.genx(n[3])
  660. if dest < 0: dest = c.getTemp(n.typ)
  661. c.gABC(n, opc, dest, tmp, tmp2)
  662. c.gABC(n, opc, tmp3)
  663. c.freeTemp(tmp)
  664. c.freeTemp(tmp2)
  665. c.freeTemp(tmp3)
  666. template sizeOfLikeMsg(name): string =
  667. "'$1' requires '.importc' types to be '.completeStruct'" % [name]
  668. proc genNarrow(c: PCtx; n: PNode; dest: TDest) =
  669. let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
  670. # uint is uint64 in the VM, we we only need to mask the result for
  671. # other unsigned types:
  672. let size = getSize(c.config, t)
  673. if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
  674. c.gABC(n, opcNarrowU, dest, TRegister(size*8))
  675. elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and size < 8):
  676. c.gABC(n, opcNarrowS, dest, TRegister(size*8))
  677. proc genNarrowU(c: PCtx; n: PNode; dest: TDest) =
  678. let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
  679. # uint is uint64 in the VM, we we only need to mask the result for
  680. # other unsigned types:
  681. let size = getSize(c.config, t)
  682. if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
  683. (t.kind in {tyUInt, tyInt} and size < 8):
  684. c.gABC(n, opcNarrowU, dest, TRegister(size*8))
  685. proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  686. genBinaryABC(c, n, dest, opc)
  687. genNarrow(c, n, dest)
  688. proc genBinaryABCnarrowU(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  689. genBinaryABC(c, n, dest, opc)
  690. genNarrowU(c, n, dest)
  691. proc genSetType(c: PCtx; n: PNode; dest: TRegister) =
  692. let t = skipTypes(n.typ, abstractInst-{tyTypeDesc})
  693. if t.kind == tySet:
  694. c.gABx(n, opcSetType, dest, c.genType(t))
  695. proc genBinarySet(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  696. let
  697. tmp = c.genx(n[1])
  698. tmp2 = c.genx(n[2])
  699. if dest < 0: dest = c.getTemp(n.typ)
  700. c.genSetType(n[1], tmp)
  701. c.genSetType(n[2], tmp2)
  702. c.gABC(n, opc, dest, tmp, tmp2)
  703. c.freeTemp(tmp)
  704. c.freeTemp(tmp2)
  705. proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
  706. let
  707. dest = c.genx(n[1])
  708. tmp = c.genx(n[2])
  709. c.gABC(n, opc, dest, tmp, 0)
  710. c.freeTemp(tmp)
  711. c.freeTemp(dest)
  712. proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) =
  713. var x = n[1]
  714. if x.kind in {nkAddr, nkHiddenAddr}: x = x[0]
  715. let
  716. dest = c.genx(x)
  717. tmp = c.genx(n[2])
  718. c.gABC(n, opc, dest, tmp, 0)
  719. #c.genAsgnPatch(n[1], dest)
  720. c.freeTemp(tmp)
  721. c.freeTemp(dest)
  722. proc genUnaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
  723. let tmp = c.genx(n[1])
  724. c.gABC(n, opc, tmp, 0, 0)
  725. c.freeTemp(tmp)
  726. proc genVarargsABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  727. if dest < 0: dest = getTemp(c, n.typ)
  728. var x = c.getTempRange(n.len-1, slotTempStr)
  729. for i in 1..<n.len:
  730. var r: TRegister = x+i-1
  731. c.gen(n[i], r)
  732. c.gABC(n, opc, dest, x, n.len-1)
  733. c.freeTempRange(x, n.len-1)
  734. proc isInt8Lit(n: PNode): bool =
  735. if n.kind in {nkCharLit..nkUInt64Lit}:
  736. result = n.intVal >= low(int8) and n.intVal <= high(int8)
  737. proc isInt16Lit(n: PNode): bool =
  738. if n.kind in {nkCharLit..nkUInt64Lit}:
  739. result = n.intVal >= low(int16) and n.intVal <= high(int16)
  740. proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  741. if n[2].isInt8Lit:
  742. let tmp = c.genx(n[1])
  743. if dest < 0: dest = c.getTemp(n.typ)
  744. c.gABI(n, succ(opc), dest, tmp, n[2].intVal)
  745. c.freeTemp(tmp)
  746. else:
  747. genBinaryABC(c, n, dest, opc)
  748. c.genNarrow(n, dest)
  749. proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
  750. let t2 = n.typ.skipTypes({tyDistinct})
  751. let targ2 = arg.typ.skipTypes({tyDistinct})
  752. proc implicitConv(): bool =
  753. if sameType(t2, targ2): return true
  754. # xxx consider whether to use t2 and targ2 here
  755. if n.typ.kind == arg.typ.kind and arg.typ.kind == tyProc:
  756. # don't do anything for lambda lifting conversions:
  757. return true
  758. if implicitConv():
  759. gen(c, arg, dest)
  760. return
  761. let tmp = c.genx(arg)
  762. if dest < 0: dest = c.getTemp(n.typ)
  763. c.gABC(n, opc, dest, tmp)
  764. c.gABx(n, opc, 0, genType(c, n.typ.skipTypes({tyStatic})))
  765. c.gABx(n, opc, 0, genType(c, arg.typ.skipTypes({tyStatic})))
  766. c.freeTemp(tmp)
  767. proc genCard(c: PCtx; n: PNode; dest: var TDest) =
  768. let tmp = c.genx(n[1])
  769. if dest < 0: dest = c.getTemp(n.typ)
  770. c.genSetType(n[1], tmp)
  771. c.gABC(n, opcCard, dest, tmp)
  772. c.freeTemp(tmp)
  773. proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
  774. const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar}
  775. var signedIntegers = {tyInt..tyInt64}
  776. var unsignedIntegers = {tyUInt..tyUInt64, tyChar}
  777. let src = n[1].typ.skipTypes(abstractRange)#.kind
  778. let dst = n[0].typ.skipTypes(abstractRange)#.kind
  779. let srcSize = getSize(c.config, src)
  780. let dstSize = getSize(c.config, dst)
  781. if src.kind in allowedIntegers and dst.kind in allowedIntegers:
  782. let tmp = c.genx(n[1])
  783. if dest < 0: dest = c.getTemp(n[0].typ)
  784. c.gABC(n, opcAsgnInt, dest, tmp)
  785. if dstSize != sizeof(BiggestInt): # don't do anything on biggest int types
  786. if dst.kind in signedIntegers: # we need to do sign extensions
  787. if dstSize <= srcSize:
  788. # Sign extension can be omitted when the size increases.
  789. c.gABC(n, opcSignExtend, dest, TRegister(dstSize*8))
  790. elif dst.kind in unsignedIntegers:
  791. if src.kind in signedIntegers or dstSize < srcSize:
  792. # Cast from signed to unsigned always needs narrowing. Cast
  793. # from unsigned to unsigned only needs narrowing when target
  794. # is smaller than source.
  795. c.gABC(n, opcNarrowU, dest, TRegister(dstSize*8))
  796. c.freeTemp(tmp)
  797. elif srcSize == dstSize and src.kind in allowedIntegers and
  798. dst.kind in {tyFloat, tyFloat32, tyFloat64}:
  799. let tmp = c.genx(n[1])
  800. if dest < 0: dest = c.getTemp(n[0].typ)
  801. if dst.kind == tyFloat32:
  802. c.gABC(n, opcCastIntToFloat32, dest, tmp)
  803. else:
  804. c.gABC(n, opcCastIntToFloat64, dest, tmp)
  805. c.freeTemp(tmp)
  806. elif srcSize == dstSize and src.kind in {tyFloat, tyFloat32, tyFloat64} and
  807. dst.kind in allowedIntegers:
  808. let tmp = c.genx(n[1])
  809. if dest < 0: dest = c.getTemp(n[0].typ)
  810. if src.kind == tyFloat32:
  811. c.gABC(n, opcCastFloatToInt32, dest, tmp)
  812. if dst.kind in unsignedIntegers:
  813. # integers are sign extended by default.
  814. # since there is no opcCastFloatToUInt32, narrowing should do the trick.
  815. c.gABC(n, opcNarrowU, dest, TRegister(32))
  816. else:
  817. c.gABC(n, opcCastFloatToInt64, dest, tmp)
  818. # narrowing for 64 bits not needed (no extended sign bits available).
  819. c.freeTemp(tmp)
  820. elif src.kind in PtrLikeKinds + {tyRef} and dst.kind == tyInt:
  821. let tmp = c.genx(n[1])
  822. if dest < 0: dest = c.getTemp(n[0].typ)
  823. var imm: BiggestInt = if src.kind in PtrLikeKinds: 1 else: 2
  824. c.gABI(n, opcCastPtrToInt, dest, tmp, imm)
  825. c.freeTemp(tmp)
  826. elif src.kind in PtrLikeKinds + {tyInt} and dst.kind in PtrLikeKinds:
  827. let tmp = c.genx(n[1])
  828. if dest < 0: dest = c.getTemp(n[0].typ)
  829. c.gABx(n, opcSetType, dest, c.genType(dst))
  830. c.gABC(n, opcCastIntToPtr, dest, tmp)
  831. c.freeTemp(tmp)
  832. elif src.kind == tyNil and dst.kind in NilableTypes:
  833. # supports casting nil literals to NilableTypes in VM
  834. # see #16024
  835. if dest < 0: dest = c.getTemp(n[0].typ)
  836. genLit(c, n[1], dest)
  837. else:
  838. # todo: support cast from tyInt to tyRef
  839. globalError(c.config, n.info, "VM does not support 'cast' from " & $src.kind & " to " & $dst.kind)
  840. proc genVoidABC(c: PCtx, n: PNode, dest: TDest, opcode: TOpcode) =
  841. unused(c, n, dest)
  842. var
  843. tmp1 = c.genx(n[1])
  844. tmp2 = c.genx(n[2])
  845. tmp3 = c.genx(n[3])
  846. c.gABC(n, opcode, tmp1, tmp2, tmp3)
  847. c.freeTemp(tmp1)
  848. c.freeTemp(tmp2)
  849. c.freeTemp(tmp3)
  850. proc genBindSym(c: PCtx; n: PNode; dest: var TDest) =
  851. # nah, cannot use c.config.features because sempass context
  852. # can have local experimental switch
  853. # if dynamicBindSym notin c.config.features:
  854. if n.len == 2: # hmm, reliable?
  855. # bindSym with static input
  856. if n[1].kind in {nkClosedSymChoice, nkOpenSymChoice, nkSym}:
  857. let idx = c.genLiteral(n[1])
  858. if dest < 0: dest = c.getTemp(n.typ)
  859. c.gABx(n, opcNBindSym, dest, idx)
  860. else:
  861. localError(c.config, n.info, "invalid bindSym usage")
  862. else:
  863. # experimental bindSym
  864. if dest < 0: dest = c.getTemp(n.typ)
  865. let x = c.getTempRange(n.len, slotTempUnknown)
  866. # callee symbol
  867. var tmp0 = TDest(x)
  868. c.genLit(n[0], tmp0)
  869. # original parameters
  870. for i in 1..<n.len-2:
  871. var r = TRegister(x+i)
  872. c.gen(n[i], r)
  873. # info node
  874. var tmp1 = TDest(x+n.len-2)
  875. c.genLit(n[^2], tmp1)
  876. # payload idx
  877. var tmp2 = TDest(x+n.len-1)
  878. c.genLit(n[^1], tmp2)
  879. c.gABC(n, opcNDynBindSym, dest, x, n.len)
  880. c.freeTempRange(x, n.len)
  881. proc fitsRegister*(t: PType): bool =
  882. assert t != nil
  883. t.skipTypes(abstractInst + {tyStatic} - {tyTypeDesc}).kind in {
  884. tyRange, tyEnum, tyBool, tyInt..tyUInt64, tyChar}
  885. proc ldNullOpcode(t: PType): TOpcode =
  886. assert t != nil
  887. if fitsRegister(t): opcLdNullReg else: opcLdNull
  888. proc whichAsgnOpc(n: PNode; requiresCopy = true): TOpcode =
  889. case n.typ.skipTypes(abstractRange+{tyOwned}-{tyTypeDesc}).kind
  890. of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64:
  891. opcAsgnInt
  892. of tyFloat..tyFloat128:
  893. opcAsgnFloat
  894. of tyRef, tyNil, tyVar, tyLent, tyPtr:
  895. opcAsgnRef
  896. else:
  897. (if requiresCopy: opcAsgnComplex else: opcFastAsgnComplex)
  898. proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
  899. case m
  900. of mAnd: c.genAndOr(n, opcFJmp, dest)
  901. of mOr: c.genAndOr(n, opcTJmp, dest)
  902. of mPred, mSubI:
  903. c.genAddSubInt(n, dest, opcSubInt)
  904. of mSucc, mAddI:
  905. c.genAddSubInt(n, dest, opcAddInt)
  906. of mInc, mDec:
  907. unused(c, n, dest)
  908. let isUnsigned = n[1].typ.skipTypes(abstractVarRange).kind in {tyUInt..tyUInt64}
  909. let opc = if not isUnsigned:
  910. if m == mInc: opcAddInt else: opcSubInt
  911. else:
  912. if m == mInc: opcAddu else: opcSubu
  913. let d = c.genx(n[1])
  914. if n[2].isInt8Lit and not isUnsigned:
  915. c.gABI(n, succ(opc), d, d, n[2].intVal)
  916. else:
  917. let tmp = c.genx(n[2])
  918. c.gABC(n, opc, d, d, tmp)
  919. c.freeTemp(tmp)
  920. c.genNarrow(n[1], d)
  921. c.genAsgnPatch(n[1], d)
  922. c.freeTemp(d)
  923. of mOrd, mChr, mArrToSeq, mUnown: c.gen(n[1], dest)
  924. of mIsolate, mFinished:
  925. genCall(c, n, dest)
  926. of mNew, mNewFinalize:
  927. unused(c, n, dest)
  928. c.genNew(n)
  929. of mNewSeq:
  930. unused(c, n, dest)
  931. c.genNewSeq(n)
  932. of mNewSeqOfCap: c.genNewSeqOfCap(n, dest)
  933. of mNewString:
  934. genUnaryABC(c, n, dest, opcNewStr)
  935. # XXX buggy
  936. of mNewStringOfCap:
  937. # we ignore the 'cap' argument and translate it as 'newString(0)'.
  938. # eval n[1] for possible side effects:
  939. c.freeTemp(c.genx(n[1]))
  940. var tmp = c.getTemp(n[1].typ)
  941. c.gABx(n, opcLdImmInt, tmp, 0)
  942. if dest < 0: dest = c.getTemp(n.typ)
  943. c.gABC(n, opcNewStr, dest, tmp)
  944. c.freeTemp(tmp)
  945. # XXX buggy
  946. of mLengthOpenArray, mLengthArray, mLengthSeq:
  947. genUnaryABI(c, n, dest, opcLenSeq)
  948. of mLengthStr:
  949. case n[1].typ.kind
  950. of tyString: genUnaryABI(c, n, dest, opcLenStr)
  951. of tyCstring: genUnaryABI(c, n, dest, opcLenCstring)
  952. else: doAssert false, $n[1].typ.kind
  953. of mIncl, mExcl:
  954. unused(c, n, dest)
  955. var d = c.genx(n[1])
  956. var tmp = c.genx(n[2])
  957. c.genSetType(n[1], d)
  958. c.gABC(n, if m == mIncl: opcIncl else: opcExcl, d, tmp)
  959. c.freeTemp(d)
  960. c.freeTemp(tmp)
  961. of mCard: genCard(c, n, dest)
  962. of mMulI: genBinaryABCnarrow(c, n, dest, opcMulInt)
  963. of mDivI: genBinaryABCnarrow(c, n, dest, opcDivInt)
  964. of mModI: genBinaryABCnarrow(c, n, dest, opcModInt)
  965. of mAddF64: genBinaryABC(c, n, dest, opcAddFloat)
  966. of mSubF64: genBinaryABC(c, n, dest, opcSubFloat)
  967. of mMulF64: genBinaryABC(c, n, dest, opcMulFloat)
  968. of mDivF64: genBinaryABC(c, n, dest, opcDivFloat)
  969. of mShrI:
  970. # modified: genBinaryABC(c, n, dest, opcShrInt)
  971. # narrowU is applied to the left operandthe idea here is to narrow the left operand
  972. let tmp = c.genx(n[1])
  973. c.genNarrowU(n, tmp)
  974. let tmp2 = c.genx(n[2])
  975. if dest < 0: dest = c.getTemp(n.typ)
  976. c.gABC(n, opcShrInt, dest, tmp, tmp2)
  977. c.freeTemp(tmp)
  978. c.freeTemp(tmp2)
  979. of mShlI:
  980. genBinaryABC(c, n, dest, opcShlInt)
  981. # genNarrowU modified
  982. let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
  983. let size = getSize(c.config, t)
  984. if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
  985. c.gABC(n, opcNarrowU, dest, TRegister(size*8))
  986. elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and size < 8):
  987. c.gABC(n, opcSignExtend, dest, TRegister(size*8))
  988. of mAshrI: genBinaryABC(c, n, dest, opcAshrInt)
  989. of mBitandI: genBinaryABC(c, n, dest, opcBitandInt)
  990. of mBitorI: genBinaryABC(c, n, dest, opcBitorInt)
  991. of mBitxorI: genBinaryABC(c, n, dest, opcBitxorInt)
  992. of mAddU: genBinaryABCnarrowU(c, n, dest, opcAddu)
  993. of mSubU: genBinaryABCnarrowU(c, n, dest, opcSubu)
  994. of mMulU: genBinaryABCnarrowU(c, n, dest, opcMulu)
  995. of mDivU: genBinaryABCnarrowU(c, n, dest, opcDivu)
  996. of mModU: genBinaryABCnarrowU(c, n, dest, opcModu)
  997. of mEqI, mEqB, mEqEnum, mEqCh:
  998. genBinaryABC(c, n, dest, opcEqInt)
  999. of mLeI, mLeEnum, mLeCh, mLeB:
  1000. genBinaryABC(c, n, dest, opcLeInt)
  1001. of mLtI, mLtEnum, mLtCh, mLtB:
  1002. genBinaryABC(c, n, dest, opcLtInt)
  1003. of mEqF64: genBinaryABC(c, n, dest, opcEqFloat)
  1004. of mLeF64: genBinaryABC(c, n, dest, opcLeFloat)
  1005. of mLtF64: genBinaryABC(c, n, dest, opcLtFloat)
  1006. of mLePtr, mLeU: genBinaryABC(c, n, dest, opcLeu)
  1007. of mLtPtr, mLtU: genBinaryABC(c, n, dest, opcLtu)
  1008. of mEqProc, mEqRef:
  1009. genBinaryABC(c, n, dest, opcEqRef)
  1010. of mXor: genBinaryABC(c, n, dest, opcXor)
  1011. of mNot: genUnaryABC(c, n, dest, opcNot)
  1012. of mUnaryMinusI, mUnaryMinusI64:
  1013. genUnaryABC(c, n, dest, opcUnaryMinusInt)
  1014. genNarrow(c, n, dest)
  1015. of mUnaryMinusF64: genUnaryABC(c, n, dest, opcUnaryMinusFloat)
  1016. of mUnaryPlusI, mUnaryPlusF64: gen(c, n[1], dest)
  1017. of mBitnotI:
  1018. genUnaryABC(c, n, dest, opcBitnotInt)
  1019. #genNarrowU modified, do not narrow signed types
  1020. let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
  1021. let size = getSize(c.config, t)
  1022. if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
  1023. c.gABC(n, opcNarrowU, dest, TRegister(size*8))
  1024. of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
  1025. genConv(c, n, n[1], dest)
  1026. of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
  1027. of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
  1028. of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
  1029. of mEqSet: genBinarySet(c, n, dest, opcEqSet)
  1030. of mLeSet: genBinarySet(c, n, dest, opcLeSet)
  1031. of mLtSet: genBinarySet(c, n, dest, opcLtSet)
  1032. of mMulSet: genBinarySet(c, n, dest, opcMulSet)
  1033. of mPlusSet: genBinarySet(c, n, dest, opcPlusSet)
  1034. of mMinusSet: genBinarySet(c, n, dest, opcMinusSet)
  1035. of mConStrStr: genVarargsABC(c, n, dest, opcConcatStr)
  1036. of mInSet: genBinarySet(c, n, dest, opcContainsSet)
  1037. of mRepr: genUnaryABC(c, n, dest, opcRepr)
  1038. of mExit:
  1039. unused(c, n, dest)
  1040. var tmp = c.genx(n[1])
  1041. c.gABC(n, opcQuit, tmp)
  1042. c.freeTemp(tmp)
  1043. of mSetLengthStr, mSetLengthSeq:
  1044. unused(c, n, dest)
  1045. var d = c.genx(n[1])
  1046. var tmp = c.genx(n[2])
  1047. c.gABC(n, if m == mSetLengthStr: opcSetLenStr else: opcSetLenSeq, d, tmp)
  1048. c.genAsgnPatch(n[1], d)
  1049. c.freeTemp(tmp)
  1050. c.freeTemp(d)
  1051. of mSwap:
  1052. unused(c, n, dest)
  1053. c.gen(lowerSwap(c.graph, n, c.idgen, if c.prc == nil or c.prc.sym == nil: c.module else: c.prc.sym))
  1054. of mIsNil: genUnaryABC(c, n, dest, opcIsNil)
  1055. of mParseBiggestFloat:
  1056. if dest < 0: dest = c.getTemp(n.typ)
  1057. var d2: TRegister
  1058. # skip 'nkHiddenAddr':
  1059. let d2AsNode = n[2][0]
  1060. if needsAsgnPatch(d2AsNode):
  1061. d2 = c.getTemp(getSysType(c.graph, n.info, tyFloat))
  1062. else:
  1063. d2 = c.genx(d2AsNode)
  1064. var
  1065. tmp1 = c.genx(n[1])
  1066. tmp3 = c.genx(n[3])
  1067. c.gABC(n, opcParseFloat, dest, tmp1, d2)
  1068. c.gABC(n, opcParseFloat, tmp3)
  1069. c.freeTemp(tmp1)
  1070. c.freeTemp(tmp3)
  1071. c.genAsgnPatch(d2AsNode, d2)
  1072. c.freeTemp(d2)
  1073. of mReset:
  1074. unused(c, n, dest)
  1075. var d = c.genx(n[1])
  1076. # XXX use ldNullOpcode() here?
  1077. c.gABx(n, opcLdNull, d, c.genType(n[1].typ))
  1078. c.gABx(n, opcNodeToReg, d, d)
  1079. c.genAsgnPatch(n[1], d)
  1080. of mDefault:
  1081. if dest < 0: dest = c.getTemp(n.typ)
  1082. c.gABx(n, ldNullOpcode(n.typ), dest, c.genType(n.typ))
  1083. of mOf, mIs:
  1084. if dest < 0: dest = c.getTemp(n.typ)
  1085. var tmp = c.genx(n[1])
  1086. var idx = c.getTemp(getSysType(c.graph, n.info, tyInt))
  1087. var typ = n[2].typ
  1088. if m == mOf: typ = typ.skipTypes(abstractPtrs)
  1089. c.gABx(n, opcLdImmInt, idx, c.genType(typ))
  1090. c.gABC(n, if m == mOf: opcOf else: opcIs, dest, tmp, idx)
  1091. c.freeTemp(tmp)
  1092. c.freeTemp(idx)
  1093. of mHigh:
  1094. if dest < 0: dest = c.getTemp(n.typ)
  1095. let tmp = c.genx(n[1])
  1096. case n[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind:
  1097. of tyString: c.gABI(n, opcLenStr, dest, tmp, 1)
  1098. of tyCstring: c.gABI(n, opcLenCstring, dest, tmp, 1)
  1099. else: c.gABI(n, opcLenSeq, dest, tmp, 1)
  1100. c.freeTemp(tmp)
  1101. of mEcho:
  1102. unused(c, n, dest)
  1103. let n = n[1].skipConv
  1104. if n.kind == nkBracket:
  1105. # can happen for nim check, see bug #9609
  1106. let x = c.getTempRange(n.len, slotTempUnknown)
  1107. for i in 0..<n.len:
  1108. var r: TRegister = x+i
  1109. c.gen(n[i], r)
  1110. c.gABC(n, opcEcho, x, n.len)
  1111. c.freeTempRange(x, n.len)
  1112. of mAppendStrCh:
  1113. unused(c, n, dest)
  1114. genBinaryStmtVar(c, n, opcAddStrCh)
  1115. of mAppendStrStr:
  1116. unused(c, n, dest)
  1117. genBinaryStmtVar(c, n, opcAddStrStr)
  1118. of mAppendSeqElem:
  1119. unused(c, n, dest)
  1120. genBinaryStmtVar(c, n, opcAddSeqElem)
  1121. of mParseExprToAst:
  1122. genUnaryABC(c, n, dest, opcParseExprToAst)
  1123. of mParseStmtToAst:
  1124. genUnaryABC(c, n, dest, opcParseStmtToAst)
  1125. of mTypeTrait:
  1126. let tmp = c.genx(n[1])
  1127. if dest < 0: dest = c.getTemp(n.typ)
  1128. c.gABx(n, opcSetType, tmp, c.genType(n[1].typ))
  1129. c.gABC(n, opcTypeTrait, dest, tmp)
  1130. c.freeTemp(tmp)
  1131. of mSlurp: genUnaryABC(c, n, dest, opcSlurp)
  1132. of mStaticExec: genBinaryABCD(c, n, dest, opcGorge)
  1133. of mNLen: genUnaryABI(c, n, dest, opcLenSeq, nimNodeFlag)
  1134. of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl)
  1135. of mGetImplTransf: genUnaryABC(c, n, dest, opcGetImplTransf)
  1136. of mSymOwner: genUnaryABC(c, n, dest, opcSymOwner)
  1137. of mSymIsInstantiationOf: genBinaryABC(c, n, dest, opcSymIsInstantiationOf)
  1138. of mNChild: genBinaryABC(c, n, dest, opcNChild)
  1139. of mNSetChild: genVoidABC(c, n, dest, opcNSetChild)
  1140. of mNDel: genVoidABC(c, n, dest, opcNDel)
  1141. of mNAdd: genBinaryABC(c, n, dest, opcNAdd)
  1142. of mNAddMultiple: genBinaryABC(c, n, dest, opcNAddMultiple)
  1143. of mNKind: genUnaryABC(c, n, dest, opcNKind)
  1144. of mNSymKind: genUnaryABC(c, n, dest, opcNSymKind)
  1145. of mNccValue: genUnaryABC(c, n, dest, opcNccValue)
  1146. of mNccInc: genBinaryABC(c, n, dest, opcNccInc)
  1147. of mNcsAdd: genBinaryABC(c, n, dest, opcNcsAdd)
  1148. of mNcsIncl: genBinaryABC(c, n, dest, opcNcsIncl)
  1149. of mNcsLen: genUnaryABC(c, n, dest, opcNcsLen)
  1150. of mNcsAt: genBinaryABC(c, n, dest, opcNcsAt)
  1151. of mNctPut: genVoidABC(c, n, dest, opcNctPut)
  1152. of mNctLen: genUnaryABC(c, n, dest, opcNctLen)
  1153. of mNctGet: genBinaryABC(c, n, dest, opcNctGet)
  1154. of mNctHasNext: genBinaryABC(c, n, dest, opcNctHasNext)
  1155. of mNctNext: genBinaryABC(c, n, dest, opcNctNext)
  1156. of mNIntVal: genUnaryABC(c, n, dest, opcNIntVal)
  1157. of mNFloatVal: genUnaryABC(c, n, dest, opcNFloatVal)
  1158. of mNSymbol: genUnaryABC(c, n, dest, opcNSymbol)
  1159. of mNIdent: genUnaryABC(c, n, dest, opcNIdent)
  1160. of mNGetType:
  1161. let tmp = c.genx(n[1])
  1162. if dest < 0: dest = c.getTemp(n.typ)
  1163. let rc = case n[0].sym.name.s:
  1164. of "getType": 0
  1165. of "typeKind": 1
  1166. of "getTypeInst": 2
  1167. else: 3 # "getTypeImpl"
  1168. c.gABC(n, opcNGetType, dest, tmp, rc)
  1169. c.freeTemp(tmp)
  1170. #genUnaryABC(c, n, dest, opcNGetType)
  1171. of mNSizeOf:
  1172. let imm = case n[0].sym.name.s:
  1173. of "getSize": 0
  1174. of "getAlign": 1
  1175. else: 2 # "getOffset"
  1176. c.genUnaryABI(n, dest, opcNGetSize, imm)
  1177. of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
  1178. of mNSigHash: genUnaryABC(c, n , dest, opcNSigHash)
  1179. of mNSetIntVal:
  1180. unused(c, n, dest)
  1181. genBinaryStmt(c, n, opcNSetIntVal)
  1182. of mNSetFloatVal:
  1183. unused(c, n, dest)
  1184. genBinaryStmt(c, n, opcNSetFloatVal)
  1185. of mNSetSymbol:
  1186. unused(c, n, dest)
  1187. genBinaryStmt(c, n, opcNSetSymbol)
  1188. of mNSetIdent:
  1189. unused(c, n, dest)
  1190. genBinaryStmt(c, n, opcNSetIdent)
  1191. of mNSetType:
  1192. unused(c, n, dest)
  1193. genBinaryStmt(c, n, opcNSetType)
  1194. of mNSetStrVal:
  1195. unused(c, n, dest)
  1196. genBinaryStmt(c, n, opcNSetStrVal)
  1197. of mNNewNimNode: genBinaryABC(c, n, dest, opcNNewNimNode)
  1198. of mNCopyNimNode: genUnaryABC(c, n, dest, opcNCopyNimNode)
  1199. of mNCopyNimTree: genUnaryABC(c, n, dest, opcNCopyNimTree)
  1200. of mNBindSym: genBindSym(c, n, dest)
  1201. of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
  1202. of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
  1203. of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimNode)
  1204. of mSameNodeType: genBinaryABC(c, n, dest, opcSameNodeType)
  1205. of mNLineInfo:
  1206. case n[0].sym.name.s
  1207. of "getFile": genUnaryABI(c, n, dest, opcNGetLineInfo, 0)
  1208. of "getLine": genUnaryABI(c, n, dest, opcNGetLineInfo, 1)
  1209. of "getColumn": genUnaryABI(c, n, dest, opcNGetLineInfo, 2)
  1210. of "copyLineInfo":
  1211. internalAssert c.config, n.len == 3
  1212. unused(c, n, dest)
  1213. genBinaryStmt(c, n, opcNSetLineInfo)
  1214. else: internalAssert c.config, false
  1215. of mNHint:
  1216. unused(c, n, dest)
  1217. genBinaryStmt(c, n, opcNHint)
  1218. of mNWarning:
  1219. unused(c, n, dest)
  1220. genBinaryStmt(c, n, opcNWarning)
  1221. of mNError:
  1222. if n.len <= 1:
  1223. # query error condition:
  1224. c.gABC(n, opcQueryErrorFlag, dest)
  1225. else:
  1226. # setter
  1227. unused(c, n, dest)
  1228. genBinaryStmt(c, n, opcNError)
  1229. of mNCallSite:
  1230. if dest < 0: dest = c.getTemp(n.typ)
  1231. c.gABC(n, opcCallSite, dest)
  1232. of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
  1233. of mMinI, mMaxI, mAbsI, mDotDot:
  1234. c.genCall(n, dest)
  1235. of mExpandToAst:
  1236. if n.len != 2:
  1237. globalError(c.config, n.info, "expandToAst requires 1 argument")
  1238. let arg = n[1]
  1239. if arg.kind in nkCallKinds:
  1240. #if arg[0].kind != nkSym or arg[0].sym.kind notin {skTemplate, skMacro}:
  1241. # "ExpandToAst: expanded symbol is no macro or template"
  1242. if dest < 0: dest = c.getTemp(n.typ)
  1243. c.genCall(arg, dest)
  1244. # do not call clearDest(n, dest) here as getAst has a meta-type as such
  1245. # produces a value
  1246. else:
  1247. globalError(c.config, n.info, "expandToAst requires a call expression")
  1248. of mSizeOf:
  1249. globalError(c.config, n.info, sizeOfLikeMsg("sizeof"))
  1250. of mAlignOf:
  1251. globalError(c.config, n.info, sizeOfLikeMsg("alignof"))
  1252. of mOffsetOf:
  1253. globalError(c.config, n.info, sizeOfLikeMsg("offsetof"))
  1254. of mRunnableExamples:
  1255. discard "just ignore any call to runnableExamples"
  1256. of mDestroy, mTrace: discard "ignore calls to the default destructor"
  1257. of mMove:
  1258. let arg = n[1]
  1259. let a = c.genx(arg)
  1260. if dest < 0: dest = c.getTemp(arg.typ)
  1261. gABC(c, arg, whichAsgnOpc(arg, requiresCopy=false), dest, a)
  1262. # XXX use ldNullOpcode() here?
  1263. # Don't zero out the arg for now #17199
  1264. # c.gABx(n, opcLdNull, a, c.genType(arg.typ))
  1265. # c.gABx(n, opcNodeToReg, a, a)
  1266. # c.genAsgnPatch(arg, a)
  1267. c.freeTemp(a)
  1268. of mNodeId:
  1269. c.genUnaryABC(n, dest, opcNodeId)
  1270. else:
  1271. # mGCref, mGCunref,
  1272. globalError(c.config, n.info, "cannot generate code for: " & $m)
  1273. proc genMarshalLoad(c: PCtx, n: PNode, dest: var TDest) =
  1274. ## Signature: proc to*[T](data: string): T
  1275. if dest < 0: dest = c.getTemp(n.typ)
  1276. var tmp = c.genx(n[1])
  1277. c.gABC(n, opcMarshalLoad, dest, tmp)
  1278. c.gABx(n, opcMarshalLoad, 0, c.genType(n.typ))
  1279. c.freeTemp(tmp)
  1280. proc genMarshalStore(c: PCtx, n: PNode, dest: var TDest) =
  1281. ## Signature: proc `$$`*[T](x: T): string
  1282. if dest < 0: dest = c.getTemp(n.typ)
  1283. var tmp = c.genx(n[1])
  1284. c.gABC(n, opcMarshalStore, dest, tmp)
  1285. c.gABx(n, opcMarshalStore, 0, c.genType(n[1].typ))
  1286. c.freeTemp(tmp)
  1287. proc unneededIndirection(n: PNode): bool =
  1288. n.typ.skipTypes(abstractInstOwned-{tyTypeDesc}).kind == tyRef
  1289. proc canElimAddr(n: PNode): PNode =
  1290. case n[0].kind
  1291. of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
  1292. var m = n[0][0]
  1293. if m.kind in {nkDerefExpr, nkHiddenDeref}:
  1294. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  1295. result = copyNode(n[0])
  1296. result.add m[0]
  1297. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  1298. var m = n[0][1]
  1299. if m.kind in {nkDerefExpr, nkHiddenDeref}:
  1300. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  1301. result = copyNode(n[0])
  1302. result.add m[0]
  1303. else:
  1304. if n[0].kind in {nkDerefExpr, nkHiddenDeref}:
  1305. # addr ( deref ( x )) --> x
  1306. result = n[0][0]
  1307. proc genAddr(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) =
  1308. if (let m = canElimAddr(n); m != nil):
  1309. gen(c, m, dest, flags)
  1310. return
  1311. let newflags = flags-{gfNode}+{gfNodeAddr}
  1312. if isGlobal(n[0]) or n[0].kind in {nkDotExpr, nkCheckedFieldExpr, nkBracketExpr}:
  1313. # checking for this pattern: addr(obj.field) / addr(array[i])
  1314. gen(c, n[0], dest, newflags)
  1315. else:
  1316. let tmp = c.genx(n[0], newflags)
  1317. if dest < 0: dest = c.getTemp(n.typ)
  1318. if c.prc.regInfo[tmp].kind >= slotTempUnknown:
  1319. gABC(c, n, opcAddrNode, dest, tmp)
  1320. # hack ahead; in order to fix bug #1781 we mark the temporary as
  1321. # permanent, so that it's not used for anything else:
  1322. c.prc.regInfo[tmp].kind = slotTempPerm
  1323. # XXX this is still a hack
  1324. #message(c.congig, n.info, warnUser, "suspicious opcode used")
  1325. else:
  1326. gABC(c, n, opcAddrReg, dest, tmp)
  1327. c.freeTemp(tmp)
  1328. proc genDeref(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) =
  1329. if unneededIndirection(n[0]):
  1330. gen(c, n[0], dest, flags)
  1331. if {gfNodeAddr, gfNode} * flags == {} and fitsRegister(n.typ):
  1332. c.gABC(n, opcNodeToReg, dest, dest)
  1333. else:
  1334. let tmp = c.genx(n[0], flags)
  1335. if dest < 0: dest = c.getTemp(n.typ)
  1336. gABC(c, n, opcLdDeref, dest, tmp)
  1337. assert n.typ != nil
  1338. if {gfNodeAddr, gfNode} * flags == {} and fitsRegister(n.typ):
  1339. c.gABC(n, opcNodeToReg, dest, dest)
  1340. c.freeTemp(tmp)
  1341. proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
  1342. let tmp = c.genx(ri)
  1343. assert dest >= 0
  1344. gABC(c, ri, whichAsgnOpc(ri, requiresCopy), dest, tmp)
  1345. c.freeTemp(tmp)
  1346. proc setSlot(c: PCtx; v: PSym) =
  1347. # XXX generate type initialization here?
  1348. if v.position == 0:
  1349. v.position = getFreeRegister(c, if v.kind == skLet: slotFixedLet else: slotFixedVar, start = 1)
  1350. proc cannotEval(c: PCtx; n: PNode) {.noinline.} =
  1351. globalError(c.config, n.info, "cannot evaluate at compile time: " &
  1352. n.renderTree)
  1353. proc isOwnedBy(a, b: PSym): bool =
  1354. var a = a.owner
  1355. while a != nil and a.kind != skModule:
  1356. if a == b: return true
  1357. a = a.owner
  1358. proc getOwner(c: PCtx): PSym =
  1359. result = c.prc.sym
  1360. if result.isNil: result = c.module
  1361. proc importcCondVar*(s: PSym): bool {.inline.} =
  1362. # see also importcCond
  1363. if sfImportc in s.flags:
  1364. return s.kind in {skVar, skLet, skConst}
  1365. proc checkCanEval(c: PCtx; n: PNode) =
  1366. # we need to ensure that we don't evaluate 'x' here:
  1367. # proc foo() = var x ...
  1368. let s = n.sym
  1369. if {sfCompileTime, sfGlobal} <= s.flags: return
  1370. if compiletimeFFI in c.config.features and s.importcCondVar: return
  1371. if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
  1372. not s.isOwnedBy(c.prc.sym) and s.owner != c.module and c.mode != emRepl:
  1373. # little hack ahead for bug #12612: assume gensym'ed variables
  1374. # are in the right scope:
  1375. if sfGenSym in s.flags and c.prc.sym == nil: discard
  1376. else: cannotEval(c, n)
  1377. elif s.kind in {skProc, skFunc, skConverter, skMethod,
  1378. skIterator} and sfForward in s.flags:
  1379. cannotEval(c, n)
  1380. template needsAdditionalCopy(n): untyped =
  1381. not c.isTemp(dest) and not fitsRegister(n.typ)
  1382. proc genAdditionalCopy(c: PCtx; n: PNode; opc: TOpcode;
  1383. dest, idx, value: TRegister) =
  1384. var cc = c.getTemp(n.typ)
  1385. c.gABC(n, whichAsgnOpc(n), cc, value)
  1386. c.gABC(n, opc, dest, idx, cc)
  1387. c.freeTemp(cc)
  1388. proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
  1389. dest, idx, value: TRegister) =
  1390. # opcLdObj et al really means "load address". We sometimes have to create a
  1391. # copy in order to not introduce false aliasing:
  1392. # mylocal = a.b # needs a copy of the data!
  1393. assert n.typ != nil
  1394. if needsAdditionalCopy(n):
  1395. genAdditionalCopy(c, n, opc, dest, idx, value)
  1396. else:
  1397. c.gABC(n, opc, dest, idx, value)
  1398. proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
  1399. case le.kind
  1400. of nkBracketExpr:
  1401. let dest = c.genx(le[0], {gfNode})
  1402. let idx = c.genIndex(le[1], le[0].typ)
  1403. let tmp = c.genx(ri)
  1404. if le[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
  1405. tyString, tyCstring}:
  1406. c.preventFalseAlias(le, opcWrStrIdx, dest, idx, tmp)
  1407. else:
  1408. c.preventFalseAlias(le, opcWrArr, dest, idx, tmp)
  1409. c.freeTemp(tmp)
  1410. c.freeTemp(idx)
  1411. c.freeTemp(dest)
  1412. of nkCheckedFieldExpr:
  1413. var objR: TDest = -1
  1414. genCheckedObjAccessAux(c, le, objR, {gfNode})
  1415. let idx = genField(c, le[0][1])
  1416. let tmp = c.genx(ri)
  1417. c.preventFalseAlias(le[0], opcWrObj, objR, idx, tmp)
  1418. c.freeTemp(tmp)
  1419. # c.freeTemp(idx) # BUGFIX, see nkDotExpr
  1420. c.freeTemp(objR)
  1421. of nkDotExpr:
  1422. let dest = c.genx(le[0], {gfNode})
  1423. let idx = genField(c, le[1])
  1424. let tmp = c.genx(ri)
  1425. c.preventFalseAlias(le, opcWrObj, dest, idx, tmp)
  1426. # c.freeTemp(idx) # BUGFIX: idx is an immediate (field position), not a register
  1427. c.freeTemp(tmp)
  1428. c.freeTemp(dest)
  1429. of nkDerefExpr, nkHiddenDeref:
  1430. let dest = c.genx(le[0], {gfNode})
  1431. let tmp = c.genx(ri)
  1432. c.preventFalseAlias(le, opcWrDeref, dest, 0, tmp)
  1433. c.freeTemp(dest)
  1434. c.freeTemp(tmp)
  1435. of nkSym:
  1436. let s = le.sym
  1437. checkCanEval(c, le)
  1438. if s.isGlobal:
  1439. withTemp(tmp, le.typ):
  1440. c.gen(le, tmp, {gfNodeAddr})
  1441. let val = c.genx(ri)
  1442. c.preventFalseAlias(le, opcWrDeref, tmp, 0, val)
  1443. c.freeTemp(val)
  1444. else:
  1445. if s.kind == skForVar: c.setSlot s
  1446. internalAssert c.config, s.position > 0 or (s.position == 0 and
  1447. s.kind in {skParam, skResult})
  1448. var dest: TRegister = s.position + ord(s.kind == skParam)
  1449. assert le.typ != nil
  1450. if needsAdditionalCopy(le) and s.kind in {skResult, skVar, skParam}:
  1451. var cc = c.getTemp(le.typ)
  1452. gen(c, ri, cc)
  1453. c.gABC(le, whichAsgnOpc(le), dest, cc)
  1454. c.freeTemp(cc)
  1455. else:
  1456. gen(c, ri, dest)
  1457. else:
  1458. let dest = c.genx(le, {gfNodeAddr})
  1459. genAsgn(c, dest, ri, requiresCopy)
  1460. c.freeTemp(dest)
  1461. proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
  1462. var n = newNode(nkType)
  1463. n.typ = t
  1464. genLit(c, n, dest)
  1465. proc importcCond*(c: PCtx; s: PSym): bool {.inline.} =
  1466. ## return true to importc `s`, false to execute its body instead (refs #8405)
  1467. if sfImportc in s.flags:
  1468. if s.kind in routineKinds:
  1469. return getBody(c.graph, s).kind == nkEmpty
  1470. proc importcSym(c: PCtx; info: TLineInfo; s: PSym) =
  1471. when hasFFI:
  1472. if compiletimeFFI in c.config.features:
  1473. c.globals.add(importcSymbol(c.config, s))
  1474. s.position = c.globals.len
  1475. else:
  1476. localError(c.config, info,
  1477. "VM is not allowed to 'importc' without --experimental:compiletimeFFI")
  1478. else:
  1479. localError(c.config, info,
  1480. "cannot 'importc' variable at compile time; " & s.name.s)
  1481. proc getNullValue*(typ: PType, info: TLineInfo; conf: ConfigRef): PNode
  1482. proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
  1483. c.globals.add(getNullValue(s.typ, n.info, c.config))
  1484. s.position = c.globals.len
  1485. # This is rather hard to support, due to the laziness of the VM code
  1486. # generator. See tests/compile/tmacro2 for why this is necessary:
  1487. # var decls{.compileTime.}: seq[NimNode] = @[]
  1488. let dest = c.getTemp(s.typ)
  1489. c.gABx(n, opcLdGlobal, dest, s.position)
  1490. if s.astdef != nil:
  1491. let tmp = c.genx(s.astdef)
  1492. c.genAdditionalCopy(n, opcWrDeref, dest, 0, tmp)
  1493. c.freeTemp(dest)
  1494. c.freeTemp(tmp)
  1495. proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
  1496. # gfNodeAddr and gfNode are mutually exclusive
  1497. assert card(flags * {gfNodeAddr, gfNode}) < 2
  1498. let s = n.sym
  1499. if s.isGlobal:
  1500. let isImportcVar = importcCondVar(s)
  1501. if sfCompileTime in s.flags or c.mode == emRepl or isImportcVar:
  1502. discard
  1503. elif s.position == 0:
  1504. cannotEval(c, n)
  1505. if s.position == 0:
  1506. if importcCond(c, s) or isImportcVar: c.importcSym(n.info, s)
  1507. else: genGlobalInit(c, n, s)
  1508. if dest < 0: dest = c.getTemp(n.typ)
  1509. assert s.typ != nil
  1510. if gfNodeAddr in flags:
  1511. if isImportcVar:
  1512. c.gABx(n, opcLdGlobalAddrDerefFFI, dest, s.position)
  1513. else:
  1514. c.gABx(n, opcLdGlobalAddr, dest, s.position)
  1515. elif isImportcVar:
  1516. c.gABx(n, opcLdGlobalDerefFFI, dest, s.position)
  1517. elif fitsRegister(s.typ) and gfNode notin flags:
  1518. var cc = c.getTemp(n.typ)
  1519. c.gABx(n, opcLdGlobal, cc, s.position)
  1520. c.gABC(n, opcNodeToReg, dest, cc)
  1521. c.freeTemp(cc)
  1522. else:
  1523. c.gABx(n, opcLdGlobal, dest, s.position)
  1524. else:
  1525. if s.kind == skForVar and c.mode == emRepl: c.setSlot(s)
  1526. if s.position > 0 or (s.position == 0 and
  1527. s.kind in {skParam, skResult}):
  1528. if dest < 0:
  1529. dest = s.position + ord(s.kind == skParam)
  1530. internalAssert(c.config, c.prc.regInfo[dest].kind < slotSomeTemp)
  1531. else:
  1532. # we need to generate an assignment:
  1533. let requiresCopy = c.prc.regInfo[dest].kind >= slotSomeTemp and
  1534. gfIsParam notin flags
  1535. genAsgn(c, dest, n, requiresCopy)
  1536. else:
  1537. # see tests/t99bott for an example that triggers it:
  1538. cannotEval(c, n)
  1539. template needsRegLoad(): untyped =
  1540. {gfNode, gfNodeAddr} * flags == {} and
  1541. fitsRegister(n.typ.skipTypes({tyVar, tyLent, tyStatic}))
  1542. proc genArrAccessOpcode(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
  1543. flags: TGenFlags) =
  1544. let a = c.genx(n[0], flags)
  1545. let b = c.genIndex(n[1], n[0].typ)
  1546. if dest < 0: dest = c.getTemp(n.typ)
  1547. if opc in {opcLdArrAddr, opcLdStrIdxAddr} and gfNodeAddr in flags:
  1548. c.gABC(n, opc, dest, a, b)
  1549. elif needsRegLoad():
  1550. var cc = c.getTemp(n.typ)
  1551. c.gABC(n, opc, cc, a, b)
  1552. c.gABC(n, opcNodeToReg, dest, cc)
  1553. c.freeTemp(cc)
  1554. else:
  1555. #message(c.config, n.info, warnUser, "argh")
  1556. #echo "FLAGS ", flags, " ", fitsRegister(n.typ), " ", typeToString(n.typ)
  1557. c.gABC(n, opc, dest, a, b)
  1558. c.freeTemp(a)
  1559. c.freeTemp(b)
  1560. proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
  1561. let a = c.genx(n[0], flags)
  1562. let b = genField(c, n[1])
  1563. if dest < 0: dest = c.getTemp(n.typ)
  1564. if {gfNodeAddr} * flags != {}:
  1565. c.gABC(n, opcLdObjAddr, dest, a, b)
  1566. elif needsRegLoad():
  1567. var cc = c.getTemp(n.typ)
  1568. c.gABC(n, opcLdObj, cc, a, b)
  1569. c.gABC(n, opcNodeToReg, dest, cc)
  1570. c.freeTemp(cc)
  1571. else:
  1572. c.gABC(n, opcLdObj, dest, a, b)
  1573. c.freeTemp(a)
  1574. proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
  1575. internalAssert c.config, n.kind == nkCheckedFieldExpr
  1576. # nkDotExpr to access the requested field
  1577. let accessExpr = n[0]
  1578. # nkCall to check if the discriminant is valid
  1579. var checkExpr = n[1]
  1580. let negCheck = checkExpr[0].sym.magic == mNot
  1581. if negCheck:
  1582. checkExpr = checkExpr[^1]
  1583. # Discriminant symbol
  1584. let disc = checkExpr[2]
  1585. internalAssert c.config, disc.sym.kind == skField
  1586. # Load the object in `dest`
  1587. c.gen(accessExpr[0], dest, flags)
  1588. # Load the discriminant
  1589. var discVal = c.getTemp(disc.typ)
  1590. c.gABC(n, opcLdObj, discVal, dest, genField(c, disc))
  1591. # Check if its value is contained in the supplied set
  1592. let setLit = c.genx(checkExpr[1])
  1593. var rs = c.getTemp(getSysType(c.graph, n.info, tyBool))
  1594. c.gABC(n, opcContainsSet, rs, setLit, discVal)
  1595. c.freeTemp(discVal)
  1596. c.freeTemp(setLit)
  1597. # If the check fails let the user know
  1598. let lab1 = c.xjmp(n, if negCheck: opcFJmp else: opcTJmp, rs)
  1599. c.freeTemp(rs)
  1600. let strType = getSysType(c.graph, n.info, tyString)
  1601. var msgReg: TDest = c.getTemp(strType)
  1602. let fieldName = $accessExpr[1]
  1603. let msg = genFieldDefect(c.config, fieldName, disc.sym)
  1604. let strLit = newStrNode(msg, accessExpr[1].info)
  1605. strLit.typ = strType
  1606. c.genLit(strLit, msgReg)
  1607. c.gABC(n, opcInvalidField, msgReg, discVal)
  1608. c.freeTemp(msgReg)
  1609. c.patch(lab1)
  1610. proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
  1611. var objR: TDest = -1
  1612. genCheckedObjAccessAux(c, n, objR, flags)
  1613. let accessExpr = n[0]
  1614. # Field symbol
  1615. var field = accessExpr[1]
  1616. internalAssert c.config, field.sym.kind == skField
  1617. # Load the content now
  1618. if dest < 0: dest = c.getTemp(n.typ)
  1619. let fieldPos = genField(c, field)
  1620. if {gfNodeAddr} * flags != {}:
  1621. c.gABC(n, opcLdObjAddr, dest, objR, fieldPos)
  1622. elif needsRegLoad():
  1623. var cc = c.getTemp(accessExpr.typ)
  1624. c.gABC(n, opcLdObj, cc, objR, fieldPos)
  1625. c.gABC(n, opcNodeToReg, dest, cc)
  1626. c.freeTemp(cc)
  1627. else:
  1628. c.gABC(n, opcLdObj, dest, objR, fieldPos)
  1629. c.freeTemp(objR)
  1630. proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
  1631. let arrayType = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
  1632. if arrayType in {tyString, tyCstring}:
  1633. let opc = if gfNodeAddr in flags: opcLdStrIdxAddr else: opcLdStrIdx
  1634. genArrAccessOpcode(c, n, dest, opc, flags)
  1635. elif arrayType == tyTypeDesc:
  1636. c.genTypeLit(n.typ, dest)
  1637. else:
  1638. let opc = if gfNodeAddr in flags: opcLdArrAddr else: opcLdArr
  1639. genArrAccessOpcode(c, n, dest, opc, flags)
  1640. proc getNullValueAux(t: PType; obj: PNode, result: PNode; conf: ConfigRef; currPosition: var int) =
  1641. if t != nil and t.len > 0 and t[0] != nil:
  1642. let b = skipTypes(t[0], skipPtrs)
  1643. getNullValueAux(b, b.n, result, conf, currPosition)
  1644. case obj.kind
  1645. of nkRecList:
  1646. for i in 0..<obj.len: getNullValueAux(nil, obj[i], result, conf, currPosition)
  1647. of nkRecCase:
  1648. getNullValueAux(nil, obj[0], result, conf, currPosition)
  1649. for i in 1..<obj.len:
  1650. getNullValueAux(nil, lastSon(obj[i]), result, conf, currPosition)
  1651. of nkSym:
  1652. let field = newNodeI(nkExprColonExpr, result.info)
  1653. field.add(obj)
  1654. field.add(getNullValue(obj.sym.typ, result.info, conf))
  1655. result.add field
  1656. doAssert obj.sym.position == currPosition
  1657. inc currPosition
  1658. else: globalError(conf, result.info, "cannot create null element for: " & $obj)
  1659. proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
  1660. var t = skipTypes(typ, abstractRange+{tyStatic, tyOwned}-{tyTypeDesc})
  1661. case t.kind
  1662. of tyBool, tyEnum, tyChar, tyInt..tyInt64:
  1663. result = newNodeIT(nkIntLit, info, t)
  1664. of tyUInt..tyUInt64:
  1665. result = newNodeIT(nkUIntLit, info, t)
  1666. of tyFloat..tyFloat128:
  1667. result = newNodeIT(nkFloatLit, info, t)
  1668. of tyCstring, tyString:
  1669. result = newNodeIT(nkStrLit, info, t)
  1670. result.strVal = ""
  1671. of tyVar, tyLent, tyPointer, tyPtr, tyUntyped,
  1672. tyTyped, tyTypeDesc, tyRef, tyNil:
  1673. result = newNodeIT(nkNilLit, info, t)
  1674. of tyProc:
  1675. if t.callConv != ccClosure:
  1676. result = newNodeIT(nkNilLit, info, t)
  1677. else:
  1678. result = newNodeIT(nkTupleConstr, info, t)
  1679. result.add(newNodeIT(nkNilLit, info, t))
  1680. result.add(newNodeIT(nkNilLit, info, t))
  1681. of tyObject:
  1682. result = newNodeIT(nkObjConstr, info, t)
  1683. result.add(newNodeIT(nkEmpty, info, t))
  1684. # initialize inherited fields, and all in the correct order:
  1685. var currPosition = 0
  1686. getNullValueAux(t, t.n, result, conf, currPosition)
  1687. of tyArray:
  1688. result = newNodeIT(nkBracket, info, t)
  1689. for i in 0..<toInt(lengthOrd(conf, t)):
  1690. result.add getNullValue(elemType(t), info, conf)
  1691. of tyTuple:
  1692. result = newNodeIT(nkTupleConstr, info, t)
  1693. for i in 0..<t.len:
  1694. result.add getNullValue(t[i], info, conf)
  1695. of tySet:
  1696. result = newNodeIT(nkCurly, info, t)
  1697. of tySequence, tyOpenArray:
  1698. result = newNodeIT(nkBracket, info, t)
  1699. else:
  1700. globalError(conf, info, "cannot create null element for: " & $t.kind)
  1701. result = newNodeI(nkEmpty, info)
  1702. proc genVarSection(c: PCtx; n: PNode) =
  1703. for a in n:
  1704. if a.kind == nkCommentStmt: continue
  1705. #assert(a[0].kind == nkSym) can happen for transformed vars
  1706. if a.kind == nkVarTuple:
  1707. for i in 0..<a.len-2:
  1708. if a[i].kind == nkSym:
  1709. if not a[i].sym.isGlobal: setSlot(c, a[i].sym)
  1710. checkCanEval(c, a[i])
  1711. c.gen(lowerTupleUnpacking(c.graph, a, c.idgen, c.getOwner))
  1712. elif a[0].kind == nkSym:
  1713. let s = a[0].sym
  1714. checkCanEval(c, a[0])
  1715. if s.isGlobal:
  1716. if s.position == 0:
  1717. if importcCond(c, s): c.importcSym(a.info, s)
  1718. else:
  1719. let sa = getNullValue(s.typ, a.info, c.config)
  1720. #if s.ast.isNil: getNullValue(s.typ, a.info)
  1721. #else: s.ast
  1722. assert sa.kind != nkCall
  1723. c.globals.add(sa)
  1724. s.position = c.globals.len
  1725. if a[2].kind != nkEmpty:
  1726. let tmp = c.genx(a[0], {gfNodeAddr})
  1727. let val = c.genx(a[2])
  1728. c.genAdditionalCopy(a[2], opcWrDeref, tmp, 0, val)
  1729. c.freeTemp(val)
  1730. c.freeTemp(tmp)
  1731. else:
  1732. setSlot(c, s)
  1733. if a[2].kind == nkEmpty:
  1734. c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ))
  1735. else:
  1736. assert s.typ != nil
  1737. if not fitsRegister(s.typ):
  1738. c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ))
  1739. let le = a[0]
  1740. assert le.typ != nil
  1741. if not fitsRegister(le.typ) and s.kind in {skResult, skVar, skParam}:
  1742. var cc = c.getTemp(le.typ)
  1743. gen(c, a[2], cc)
  1744. c.gABC(le, whichAsgnOpc(le), s.position.TRegister, cc)
  1745. c.freeTemp(cc)
  1746. else:
  1747. gen(c, a[2], s.position.TRegister)
  1748. else:
  1749. # assign to a[0]; happens for closures
  1750. if a[2].kind == nkEmpty:
  1751. let tmp = genx(c, a[0])
  1752. c.gABx(a, ldNullOpcode(a[0].typ), tmp, c.genType(a[0].typ))
  1753. c.freeTemp(tmp)
  1754. else:
  1755. genAsgn(c, a[0], a[2], true)
  1756. proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
  1757. if dest < 0: dest = c.getTemp(n.typ)
  1758. c.gABx(n, opcLdNull, dest, c.genType(n.typ))
  1759. let intType = getSysType(c.graph, n.info, tyInt)
  1760. let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
  1761. if seqType.kind == tySequence:
  1762. var tmp = c.getTemp(intType)
  1763. c.gABx(n, opcLdImmInt, tmp, n.len)
  1764. c.gABx(n, opcNewSeq, dest, c.genType(seqType))
  1765. c.gABx(n, opcNewSeq, tmp, 0)
  1766. c.freeTemp(tmp)
  1767. if n.len > 0:
  1768. var tmp = getTemp(c, intType)
  1769. c.gABx(n, opcLdNullReg, tmp, c.genType(intType))
  1770. for x in n:
  1771. let a = c.genx(x)
  1772. c.preventFalseAlias(n, opcWrArr, dest, tmp, a)
  1773. c.gABI(n, opcAddImmInt, tmp, tmp, 1)
  1774. c.freeTemp(a)
  1775. c.freeTemp(tmp)
  1776. proc genSetConstr(c: PCtx, n: PNode, dest: var TDest) =
  1777. if dest < 0: dest = c.getTemp(n.typ)
  1778. c.gABx(n, opcLdNull, dest, c.genType(n.typ))
  1779. for x in n:
  1780. if x.kind == nkRange:
  1781. let a = c.genx(x[0])
  1782. let b = c.genx(x[1])
  1783. c.gABC(n, opcInclRange, dest, a, b)
  1784. c.freeTemp(b)
  1785. c.freeTemp(a)
  1786. else:
  1787. let a = c.genx(x)
  1788. c.gABC(n, opcIncl, dest, a)
  1789. c.freeTemp(a)
  1790. proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) =
  1791. if dest < 0: dest = c.getTemp(n.typ)
  1792. let t = n.typ.skipTypes(abstractRange+{tyOwned}-{tyTypeDesc})
  1793. if t.kind == tyRef:
  1794. c.gABx(n, opcNew, dest, c.genType(t[0]))
  1795. else:
  1796. c.gABx(n, opcLdNull, dest, c.genType(n.typ))
  1797. for i in 1..<n.len:
  1798. let it = n[i]
  1799. if it.kind == nkExprColonExpr and it[0].kind == nkSym:
  1800. let idx = genField(c, it[0])
  1801. let tmp = c.genx(it[1])
  1802. c.preventFalseAlias(it[1], opcWrObj,
  1803. dest, idx, tmp)
  1804. c.freeTemp(tmp)
  1805. else:
  1806. globalError(c.config, n.info, "invalid object constructor")
  1807. proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
  1808. if dest < 0: dest = c.getTemp(n.typ)
  1809. if n.typ.kind != tyTypeDesc:
  1810. c.gABx(n, opcLdNull, dest, c.genType(n.typ))
  1811. # XXX x = (x.old, 22) produces wrong code ... stupid self assignments
  1812. for i in 0..<n.len:
  1813. let it = n[i]
  1814. if it.kind == nkExprColonExpr:
  1815. let idx = genField(c, it[0])
  1816. let tmp = c.genx(it[1])
  1817. c.preventFalseAlias(it[1], opcWrObj,
  1818. dest, idx, tmp)
  1819. c.freeTemp(tmp)
  1820. else:
  1821. let tmp = c.genx(it)
  1822. c.preventFalseAlias(it, opcWrObj, dest, i.TRegister, tmp)
  1823. c.freeTemp(tmp)
  1824. proc genProc*(c: PCtx; s: PSym): int
  1825. proc matches(s: PSym; x: string): bool =
  1826. let y = x.split('.')
  1827. var s = s
  1828. for i in 1..y.len:
  1829. if s == nil or (y[^i].cmpIgnoreStyle(s.name.s) != 0 and y[^i] != "*"):
  1830. return false
  1831. s = if sfFromGeneric in s.flags: s.owner.owner else: s.owner
  1832. while s != nil and s.kind == skPackage and s.owner != nil: s = s.owner
  1833. result = true
  1834. proc procIsCallback(c: PCtx; s: PSym): bool =
  1835. if s.offset < -1: return true
  1836. var i = -2
  1837. for key, value in items(c.callbacks):
  1838. if s.matches(key):
  1839. doAssert s.offset == -1
  1840. s.offset = i
  1841. return true
  1842. dec i
  1843. proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
  1844. when defined(nimCompilerStacktraceHints):
  1845. setFrameMsg c.config$n.info & " " & $n.kind & " " & $flags
  1846. case n.kind
  1847. of nkSym:
  1848. let s = n.sym
  1849. checkCanEval(c, n)
  1850. case s.kind
  1851. of skVar, skForVar, skTemp, skLet, skParam, skResult:
  1852. genRdVar(c, n, dest, flags)
  1853. of skProc, skFunc, skConverter, skMacro, skTemplate, skMethod, skIterator:
  1854. # 'skTemplate' is only allowed for 'getAst' support:
  1855. if s.kind == skIterator and s.typ.callConv == TCallingConvention.ccClosure:
  1856. globalError(c.config, n.info, "Closure iterators are not supported by VM!")
  1857. if procIsCallback(c, s): discard
  1858. elif importcCond(c, s): c.importcSym(n.info, s)
  1859. genLit(c, n, dest)
  1860. of skConst:
  1861. let constVal = if s.ast != nil: s.ast else: s.typ.n
  1862. gen(c, constVal, dest)
  1863. of skEnumField:
  1864. # we never reach this case - as of the time of this comment,
  1865. # skEnumField is folded to an int in semfold.nim, but this code
  1866. # remains for robustness
  1867. if dest < 0: dest = c.getTemp(n.typ)
  1868. if s.position >= low(int16) and s.position <= high(int16):
  1869. c.gABx(n, opcLdImmInt, dest, s.position)
  1870. else:
  1871. var lit = genLiteral(c, newIntNode(nkIntLit, s.position))
  1872. c.gABx(n, opcLdConst, dest, lit)
  1873. of skType:
  1874. genTypeLit(c, s.typ, dest)
  1875. of skGenericParam:
  1876. if c.prc.sym != nil and c.prc.sym.kind == skMacro:
  1877. genRdVar(c, n, dest, flags)
  1878. else:
  1879. globalError(c.config, n.info, "cannot generate code for: " & s.name.s)
  1880. else:
  1881. globalError(c.config, n.info, "cannot generate code for: " & s.name.s)
  1882. of nkCallKinds:
  1883. if n[0].kind == nkSym:
  1884. let s = n[0].sym
  1885. if s.magic != mNone:
  1886. genMagic(c, n, dest, s.magic)
  1887. elif s.kind == skMethod:
  1888. localError(c.config, n.info, "cannot call method " & s.name.s &
  1889. " at compile time")
  1890. elif matches(s, "stdlib.marshal.to"):
  1891. # XXX marshal load&store should not be opcodes, but use the
  1892. # general callback mechanisms.
  1893. genMarshalLoad(c, n, dest)
  1894. elif matches(s, "stdlib.marshal.$$"):
  1895. genMarshalStore(c, n, dest)
  1896. else:
  1897. genCall(c, n, dest)
  1898. clearDest(c, n, dest)
  1899. else:
  1900. genCall(c, n, dest)
  1901. clearDest(c, n, dest)
  1902. of nkCharLit..nkInt64Lit:
  1903. if isInt16Lit(n):
  1904. if dest < 0: dest = c.getTemp(n.typ)
  1905. c.gABx(n, opcLdImmInt, dest, n.intVal.int)
  1906. else:
  1907. genLit(c, n, dest)
  1908. of nkUIntLit..pred(nkNilLit): genLit(c, n, dest)
  1909. of nkNilLit:
  1910. if not n.typ.isEmptyType: genLit(c, getNullValue(n.typ, n.info, c.config), dest)
  1911. else: unused(c, n, dest)
  1912. of nkAsgn, nkFastAsgn:
  1913. unused(c, n, dest)
  1914. genAsgn(c, n[0], n[1], n.kind == nkAsgn)
  1915. of nkDotExpr: genObjAccess(c, n, dest, flags)
  1916. of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags)
  1917. of nkBracketExpr: genArrAccess(c, n, dest, flags)
  1918. of nkDerefExpr, nkHiddenDeref: genDeref(c, n, dest, flags)
  1919. of nkAddr, nkHiddenAddr: genAddr(c, n, dest, flags)
  1920. of nkIfStmt, nkIfExpr: genIf(c, n, dest)
  1921. of nkWhenStmt:
  1922. # This is "when nimvm" node. Chose the first branch.
  1923. gen(c, n[0][1], dest)
  1924. of nkCaseStmt: genCase(c, n, dest)
  1925. of nkWhileStmt:
  1926. unused(c, n, dest)
  1927. genWhile(c, n)
  1928. of nkBlockExpr, nkBlockStmt: genBlock(c, n, dest)
  1929. of nkReturnStmt:
  1930. genReturn(c, n)
  1931. of nkRaiseStmt:
  1932. genRaise(c, n)
  1933. of nkBreakStmt:
  1934. genBreak(c, n)
  1935. of nkTryStmt, nkHiddenTryStmt: genTry(c, n, dest)
  1936. of nkStmtList:
  1937. #unused(c, n, dest)
  1938. # XXX Fix this bug properly, lexim triggers it
  1939. for x in n: gen(c, x)
  1940. of nkStmtListExpr:
  1941. for i in 0..<n.len-1: gen(c, n[i])
  1942. gen(c, n[^1], dest, flags)
  1943. of nkPragmaBlock:
  1944. gen(c, n.lastSon, dest, flags)
  1945. of nkDiscardStmt:
  1946. unused(c, n, dest)
  1947. gen(c, n[0])
  1948. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  1949. genConv(c, n, n[1], dest)
  1950. of nkObjDownConv:
  1951. genConv(c, n, n[0], dest)
  1952. of nkObjUpConv:
  1953. genConv(c, n, n[0], dest)
  1954. of nkVarSection, nkLetSection:
  1955. unused(c, n, dest)
  1956. genVarSection(c, n)
  1957. of declarativeDefs, nkMacroDef:
  1958. unused(c, n, dest)
  1959. of nkLambdaKinds:
  1960. #let s = n[namePos].sym
  1961. #discard genProc(c, s)
  1962. genLit(c, newSymNode(n[namePos].sym), dest)
  1963. of nkChckRangeF, nkChckRange64, nkChckRange:
  1964. let
  1965. tmp0 = c.genx(n[0])
  1966. tmp1 = c.genx(n[1])
  1967. tmp2 = c.genx(n[2])
  1968. c.gABC(n, opcRangeChck, tmp0, tmp1, tmp2)
  1969. c.freeTemp(tmp1)
  1970. c.freeTemp(tmp2)
  1971. if dest >= 0:
  1972. gABC(c, n, whichAsgnOpc(n), dest, tmp0)
  1973. c.freeTemp(tmp0)
  1974. else:
  1975. dest = tmp0
  1976. of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
  1977. nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt,
  1978. nkMixinStmt, nkBindStmt:
  1979. unused(c, n, dest)
  1980. of nkStringToCString, nkCStringToString:
  1981. gen(c, n[0], dest)
  1982. of nkBracket: genArrayConstr(c, n, dest)
  1983. of nkCurly: genSetConstr(c, n, dest)
  1984. of nkObjConstr: genObjConstr(c, n, dest)
  1985. of nkPar, nkClosure, nkTupleConstr: genTupleConstr(c, n, dest)
  1986. of nkCast:
  1987. if allowCast in c.features:
  1988. genConv(c, n, n[1], dest, opcCast)
  1989. else:
  1990. genCastIntFloat(c, n, dest)
  1991. of nkTypeOfExpr:
  1992. genTypeLit(c, n.typ, dest)
  1993. of nkComesFrom:
  1994. discard "XXX to implement for better stack traces"
  1995. else:
  1996. if n.typ != nil and n.typ.isCompileTimeOnly:
  1997. genTypeLit(c, n.typ, dest)
  1998. else:
  1999. globalError(c.config, n.info, "cannot generate VM code for " & $n)
  2000. proc removeLastEof(c: PCtx) =
  2001. let last = c.code.len-1
  2002. if last >= 0 and c.code[last].opcode == opcEof:
  2003. # overwrite last EOF:
  2004. assert c.code.len == c.debug.len
  2005. c.code.setLen(last)
  2006. c.debug.setLen(last)
  2007. proc genStmt*(c: PCtx; n: PNode): int =
  2008. c.removeLastEof
  2009. result = c.code.len
  2010. var d: TDest = -1
  2011. c.gen(n, d)
  2012. c.gABC(n, opcEof)
  2013. if d >= 0:
  2014. globalError(c.config, n.info, "VM problem: dest register is set")
  2015. proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int =
  2016. c.removeLastEof
  2017. result = c.code.len
  2018. var d: TDest = -1
  2019. c.gen(n, d)
  2020. if d < 0:
  2021. if requiresValue:
  2022. globalError(c.config, n.info, "VM problem: dest register is not set")
  2023. d = 0
  2024. c.gABC(n, opcEof, d)
  2025. #echo renderTree(n)
  2026. #c.echoCode(result)
  2027. proc genParams(c: PCtx; params: PNode) =
  2028. # res.sym.position is already 0
  2029. setLen(c.prc.regInfo, max(params.len, 1))
  2030. c.prc.regInfo[0] = (inUse: true, kind: slotFixedVar)
  2031. for i in 1..<params.len:
  2032. c.prc.regInfo[i] = (inUse: true, kind: slotFixedLet)
  2033. proc finalJumpTarget(c: PCtx; pc, diff: int) =
  2034. internalAssert(c.config, regBxMin < diff and diff < regBxMax)
  2035. let oldInstr = c.code[pc]
  2036. # opcode and regA stay the same:
  2037. c.code[pc] = ((oldInstr.TInstrType and ((regOMask shl regOShift) or (regAMask shl regAShift))).TInstrType or
  2038. TInstrType(diff+wordExcess) shl regBxShift).TInstr
  2039. proc genGenericParams(c: PCtx; gp: PNode) =
  2040. var base = c.prc.regInfo.len
  2041. setLen c.prc.regInfo, base + gp.len
  2042. for i in 0..<gp.len:
  2043. var param = gp[i].sym
  2044. param.position = base + i # XXX: fix this earlier; make it consistent with templates
  2045. c.prc.regInfo[base + i] = (inUse: true, kind: slotFixedLet)
  2046. proc optimizeJumps(c: PCtx; start: int) =
  2047. const maxIterations = 10
  2048. for i in start..<c.code.len:
  2049. let opc = c.code[i].opcode
  2050. case opc
  2051. of opcTJmp, opcFJmp:
  2052. var reg = c.code[i].regA
  2053. var d = i + c.code[i].jmpDiff
  2054. for iters in countdown(maxIterations, 0):
  2055. case c.code[d].opcode
  2056. of opcJmp:
  2057. d += c.code[d].jmpDiff
  2058. of opcTJmp, opcFJmp:
  2059. if c.code[d].regA != reg: break
  2060. # tjmp x, 23
  2061. # ...
  2062. # tjmp x, 12
  2063. # -- we know 'x' is true, and so can jump to 12+13:
  2064. if c.code[d].opcode == opc:
  2065. d += c.code[d].jmpDiff
  2066. else:
  2067. # tjmp x, 23
  2068. # fjmp x, 22
  2069. # We know 'x' is true so skip to the next instruction:
  2070. d += 1
  2071. else: break
  2072. if d != i + c.code[i].jmpDiff:
  2073. c.finalJumpTarget(i, d - i)
  2074. of opcJmp, opcJmpBack:
  2075. var d = i + c.code[i].jmpDiff
  2076. var iters = maxIterations
  2077. while c.code[d].opcode == opcJmp and iters > 0:
  2078. d += c.code[d].jmpDiff
  2079. dec iters
  2080. if c.code[d].opcode == opcRet:
  2081. # optimize 'jmp to ret' to 'ret' here
  2082. c.code[i] = c.code[d]
  2083. elif d != i + c.code[i].jmpDiff:
  2084. c.finalJumpTarget(i, d - i)
  2085. else: discard
  2086. proc genProc(c: PCtx; s: PSym): int =
  2087. let
  2088. pos = c.procToCodePos.getOrDefault(s.id)
  2089. wasNotGenProcBefore = pos == 0
  2090. noRegistersAllocated = s.offset == -1
  2091. if wasNotGenProcBefore or noRegistersAllocated:
  2092. # xxx: the noRegisterAllocated check is required in order to avoid issues
  2093. # where nimsuggest can crash due as a macro with pos will be loaded
  2094. # but it doesn't have offsets for register allocations see:
  2095. # https://github.com/nim-lang/Nim/issues/18385
  2096. # Improvements and further use of IC should remove the need for this.
  2097. #if s.name.s == "outterMacro" or s.name.s == "innerProc":
  2098. # echo "GENERATING CODE FOR ", s.name.s
  2099. let last = c.code.len-1
  2100. var eofInstr: TInstr
  2101. if last >= 0 and c.code[last].opcode == opcEof:
  2102. eofInstr = c.code[last]
  2103. c.code.setLen(last)
  2104. c.debug.setLen(last)
  2105. #c.removeLastEof
  2106. result = c.code.len+1 # skip the jump instruction
  2107. c.procToCodePos[s.id] = result
  2108. # thanks to the jmp we can add top level statements easily and also nest
  2109. # procs easily:
  2110. let body = transformBody(c.graph, c.idgen, s, cache = not isCompileTimeProc(s))
  2111. let procStart = c.xjmp(body, opcJmp, 0)
  2112. var p = PProc(blocks: @[], sym: s)
  2113. let oldPrc = c.prc
  2114. c.prc = p
  2115. # iterate over the parameters and allocate space for them:
  2116. genParams(c, s.typ.n)
  2117. # allocate additional space for any generically bound parameters
  2118. if s.kind == skMacro and s.isGenericRoutineStrict:
  2119. genGenericParams(c, s.ast[genericParamsPos])
  2120. if tfCapturesEnv in s.typ.flags:
  2121. #let env = s.ast[paramsPos].lastSon.sym
  2122. #assert env.position == 2
  2123. c.prc.regInfo.add (inUse: true, kind: slotFixedLet)
  2124. gen(c, body)
  2125. # generate final 'return' statement:
  2126. c.gABC(body, opcRet)
  2127. c.patch(procStart)
  2128. c.gABC(body, opcEof, eofInstr.regA)
  2129. c.optimizeJumps(result)
  2130. s.offset = c.prc.regInfo.len
  2131. #if s.name.s == "main" or s.name.s == "[]":
  2132. # echo renderTree(body)
  2133. # c.echoCode(result)
  2134. c.prc = oldPrc
  2135. else:
  2136. c.prc.regInfo.setLen s.offset
  2137. result = pos