vmgen.nim 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998
  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
  28. strutils, ast, astalgo, types, msgs, renderer, vmdef,
  29. trees, intsets, rodread, magicsys, options, lowerings
  30. from os import splitFile
  31. when hasFFI:
  32. import evalffi
  33. type
  34. TGenFlag = enum gfAddrOf, gfFieldAccess
  35. TGenFlags = set[TGenFlag]
  36. proc debugInfo(info: TLineInfo): string =
  37. result = info.toFilename.splitFile.name & ":" & $info.line
  38. proc codeListing(c: PCtx, result: var string, start=0; last = -1) =
  39. # first iteration: compute all necessary labels:
  40. var jumpTargets = initIntSet()
  41. let last = if last < 0: c.code.len-1 else: min(last, c.code.len-1)
  42. for i in start..last:
  43. let x = c.code[i]
  44. if x.opcode in relativeJumps:
  45. jumpTargets.incl(i+x.regBx-wordExcess)
  46. # for debugging purposes
  47. var i = start
  48. while i <= last:
  49. if i in jumpTargets: result.addf("L$1:\n", i)
  50. let x = c.code[i]
  51. result.add($i)
  52. let opc = opcode(x)
  53. if opc in {opcConv, opcCast}:
  54. let y = c.code[i+1]
  55. let z = c.code[i+2]
  56. result.addf("\t$#\tr$#, r$#, $#, $#", ($opc).substr(3), x.regA, x.regB,
  57. c.types[y.regBx-wordExcess].typeToString,
  58. c.types[z.regBx-wordExcess].typeToString)
  59. inc i, 2
  60. elif opc < firstABxInstr:
  61. result.addf("\t$#\tr$#, r$#, r$#", ($opc).substr(3), x.regA,
  62. x.regB, x.regC)
  63. elif opc in relativeJumps:
  64. result.addf("\t$#\tr$#, L$#", ($opc).substr(3), x.regA,
  65. i+x.regBx-wordExcess)
  66. elif opc in {opcLdConst, opcAsgnConst}:
  67. let idx = x.regBx-wordExcess
  68. result.addf("\t$#\tr$#, $# ($#)", ($opc).substr(3), x.regA,
  69. c.constants[idx].renderTree, $idx)
  70. elif opc in {opcMarshalLoad, opcMarshalStore}:
  71. let y = c.code[i+1]
  72. result.addf("\t$#\tr$#, r$#, $#", ($opc).substr(3), x.regA, x.regB,
  73. c.types[y.regBx-wordExcess].typeToString)
  74. inc i
  75. else:
  76. result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA, x.regBx-wordExcess)
  77. result.add("\t#")
  78. result.add(debugInfo(c.debug[i]))
  79. result.add("\n")
  80. inc i
  81. proc echoCode*(c: PCtx; start=0; last = -1) {.deprecated.} =
  82. var buf = ""
  83. codeListing(c, buf, start, last)
  84. echo buf
  85. proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) =
  86. ## Takes the registers `b` and `c`, applies the operation `opc` to them, and
  87. ## stores the result into register `a`
  88. ## The node is needed for debug information
  89. assert opc.ord < 255
  90. let ins = (opc.uint32 or (a.uint32 shl 8'u32) or
  91. (b.uint32 shl 16'u32) or
  92. (c.uint32 shl 24'u32)).TInstr
  93. when false:
  94. if ctx.code.len == 43:
  95. writeStackTrace()
  96. echo "generating ", opc
  97. ctx.code.add(ins)
  98. ctx.debug.add(n.info)
  99. proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
  100. # Takes the `b` register and the immediate `imm`, appies the operation `opc`,
  101. # and stores the output value into `a`.
  102. # `imm` is signed and must be within [-128, 127]
  103. if imm >= -128 and imm <= 127:
  104. let ins = (opc.uint32 or (a.uint32 shl 8'u32) or
  105. (b.uint32 shl 16'u32) or
  106. (imm+byteExcess).uint32 shl 24'u32).TInstr
  107. c.code.add(ins)
  108. c.debug.add(n.info)
  109. else:
  110. localError(n.info, errGenerated,
  111. "VM: immediate value does not fit into an int8")
  112. proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
  113. # Applies `opc` to `bx` and stores it into register `a`
  114. # `bx` must be signed and in the range [-32768, 32767]
  115. when false:
  116. if c.code.len == 43:
  117. writeStackTrace()
  118. echo "generating ", opc
  119. if bx >= -32768 and bx <= 32767:
  120. let ins = (opc.uint32 or a.uint32 shl 8'u32 or
  121. (bx+wordExcess).uint32 shl 16'u32).TInstr
  122. c.code.add(ins)
  123. c.debug.add(n.info)
  124. else:
  125. localError(n.info, errGenerated,
  126. "VM: immediate value does not fit into an int16")
  127. proc xjmp(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0): TPosition =
  128. #assert opc in {opcJmp, opcFJmp, opcTJmp}
  129. result = TPosition(c.code.len)
  130. gABx(c, n, opc, a, 0)
  131. proc genLabel(c: PCtx): TPosition =
  132. result = TPosition(c.code.len)
  133. #c.jumpTargets.incl(c.code.len)
  134. proc jmpBack(c: PCtx, n: PNode, p = TPosition(0)) =
  135. let dist = p.int - c.code.len
  136. internalAssert(-0x7fff < dist and dist < 0x7fff)
  137. gABx(c, n, opcJmpBack, 0, dist)
  138. proc patch(c: PCtx, p: TPosition) =
  139. # patch with current index
  140. let p = p.int
  141. let diff = c.code.len - p
  142. #c.jumpTargets.incl(c.code.len)
  143. internalAssert(-0x7fff < diff and diff < 0x7fff)
  144. let oldInstr = c.code[p]
  145. # opcode and regA stay the same:
  146. c.code[p] = ((oldInstr.uint32 and 0xffff'u32).uint32 or
  147. uint32(diff+wordExcess) shl 16'u32).TInstr
  148. proc getSlotKind(t: PType): TSlotKind =
  149. case t.skipTypes(abstractRange-{tyTypeDesc}).kind
  150. of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64:
  151. slotTempInt
  152. of tyString, tyCString:
  153. slotTempStr
  154. of tyFloat..tyFloat128:
  155. slotTempFloat
  156. else:
  157. slotTempComplex
  158. const
  159. HighRegisterPressure = 40
  160. proc bestEffort(c: PCtx): TLineInfo =
  161. (if c.prc == nil: c.module.info else: c.prc.sym.info)
  162. proc getTemp(cc: PCtx; tt: PType): TRegister =
  163. let typ = tt.skipTypesOrNil({tyStatic})
  164. let c = cc.prc
  165. # we prefer the same slot kind here for efficiency. Unfortunately for
  166. # discardable return types we may not know the desired type. This can happen
  167. # for e.g. mNAdd[Multiple]:
  168. let k = if typ.isNil: slotTempComplex else: typ.getSlotKind
  169. for i in 0 .. c.maxSlots-1:
  170. if c.slots[i].kind == k and not c.slots[i].inUse:
  171. c.slots[i].inUse = true
  172. return TRegister(i)
  173. # if register pressure is high, we re-use more aggressively:
  174. if c.maxSlots >= HighRegisterPressure and false:
  175. for i in 0 .. c.maxSlots-1:
  176. if not c.slots[i].inUse:
  177. c.slots[i] = (inUse: true, kind: k)
  178. return TRegister(i)
  179. if c.maxSlots >= high(TRegister):
  180. globalError(cc.bestEffort, "VM problem: too many registers required")
  181. result = TRegister(c.maxSlots)
  182. c.slots[c.maxSlots] = (inUse: true, kind: k)
  183. inc c.maxSlots
  184. proc freeTemp(c: PCtx; r: TRegister) =
  185. let c = c.prc
  186. if c.slots[r].kind in {slotSomeTemp..slotTempComplex}: c.slots[r].inUse = false
  187. proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister =
  188. # if register pressure is high, we re-use more aggressively:
  189. let c = cc.prc
  190. if c.maxSlots >= HighRegisterPressure or c.maxSlots+n >= high(TRegister):
  191. for i in 0 .. c.maxSlots-n:
  192. if not c.slots[i].inUse:
  193. block search:
  194. for j in i+1 .. i+n-1:
  195. if c.slots[j].inUse: break search
  196. result = TRegister(i)
  197. for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
  198. return
  199. if c.maxSlots+n >= high(TRegister):
  200. globalError(cc.bestEffort, "VM problem: too many registers required")
  201. result = TRegister(c.maxSlots)
  202. inc c.maxSlots, n
  203. for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
  204. proc freeTempRange(c: PCtx; start: TRegister, n: int) =
  205. for i in start .. start+n-1: c.freeTemp(TRegister(i))
  206. template withTemp(tmp, typ, body: untyped) {.dirty.} =
  207. var tmp = getTemp(c, typ)
  208. body
  209. c.freeTemp(tmp)
  210. proc popBlock(c: PCtx; oldLen: int) =
  211. for f in c.prc.blocks[oldLen].fixups:
  212. c.patch(f)
  213. c.prc.blocks.setLen(oldLen)
  214. template withBlock(labl: PSym; body: untyped) {.dirty.} =
  215. var oldLen {.gensym.} = c.prc.blocks.len
  216. c.prc.blocks.add TBlock(label: labl, fixups: @[])
  217. body
  218. popBlock(c, oldLen)
  219. proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {})
  220. proc gen(c: PCtx; n: PNode; dest: TRegister; flags: TGenFlags = {}) =
  221. var d: TDest = dest
  222. gen(c, n, d, flags)
  223. internalAssert d == dest
  224. proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) =
  225. var tmp: TDest = -1
  226. gen(c, n, tmp, flags)
  227. #if n.typ.isEmptyType: InternalAssert tmp < 0
  228. proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
  229. var tmp: TDest = -1
  230. gen(c, n, tmp, flags)
  231. #internalAssert tmp >= 0 # 'nim check' does not like this internalAssert.
  232. if tmp >= 0:
  233. result = TRegister(tmp)
  234. proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} =
  235. # stmt is different from 'void' in meta programming contexts.
  236. # So we only set dest to -1 if 'void':
  237. if dest >= 0 and (n.typ.isNil or n.typ.kind == tyVoid):
  238. c.freeTemp(dest)
  239. dest = -1
  240. proc isNotOpr(n: PNode): bool =
  241. n.kind in nkCallKinds and n.sons[0].kind == nkSym and
  242. n.sons[0].sym.magic == mNot
  243. proc isTrue(n: PNode): bool =
  244. n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
  245. n.kind == nkIntLit and n.intVal != 0
  246. proc genWhile(c: PCtx; n: PNode) =
  247. # L1:
  248. # cond, tmp
  249. # fjmp tmp, L2
  250. # body
  251. # jmp L1
  252. # L2:
  253. let L1 = c.genLabel
  254. withBlock(nil):
  255. if isTrue(n.sons[0]):
  256. c.gen(n.sons[1])
  257. c.jmpBack(n, L1)
  258. elif isNotOpr(n.sons[0]):
  259. var tmp = c.genx(n.sons[0].sons[1])
  260. let L2 = c.xjmp(n, opcTJmp, tmp)
  261. c.freeTemp(tmp)
  262. c.gen(n.sons[1])
  263. c.jmpBack(n, L1)
  264. c.patch(L2)
  265. else:
  266. var tmp = c.genx(n.sons[0])
  267. let L2 = c.xjmp(n, opcFJmp, tmp)
  268. c.freeTemp(tmp)
  269. c.gen(n.sons[1])
  270. c.jmpBack(n, L1)
  271. c.patch(L2)
  272. proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
  273. withBlock(n.sons[0].sym):
  274. c.gen(n.sons[1], dest)
  275. c.clearDest(n, dest)
  276. proc genBreak(c: PCtx; n: PNode) =
  277. let L1 = c.xjmp(n, opcJmp)
  278. if n.sons[0].kind == nkSym:
  279. #echo cast[int](n.sons[0].sym)
  280. for i in countdown(c.prc.blocks.len-1, 0):
  281. if c.prc.blocks[i].label == n.sons[0].sym:
  282. c.prc.blocks[i].fixups.add L1
  283. return
  284. globalError(n.info, errGenerated, "VM problem: cannot find 'break' target")
  285. else:
  286. c.prc.blocks[c.prc.blocks.high].fixups.add L1
  287. proc genIf(c: PCtx, n: PNode; dest: var TDest) =
  288. # if (!expr1) goto L1;
  289. # thenPart
  290. # goto LEnd
  291. # L1:
  292. # if (!expr2) goto L2;
  293. # thenPart2
  294. # goto LEnd
  295. # L2:
  296. # elsePart
  297. # Lend:
  298. if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
  299. var endings: seq[TPosition] = @[]
  300. for i in countup(0, len(n) - 1):
  301. var it = n.sons[i]
  302. if it.len == 2:
  303. withTemp(tmp, it.sons[0].typ):
  304. var elsePos: TPosition
  305. if isNotOpr(it.sons[0]):
  306. c.gen(it.sons[0].sons[1], tmp)
  307. elsePos = c.xjmp(it.sons[0].sons[1], opcTJmp, tmp) # if true
  308. else:
  309. c.gen(it.sons[0], tmp)
  310. elsePos = c.xjmp(it.sons[0], opcFJmp, tmp) # if false
  311. c.clearDest(n, dest)
  312. c.gen(it.sons[1], dest) # then part
  313. if i < sonsLen(n)-1:
  314. endings.add(c.xjmp(it.sons[1], opcJmp, 0))
  315. c.patch(elsePos)
  316. else:
  317. c.clearDest(n, dest)
  318. c.gen(it.sons[0], dest)
  319. for endPos in endings: c.patch(endPos)
  320. c.clearDest(n, dest)
  321. proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
  322. # asgn dest, a
  323. # tjmp|fjmp L1
  324. # asgn dest, b
  325. # L1:
  326. if dest < 0: dest = getTemp(c, n.typ)
  327. c.gen(n.sons[1], dest)
  328. let L1 = c.xjmp(n, opc, dest)
  329. c.gen(n.sons[2], dest)
  330. c.patch(L1)
  331. proc canonValue*(n: PNode): PNode =
  332. result = n
  333. proc rawGenLiteral(c: PCtx; n: PNode): int =
  334. result = c.constants.len
  335. #assert(n.kind != nkCall)
  336. n.flags.incl nfAllConst
  337. c.constants.add n.canonValue
  338. internalAssert result < 0x7fff
  339. proc sameConstant*(a, b: PNode): bool =
  340. result = false
  341. if a == b:
  342. result = true
  343. elif a != nil and b != nil and a.kind == b.kind:
  344. case a.kind
  345. of nkSym: result = a.sym == b.sym
  346. of nkIdent: result = a.ident.id == b.ident.id
  347. of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
  348. of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
  349. of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
  350. of nkType, nkNilLit: result = a.typ == b.typ
  351. of nkEmpty: result = true
  352. else:
  353. if sonsLen(a) == sonsLen(b):
  354. for i in countup(0, sonsLen(a) - 1):
  355. if not sameConstant(a.sons[i], b.sons[i]): return
  356. result = true
  357. proc genLiteral(c: PCtx; n: PNode): int =
  358. # types do not matter here:
  359. for i in 0 .. <c.constants.len:
  360. if sameConstant(c.constants[i], n): return i
  361. result = rawGenLiteral(c, n)
  362. proc unused(n: PNode; x: TDest) {.inline.} =
  363. if x >= 0:
  364. #debug(n)
  365. globalError(n.info, "not unused")
  366. proc genCase(c: PCtx; n: PNode; dest: var TDest) =
  367. # if (!expr1) goto L1;
  368. # thenPart
  369. # goto LEnd
  370. # L1:
  371. # if (!expr2) goto L2;
  372. # thenPart2
  373. # goto LEnd
  374. # L2:
  375. # elsePart
  376. # Lend:
  377. if not isEmptyType(n.typ):
  378. if dest < 0: dest = getTemp(c, n.typ)
  379. else:
  380. unused(n, dest)
  381. var endings: seq[TPosition] = @[]
  382. withTemp(tmp, n.sons[0].typ):
  383. c.gen(n.sons[0], tmp)
  384. # branch tmp, codeIdx
  385. # fjmp elseLabel
  386. for i in 1 .. <n.len:
  387. let it = n.sons[i]
  388. if it.len == 1:
  389. # else stmt:
  390. c.gen(it.sons[0], dest)
  391. else:
  392. let b = rawGenLiteral(c, it)
  393. c.gABx(it, opcBranch, tmp, b)
  394. let elsePos = c.xjmp(it.lastSon, opcFJmp, tmp)
  395. c.gen(it.lastSon, dest)
  396. if i < sonsLen(n)-1:
  397. endings.add(c.xjmp(it.lastSon, opcJmp, 0))
  398. c.patch(elsePos)
  399. c.clearDest(n, dest)
  400. for endPos in endings: c.patch(endPos)
  401. proc genType(c: PCtx; typ: PType): int =
  402. for i, t in c.types:
  403. if sameType(t, typ): return i
  404. result = c.types.len
  405. c.types.add(typ)
  406. internalAssert(result <= 0x7fff)
  407. proc genTry(c: PCtx; n: PNode; dest: var TDest) =
  408. if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
  409. var endings: seq[TPosition] = @[]
  410. let elsePos = c.xjmp(n, opcTry, 0)
  411. c.gen(n.sons[0], dest)
  412. c.clearDest(n, dest)
  413. c.patch(elsePos)
  414. for i in 1 .. <n.len:
  415. let it = n.sons[i]
  416. if it.kind != nkFinally:
  417. var blen = len(it)
  418. # first opcExcept contains the end label of the 'except' block:
  419. let endExcept = c.xjmp(it, opcExcept, 0)
  420. for j in countup(0, blen - 2):
  421. assert(it.sons[j].kind == nkType)
  422. let typ = it.sons[j].typ.skipTypes(abstractPtrs-{tyTypeDesc})
  423. c.gABx(it, opcExcept, 0, c.genType(typ))
  424. if blen == 1:
  425. # general except section:
  426. c.gABx(it, opcExcept, 0, 0)
  427. c.gen(it.lastSon, dest)
  428. c.clearDest(n, dest)
  429. if i < sonsLen(n)-1:
  430. endings.add(c.xjmp(it, opcJmp, 0))
  431. c.patch(endExcept)
  432. for endPos in endings: c.patch(endPos)
  433. let fin = lastSon(n)
  434. # we always generate an 'opcFinally' as that pops the safepoint
  435. # from the stack
  436. c.gABx(fin, opcFinally, 0, 0)
  437. if fin.kind == nkFinally:
  438. c.gen(fin.sons[0])
  439. c.clearDest(n, dest)
  440. c.gABx(fin, opcFinallyEnd, 0, 0)
  441. proc genRaise(c: PCtx; n: PNode) =
  442. let dest = genx(c, n.sons[0])
  443. c.gABC(n, opcRaise, dest)
  444. c.freeTemp(dest)
  445. proc genReturn(c: PCtx; n: PNode) =
  446. if n.sons[0].kind != nkEmpty:
  447. gen(c, n.sons[0])
  448. c.gABC(n, opcRet)
  449. proc genLit(c: PCtx; n: PNode; dest: var TDest) =
  450. # opcLdConst is now always valid. We produce the necessary copy in the
  451. # assignments now:
  452. #var opc = opcLdConst
  453. if dest < 0: dest = c.getTemp(n.typ)
  454. #elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
  455. let lit = genLiteral(c, n)
  456. c.gABx(n, opcLdConst, dest, lit)
  457. proc genCall(c: PCtx; n: PNode; dest: var TDest) =
  458. # it can happen that due to inlining we have a 'n' that should be
  459. # treated as a constant (see issue #537).
  460. #if n.typ != nil and n.typ.sym != nil and n.typ.sym.magic == mPNimrodNode:
  461. # genLit(c, n, dest)
  462. # return
  463. if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
  464. let x = c.getTempRange(n.len, slotTempUnknown)
  465. # varargs need 'opcSetType' for the FFI support:
  466. let fntyp = skipTypes(n.sons[0].typ, abstractInst)
  467. for i in 0.. <n.len:
  468. #if i > 0 and i < sonsLen(fntyp):
  469. # let paramType = fntyp.n.sons[i]
  470. # if paramType.typ.isCompileTimeOnly: continue
  471. var r: TRegister = x+i
  472. c.gen(n.sons[i], r)
  473. if i >= fntyp.len:
  474. internalAssert tfVarargs in fntyp.flags
  475. c.gABx(n, opcSetType, r, c.genType(n.sons[i].typ))
  476. if dest < 0:
  477. c.gABC(n, opcIndCall, 0, x, n.len)
  478. else:
  479. c.gABC(n, opcIndCallAsgn, dest, x, n.len)
  480. c.freeTempRange(x, n.len)
  481. template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
  482. proc isGlobal(n: PNode): bool = n.kind == nkSym and isGlobal(n.sym)
  483. proc needsAsgnPatch(n: PNode): bool =
  484. n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr,
  485. nkDerefExpr, nkHiddenDeref} or (n.kind == nkSym and n.sym.isGlobal)
  486. proc genField(n: PNode): TRegister =
  487. if n.kind != nkSym or n.sym.kind != skField:
  488. globalError(n.info, "no field symbol")
  489. let s = n.sym
  490. if s.position > high(result):
  491. globalError(n.info,
  492. "too large offset! cannot generate code for: " & s.name.s)
  493. result = s.position
  494. proc genIndex(c: PCtx; n: PNode; arr: PType): TRegister =
  495. if arr.skipTypes(abstractInst).kind == tyArray and (let x = firstOrd(arr);
  496. x != 0):
  497. let tmp = c.genx(n)
  498. # freeing the temporary here means we can produce: regA = regA - Imm
  499. c.freeTemp(tmp)
  500. result = c.getTemp(n.typ)
  501. c.gABI(n, opcSubImmInt, result, tmp, x.int)
  502. else:
  503. result = c.genx(n)
  504. proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
  505. case le.kind
  506. of nkBracketExpr:
  507. let dest = c.genx(le.sons[0], {gfAddrOf, gfFieldAccess})
  508. let idx = c.genIndex(le.sons[1], le.sons[0].typ)
  509. c.gABC(le, opcWrArr, dest, idx, value)
  510. c.freeTemp(dest)
  511. c.freeTemp(idx)
  512. of nkDotExpr, nkCheckedFieldExpr:
  513. # XXX field checks here
  514. let left = if le.kind == nkDotExpr: le else: le.sons[0]
  515. let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess})
  516. let idx = genField(left.sons[1])
  517. c.gABC(left, opcWrObj, dest, idx, value)
  518. c.freeTemp(dest)
  519. of nkDerefExpr, nkHiddenDeref:
  520. let dest = c.genx(le.sons[0], {gfAddrOf})
  521. c.gABC(le, opcWrDeref, dest, 0, value)
  522. c.freeTemp(dest)
  523. of nkSym:
  524. if le.sym.isGlobal:
  525. let dest = c.genx(le, {gfAddrOf})
  526. c.gABC(le, opcWrDeref, dest, 0, value)
  527. c.freeTemp(dest)
  528. else:
  529. discard
  530. proc genNew(c: PCtx; n: PNode) =
  531. let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(n.sons[1].typ)
  532. else: c.genx(n.sons[1])
  533. # we use the ref's base type here as the VM conflates 'ref object'
  534. # and 'object' since internally we already have a pointer.
  535. c.gABx(n, opcNew, dest,
  536. c.genType(n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).sons[0]))
  537. c.genAsgnPatch(n.sons[1], dest)
  538. c.freeTemp(dest)
  539. proc genNewSeq(c: PCtx; n: PNode) =
  540. let t = n.sons[1].typ
  541. let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(t)
  542. else: c.genx(n.sons[1])
  543. let tmp = c.genx(n.sons[2])
  544. c.gABx(n, opcNewSeq, dest, c.genType(t.skipTypes(
  545. abstractVar-{tyTypeDesc})))
  546. c.gABx(n, opcNewSeq, tmp, 0)
  547. c.freeTemp(tmp)
  548. c.genAsgnPatch(n.sons[1], dest)
  549. c.freeTemp(dest)
  550. proc genNewSeqOfCap(c: PCtx; n: PNode; dest: var TDest) =
  551. let t = n.typ
  552. let tmp = c.getTemp(n.sons[1].typ)
  553. c.gABx(n, opcLdNull, dest, c.genType(t))
  554. c.gABx(n, opcLdImmInt, tmp, 0)
  555. c.gABx(n, opcNewSeq, dest, c.genType(t.skipTypes(
  556. abstractVar-{tyTypeDesc})))
  557. c.gABx(n, opcNewSeq, tmp, 0)
  558. c.freeTemp(tmp)
  559. proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  560. let tmp = c.genx(n.sons[1])
  561. if dest < 0: dest = c.getTemp(n.typ)
  562. c.gABC(n, opc, dest, tmp)
  563. c.freeTemp(tmp)
  564. proc genUnaryABI(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; imm: BiggestInt=0) =
  565. let tmp = c.genx(n.sons[1])
  566. if dest < 0: dest = c.getTemp(n.typ)
  567. c.gABI(n, opc, dest, tmp, imm)
  568. c.freeTemp(tmp)
  569. proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  570. let
  571. tmp = c.genx(n.sons[1])
  572. tmp2 = c.genx(n.sons[2])
  573. if dest < 0: dest = c.getTemp(n.typ)
  574. c.gABC(n, opc, dest, tmp, tmp2)
  575. c.freeTemp(tmp)
  576. c.freeTemp(tmp2)
  577. proc genBinaryABCD(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  578. let
  579. tmp = c.genx(n.sons[1])
  580. tmp2 = c.genx(n.sons[2])
  581. tmp3 = c.genx(n.sons[3])
  582. if dest < 0: dest = c.getTemp(n.typ)
  583. c.gABC(n, opc, dest, tmp, tmp2)
  584. c.gABC(n, opc, tmp3)
  585. c.freeTemp(tmp)
  586. c.freeTemp(tmp2)
  587. c.freeTemp(tmp3)
  588. proc genNarrow(c: PCtx; n: PNode; dest: TDest) =
  589. let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
  590. # uint is uint64 in the VM, we we only need to mask the result for
  591. # other unsigned types:
  592. if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
  593. c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
  594. elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8):
  595. c.gABC(n, opcNarrowS, dest, TRegister(t.size*8))
  596. proc genNarrowU(c: PCtx; n: PNode; dest: TDest) =
  597. let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
  598. # uint is uint64 in the VM, we we only need to mask the result for
  599. # other unsigned types:
  600. if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
  601. (t.kind in {tyUInt, tyInt} and t.size < 8):
  602. c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
  603. proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  604. genBinaryABC(c, n, dest, opc)
  605. genNarrow(c, n, dest)
  606. proc genBinaryABCnarrowU(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  607. genBinaryABC(c, n, dest, opc)
  608. genNarrowU(c, n, dest)
  609. proc genSetType(c: PCtx; n: PNode; dest: TRegister) =
  610. let t = skipTypes(n.typ, abstractInst-{tyTypeDesc})
  611. if t.kind == tySet:
  612. c.gABx(n, opcSetType, dest, c.genType(t))
  613. proc genBinarySet(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  614. let
  615. tmp = c.genx(n.sons[1])
  616. tmp2 = c.genx(n.sons[2])
  617. if dest < 0: dest = c.getTemp(n.typ)
  618. c.genSetType(n.sons[1], tmp)
  619. c.genSetType(n.sons[2], tmp2)
  620. c.gABC(n, opc, dest, tmp, tmp2)
  621. c.freeTemp(tmp)
  622. c.freeTemp(tmp2)
  623. proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
  624. let
  625. dest = c.genx(n.sons[1])
  626. tmp = c.genx(n.sons[2])
  627. c.gABC(n, opc, dest, tmp, 0)
  628. c.freeTemp(tmp)
  629. proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) =
  630. var x = n.sons[1]
  631. if x.kind in {nkAddr, nkHiddenAddr}: x = x.sons[0]
  632. let
  633. dest = c.genx(x)
  634. tmp = c.genx(n.sons[2])
  635. c.gABC(n, opc, dest, tmp, 0)
  636. #c.genAsgnPatch(n.sons[1], dest)
  637. c.freeTemp(tmp)
  638. proc genUnaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
  639. let tmp = c.genx(n.sons[1])
  640. c.gABC(n, opc, tmp, 0, 0)
  641. c.freeTemp(tmp)
  642. proc genVarargsABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  643. if dest < 0: dest = getTemp(c, n.typ)
  644. var x = c.getTempRange(n.len-1, slotTempStr)
  645. for i in 1..n.len-1:
  646. var r: TRegister = x+i-1
  647. c.gen(n.sons[i], r)
  648. c.gABC(n, opc, dest, x, n.len-1)
  649. c.freeTempRange(x, n.len)
  650. proc isInt8Lit(n: PNode): bool =
  651. if n.kind in {nkCharLit..nkUInt64Lit}:
  652. result = n.intVal >= low(int8) and n.intVal <= high(int8)
  653. proc isInt16Lit(n: PNode): bool =
  654. if n.kind in {nkCharLit..nkUInt64Lit}:
  655. result = n.intVal >= low(int16) and n.intVal <= high(int16)
  656. proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
  657. if n.sons[2].isInt8Lit:
  658. let tmp = c.genx(n.sons[1])
  659. if dest < 0: dest = c.getTemp(n.typ)
  660. c.gABI(n, succ(opc), dest, tmp, n.sons[2].intVal)
  661. c.freeTemp(tmp)
  662. else:
  663. genBinaryABC(c, n, dest, opc)
  664. c.genNarrow(n, dest)
  665. proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
  666. if n.typ.kind == arg.typ.kind and arg.typ.kind == tyProc:
  667. # don't do anything for lambda lifting conversions:
  668. gen(c, arg, dest)
  669. return
  670. let tmp = c.genx(arg)
  671. if dest < 0: dest = c.getTemp(n.typ)
  672. c.gABC(n, opc, dest, tmp)
  673. c.gABx(n, opc, 0, genType(c, n.typ.skipTypes({tyStatic})))
  674. c.gABx(n, opc, 0, genType(c, arg.typ.skipTypes({tyStatic})))
  675. c.freeTemp(tmp)
  676. proc genCard(c: PCtx; n: PNode; dest: var TDest) =
  677. let tmp = c.genx(n.sons[1])
  678. if dest < 0: dest = c.getTemp(n.typ)
  679. c.genSetType(n.sons[1], tmp)
  680. c.gABC(n, opcCard, dest, tmp)
  681. c.freeTemp(tmp)
  682. proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
  683. case m
  684. of mAnd: c.genAndOr(n, opcFJmp, dest)
  685. of mOr: c.genAndOr(n, opcTJmp, dest)
  686. of mUnaryLt:
  687. let tmp = c.genx(n.sons[1])
  688. if dest < 0: dest = c.getTemp(n.typ)
  689. c.gABI(n, opcSubImmInt, dest, tmp, 1)
  690. c.freeTemp(tmp)
  691. of mPred, mSubI:
  692. c.genAddSubInt(n, dest, opcSubInt)
  693. of mSucc, mAddI:
  694. c.genAddSubInt(n, dest, opcAddInt)
  695. of mInc, mDec:
  696. unused(n, dest)
  697. let opc = if m == mInc: opcAddInt else: opcSubInt
  698. let d = c.genx(n.sons[1])
  699. if n.sons[2].isInt8Lit:
  700. c.gABI(n, succ(opc), d, d, n.sons[2].intVal)
  701. else:
  702. let tmp = c.genx(n.sons[2])
  703. c.gABC(n, opc, d, d, tmp)
  704. c.freeTemp(tmp)
  705. c.genNarrow(n.sons[1], d)
  706. c.genAsgnPatch(n.sons[1], d)
  707. c.freeTemp(d)
  708. of mOrd, mChr, mArrToSeq: c.gen(n.sons[1], dest)
  709. of mNew, mNewFinalize:
  710. unused(n, dest)
  711. c.genNew(n)
  712. of mNewSeq:
  713. unused(n, dest)
  714. c.genNewSeq(n)
  715. of mNewSeqOfCap: c.genNewSeqOfCap(n, dest)
  716. of mNewString:
  717. genUnaryABC(c, n, dest, opcNewStr)
  718. # XXX buggy
  719. of mNewStringOfCap:
  720. # we ignore the 'cap' argument and translate it as 'newString(0)'.
  721. # eval n.sons[1] for possible side effects:
  722. var tmp = c.genx(n.sons[1])
  723. c.gABx(n, opcLdImmInt, tmp, 0)
  724. if dest < 0: dest = c.getTemp(n.typ)
  725. c.gABC(n, opcNewStr, dest, tmp)
  726. c.freeTemp(tmp)
  727. # XXX buggy
  728. of mLengthOpenArray, mLengthArray, mLengthSeq, mXLenSeq:
  729. genUnaryABI(c, n, dest, opcLenSeq)
  730. of mLengthStr, mXLenStr:
  731. genUnaryABI(c, n, dest, opcLenStr)
  732. of mIncl, mExcl:
  733. unused(n, dest)
  734. var d = c.genx(n.sons[1])
  735. var tmp = c.genx(n.sons[2])
  736. c.genSetType(n.sons[1], d)
  737. c.gABC(n, if m == mIncl: opcIncl else: opcExcl, d, tmp)
  738. c.freeTemp(d)
  739. c.freeTemp(tmp)
  740. of mCard: genCard(c, n, dest)
  741. of mMulI: genBinaryABCnarrow(c, n, dest, opcMulInt)
  742. of mDivI: genBinaryABCnarrow(c, n, dest, opcDivInt)
  743. of mModI: genBinaryABCnarrow(c, n, dest, opcModInt)
  744. of mAddF64: genBinaryABC(c, n, dest, opcAddFloat)
  745. of mSubF64: genBinaryABC(c, n, dest, opcSubFloat)
  746. of mMulF64: genBinaryABC(c, n, dest, opcMulFloat)
  747. of mDivF64: genBinaryABC(c, n, dest, opcDivFloat)
  748. of mShrI:
  749. # the idea here is to narrow type if needed before executing right shift
  750. # inlined modified: genNarrowU(c, n, dest)
  751. let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
  752. # uint is uint64 in the VM, we we only need to mask the result for
  753. # other unsigned types:
  754. let tmp = c.genx(n.sons[1])
  755. if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32}:
  756. c.gABC(n, opcNarrowU, tmp, TRegister(t.size*8))
  757. # inlined modified: genBinaryABC(c, n, dest, opcShrInt)
  758. let tmp2 = c.genx(n.sons[2])
  759. if dest < 0: dest = c.getTemp(n.typ)
  760. c.gABC(n, opcShrInt, dest, tmp, tmp2)
  761. c.freeTemp(tmp)
  762. c.freeTemp(tmp2)
  763. of mShlI: genBinaryABCnarrowU(c, n, dest, opcShlInt)
  764. of mBitandI: genBinaryABCnarrowU(c, n, dest, opcBitandInt)
  765. of mBitorI: genBinaryABCnarrowU(c, n, dest, opcBitorInt)
  766. of mBitxorI: genBinaryABCnarrowU(c, n, dest, opcBitxorInt)
  767. of mAddU: genBinaryABCnarrowU(c, n, dest, opcAddu)
  768. of mSubU: genBinaryABCnarrowU(c, n, dest, opcSubu)
  769. of mMulU: genBinaryABCnarrowU(c, n, dest, opcMulu)
  770. of mDivU: genBinaryABCnarrowU(c, n, dest, opcDivu)
  771. of mModU: genBinaryABCnarrowU(c, n, dest, opcModu)
  772. of mEqI, mEqB, mEqEnum, mEqCh:
  773. genBinaryABC(c, n, dest, opcEqInt)
  774. of mLeI, mLeEnum, mLeCh, mLeB:
  775. genBinaryABC(c, n, dest, opcLeInt)
  776. of mLtI, mLtEnum, mLtCh, mLtB:
  777. genBinaryABC(c, n, dest, opcLtInt)
  778. of mEqF64: genBinaryABC(c, n, dest, opcEqFloat)
  779. of mLeF64: genBinaryABC(c, n, dest, opcLeFloat)
  780. of mLtF64: genBinaryABC(c, n, dest, opcLtFloat)
  781. of mLePtr, mLeU, mLeU64: genBinaryABC(c, n, dest, opcLeu)
  782. of mLtPtr, mLtU, mLtU64: genBinaryABC(c, n, dest, opcLtu)
  783. of mEqProc, mEqRef, mEqUntracedRef:
  784. genBinaryABC(c, n, dest, opcEqRef)
  785. of mXor: genBinaryABCnarrowU(c, n, dest, opcXor)
  786. of mNot: genUnaryABC(c, n, dest, opcNot)
  787. of mUnaryMinusI, mUnaryMinusI64:
  788. genUnaryABC(c, n, dest, opcUnaryMinusInt)
  789. genNarrow(c, n, dest)
  790. of mUnaryMinusF64: genUnaryABC(c, n, dest, opcUnaryMinusFloat)
  791. of mUnaryPlusI, mUnaryPlusF64: gen(c, n.sons[1], dest)
  792. of mBitnotI:
  793. genUnaryABC(c, n, dest, opcBitnotInt)
  794. genNarrowU(c, n, dest)
  795. of mToFloat, mToBiggestFloat, mToInt,
  796. mToBiggestInt, mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr,
  797. mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
  798. genConv(c, n, n.sons[1], dest)
  799. of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
  800. #genNarrowU modified
  801. let t = skipTypes(n.sons[1].typ, abstractVar-{tyTypeDesc})
  802. let tmp = c.genx(n.sons[1])
  803. c.gABC(n, opcNarrowU, tmp, TRegister(t.size*8))
  804. # assign result to dest register
  805. if dest < 0: dest = c.getTemp(n.typ)
  806. c.gABC(n, opcAsgnInt, dest, tmp)
  807. c.freeTemp(tmp)
  808. of mToU8, mToU16, mToU32:
  809. let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
  810. var tmp = c.genx(n.sons[1])
  811. if dest < 0: dest = c.getTemp(n.typ)
  812. c.gABC(n, opcToNarrowInt, dest, tmp, TRegister(t.size*8))
  813. c.freeTemp(tmp)
  814. of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
  815. of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
  816. of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
  817. of mEqSet: genBinarySet(c, n, dest, opcEqSet)
  818. of mLeSet: genBinarySet(c, n, dest, opcLeSet)
  819. of mLtSet: genBinarySet(c, n, dest, opcLtSet)
  820. of mMulSet: genBinarySet(c, n, dest, opcMulSet)
  821. of mPlusSet: genBinarySet(c, n, dest, opcPlusSet)
  822. of mMinusSet: genBinarySet(c, n, dest, opcMinusSet)
  823. of mSymDiffSet: genBinarySet(c, n, dest, opcSymdiffSet)
  824. of mConStrStr: genVarargsABC(c, n, dest, opcConcatStr)
  825. of mInSet: genBinarySet(c, n, dest, opcContainsSet)
  826. of mRepr: genUnaryABC(c, n, dest, opcRepr)
  827. of mExit:
  828. unused(n, dest)
  829. var tmp = c.genx(n.sons[1])
  830. c.gABC(n, opcQuit, tmp)
  831. c.freeTemp(tmp)
  832. of mSetLengthStr, mSetLengthSeq:
  833. unused(n, dest)
  834. var d = c.genx(n.sons[1])
  835. var tmp = c.genx(n.sons[2])
  836. c.gABC(n, if m == mSetLengthStr: opcSetLenStr else: opcSetLenSeq, d, tmp)
  837. c.genAsgnPatch(n.sons[1], d)
  838. c.freeTemp(tmp)
  839. of mSwap:
  840. unused(n, dest)
  841. c.gen(lowerSwap(n, if c.prc == nil: c.module else: c.prc.sym))
  842. of mIsNil: genUnaryABC(c, n, dest, opcIsNil)
  843. of mCopyStr:
  844. if dest < 0: dest = c.getTemp(n.typ)
  845. var
  846. tmp1 = c.genx(n.sons[1])
  847. tmp2 = c.genx(n.sons[2])
  848. tmp3 = c.getTemp(n.sons[2].typ)
  849. c.gABC(n, opcLenStr, tmp3, tmp1)
  850. c.gABC(n, opcSubStr, dest, tmp1, tmp2)
  851. c.gABC(n, opcSubStr, tmp3)
  852. c.freeTemp(tmp1)
  853. c.freeTemp(tmp2)
  854. c.freeTemp(tmp3)
  855. of mCopyStrLast:
  856. if dest < 0: dest = c.getTemp(n.typ)
  857. var
  858. tmp1 = c.genx(n.sons[1])
  859. tmp2 = c.genx(n.sons[2])
  860. tmp3 = c.genx(n.sons[3])
  861. c.gABC(n, opcSubStr, dest, tmp1, tmp2)
  862. c.gABC(n, opcSubStr, tmp3)
  863. c.freeTemp(tmp1)
  864. c.freeTemp(tmp2)
  865. c.freeTemp(tmp3)
  866. of mParseBiggestFloat:
  867. if dest < 0: dest = c.getTemp(n.typ)
  868. var d2: TRegister
  869. # skip 'nkHiddenAddr':
  870. let d2AsNode = n.sons[2].sons[0]
  871. if needsAsgnPatch(d2AsNode):
  872. d2 = c.getTemp(getSysType(tyFloat))
  873. else:
  874. d2 = c.genx(d2AsNode)
  875. var
  876. tmp1 = c.genx(n.sons[1])
  877. tmp3 = c.genx(n.sons[3])
  878. c.gABC(n, opcParseFloat, dest, tmp1, d2)
  879. c.gABC(n, opcParseFloat, tmp3)
  880. c.freeTemp(tmp1)
  881. c.freeTemp(tmp3)
  882. c.genAsgnPatch(d2AsNode, d2)
  883. c.freeTemp(d2)
  884. of mReset:
  885. unused(n, dest)
  886. var d = c.genx(n.sons[1])
  887. c.gABC(n, opcReset, d)
  888. of mOf, mIs:
  889. if dest < 0: dest = c.getTemp(n.typ)
  890. var tmp = c.genx(n.sons[1])
  891. var idx = c.getTemp(getSysType(tyInt))
  892. var typ = n.sons[2].typ
  893. if m == mOf: typ = typ.skipTypes(abstractPtrs-{tyTypeDesc})
  894. c.gABx(n, opcLdImmInt, idx, c.genType(typ))
  895. c.gABC(n, if m == mOf: opcOf else: opcIs, dest, tmp, idx)
  896. c.freeTemp(tmp)
  897. c.freeTemp(idx)
  898. of mSizeOf:
  899. globalError(n.info, errCannotInterpretNodeX, renderTree(n))
  900. of mHigh:
  901. if dest < 0: dest = c.getTemp(n.typ)
  902. let tmp = c.genx(n.sons[1])
  903. case n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind:
  904. of tyString, tyCString:
  905. c.gABI(n, opcLenStr, dest, tmp, 1)
  906. else:
  907. c.gABI(n, opcLenSeq, dest, tmp, 1)
  908. c.freeTemp(tmp)
  909. of mEcho:
  910. unused(n, dest)
  911. let n = n[1].skipConv
  912. let x = c.getTempRange(n.len, slotTempUnknown)
  913. internalAssert n.kind == nkBracket
  914. for i in 0.. <n.len:
  915. var r: TRegister = x+i
  916. c.gen(n.sons[i], r)
  917. c.gABC(n, opcEcho, x, n.len)
  918. c.freeTempRange(x, n.len)
  919. of mAppendStrCh:
  920. unused(n, dest)
  921. genBinaryStmtVar(c, n, opcAddStrCh)
  922. of mAppendStrStr:
  923. unused(n, dest)
  924. genBinaryStmtVar(c, n, opcAddStrStr)
  925. of mAppendSeqElem:
  926. unused(n, dest)
  927. genBinaryStmtVar(c, n, opcAddSeqElem)
  928. of mParseExprToAst:
  929. genUnaryABC(c, n, dest, opcParseExprToAst)
  930. of mParseStmtToAst:
  931. genUnaryABC(c, n, dest, opcParseStmtToAst)
  932. of mTypeTrait:
  933. let tmp = c.genx(n.sons[1])
  934. if dest < 0: dest = c.getTemp(n.typ)
  935. c.gABx(n, opcSetType, tmp, c.genType(n.sons[1].typ))
  936. c.gABC(n, opcTypeTrait, dest, tmp)
  937. c.freeTemp(tmp)
  938. of mSlurp: genUnaryABC(c, n, dest, opcSlurp)
  939. of mStaticExec: genBinaryABCD(c, n, dest, opcGorge)
  940. of mNLen: genUnaryABI(c, n, dest, opcLenSeq, nimNodeFlag)
  941. of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl)
  942. of mNChild: genBinaryABC(c, n, dest, opcNChild)
  943. of mNSetChild, mNDel:
  944. unused(n, dest)
  945. var
  946. tmp1 = c.genx(n.sons[1])
  947. tmp2 = c.genx(n.sons[2])
  948. tmp3 = c.genx(n.sons[3])
  949. c.gABC(n, if m == mNSetChild: opcNSetChild else: opcNDel, tmp1, tmp2, tmp3)
  950. c.freeTemp(tmp1)
  951. c.freeTemp(tmp2)
  952. c.freeTemp(tmp3)
  953. of mNAdd: genBinaryABC(c, n, dest, opcNAdd)
  954. of mNAddMultiple: genBinaryABC(c, n, dest, opcNAddMultiple)
  955. of mNKind: genUnaryABC(c, n, dest, opcNKind)
  956. of mNIntVal: genUnaryABC(c, n, dest, opcNIntVal)
  957. of mNFloatVal: genUnaryABC(c, n, dest, opcNFloatVal)
  958. of mNSymbol: genUnaryABC(c, n, dest, opcNSymbol)
  959. of mNIdent: genUnaryABC(c, n, dest, opcNIdent)
  960. of mNGetType:
  961. let tmp = c.genx(n.sons[1])
  962. if dest < 0: dest = c.getTemp(n.typ)
  963. let rc = case n[0].sym.name.s:
  964. of "getType": 0
  965. of "typeKind": 1
  966. of "getTypeInst": 2
  967. else: 3 # "getTypeImpl"
  968. c.gABC(n, opcNGetType, dest, tmp, rc)
  969. c.freeTemp(tmp)
  970. #genUnaryABC(c, n, dest, opcNGetType)
  971. of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
  972. of mNSetIntVal:
  973. unused(n, dest)
  974. genBinaryStmt(c, n, opcNSetIntVal)
  975. of mNSetFloatVal:
  976. unused(n, dest)
  977. genBinaryStmt(c, n, opcNSetFloatVal)
  978. of mNSetSymbol:
  979. unused(n, dest)
  980. genBinaryStmt(c, n, opcNSetSymbol)
  981. of mNSetIdent:
  982. unused(n, dest)
  983. genBinaryStmt(c, n, opcNSetIdent)
  984. of mNSetType:
  985. unused(n, dest)
  986. genBinaryStmt(c, n, opcNSetType)
  987. of mNSetStrVal:
  988. unused(n, dest)
  989. genBinaryStmt(c, n, opcNSetStrVal)
  990. of mNNewNimNode: genBinaryABC(c, n, dest, opcNNewNimNode)
  991. of mNCopyNimNode: genUnaryABC(c, n, dest, opcNCopyNimNode)
  992. of mNCopyNimTree: genUnaryABC(c, n, dest, opcNCopyNimTree)
  993. of mNBindSym:
  994. if n[1].kind in {nkClosedSymChoice, nkOpenSymChoice, nkSym}:
  995. let idx = c.genLiteral(n[1])
  996. if dest < 0: dest = c.getTemp(n.typ)
  997. c.gABx(n, opcNBindSym, dest, idx)
  998. else:
  999. localError(n.info, "invalid bindSym usage")
  1000. of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
  1001. of mIdentToStr: genUnaryABC(c, n, dest, opcIdentToStr)
  1002. of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
  1003. of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimrodNode)
  1004. of mSameNodeType: genBinaryABC(c, n, dest, opcSameNodeType)
  1005. of mNLineInfo:
  1006. case n[0].sym.name.s
  1007. of "getFile":
  1008. genUnaryABC(c, n, dest, opcNGetFile)
  1009. of "getLine":
  1010. genUnaryABC(c, n, dest, opcNGetLine)
  1011. of "getColumn":
  1012. genUnaryABC(c, n, dest, opcNGetColumn)
  1013. else:
  1014. internalAssert false
  1015. of mNHint:
  1016. unused(n, dest)
  1017. genUnaryStmt(c, n, opcNHint)
  1018. of mNWarning:
  1019. unused(n, dest)
  1020. genUnaryStmt(c, n, opcNWarning)
  1021. of mNError:
  1022. if n.len <= 1:
  1023. # query error condition:
  1024. c.gABC(n, opcQueryErrorFlag, dest)
  1025. else:
  1026. # setter
  1027. unused(n, dest)
  1028. genBinaryStmt(c, n, opcNError)
  1029. of mNCallSite:
  1030. if dest < 0: dest = c.getTemp(n.typ)
  1031. c.gABC(n, opcCallSite, dest)
  1032. of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
  1033. of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI,
  1034. mDotDot:
  1035. c.genCall(n, dest)
  1036. of mExpandToAst:
  1037. if n.len != 2:
  1038. globalError(n.info, errGenerated, "expandToAst requires 1 argument")
  1039. let arg = n.sons[1]
  1040. if arg.kind in nkCallKinds:
  1041. #if arg[0].kind != nkSym or arg[0].sym.kind notin {skTemplate, skMacro}:
  1042. # "ExpandToAst: expanded symbol is no macro or template"
  1043. if dest < 0: dest = c.getTemp(n.typ)
  1044. c.genCall(arg, dest)
  1045. # do not call clearDest(n, dest) here as getAst has a meta-type as such
  1046. # produces a value
  1047. else:
  1048. globalError(n.info, "expandToAst requires a call expression")
  1049. else:
  1050. # mGCref, mGCunref,
  1051. globalError(n.info, "cannot generate code for: " & $m)
  1052. proc genMarshalLoad(c: PCtx, n: PNode, dest: var TDest) =
  1053. ## Signature: proc to*[T](data: string): T
  1054. if dest < 0: dest = c.getTemp(n.typ)
  1055. var tmp = c.genx(n.sons[1])
  1056. c.gABC(n, opcMarshalLoad, dest, tmp)
  1057. c.gABx(n, opcMarshalLoad, 0, c.genType(n.typ))
  1058. c.freeTemp(tmp)
  1059. proc genMarshalStore(c: PCtx, n: PNode, dest: var TDest) =
  1060. ## Signature: proc `$$`*[T](x: T): string
  1061. if dest < 0: dest = c.getTemp(n.typ)
  1062. var tmp = c.genx(n.sons[1])
  1063. c.gABC(n, opcMarshalStore, dest, tmp)
  1064. c.gABx(n, opcMarshalStore, 0, c.genType(n.sons[1].typ))
  1065. c.freeTemp(tmp)
  1066. const
  1067. atomicTypes = {tyBool, tyChar,
  1068. tyExpr, tyStmt, tyTypeDesc, tyStatic,
  1069. tyEnum,
  1070. tyOrdinal,
  1071. tyRange,
  1072. tyProc,
  1073. tyPointer, tyOpenArray,
  1074. tyString, tyCString,
  1075. tyInt, tyInt8, tyInt16, tyInt32, tyInt64,
  1076. tyFloat, tyFloat32, tyFloat64, tyFloat128,
  1077. tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64}
  1078. proc fitsRegister*(t: PType): bool =
  1079. assert t != nil
  1080. t.skipTypes(abstractInst-{tyTypeDesc}).kind in {
  1081. tyRange, tyEnum, tyBool, tyInt..tyUInt64, tyChar}
  1082. proc unneededIndirection(n: PNode): bool =
  1083. n.typ.skipTypes(abstractInst-{tyTypeDesc}).kind == tyRef
  1084. proc canElimAddr(n: PNode): PNode =
  1085. case n.sons[0].kind
  1086. of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
  1087. var m = n.sons[0].sons[0]
  1088. if m.kind in {nkDerefExpr, nkHiddenDeref}:
  1089. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  1090. result = copyNode(n.sons[0])
  1091. result.add m.sons[0]
  1092. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  1093. var m = n.sons[0].sons[1]
  1094. if m.kind in {nkDerefExpr, nkHiddenDeref}:
  1095. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  1096. result = copyNode(n.sons[0])
  1097. result.add m.sons[0]
  1098. else:
  1099. if n.sons[0].kind in {nkDerefExpr, nkHiddenDeref}:
  1100. # addr ( deref ( x )) --> x
  1101. result = n.sons[0].sons[0]
  1102. proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
  1103. flags: TGenFlags) =
  1104. # a nop for certain types
  1105. let isAddr = opc in {opcAddrNode, opcAddrReg}
  1106. if isAddr and (let m = canElimAddr(n); m != nil):
  1107. gen(c, m, dest, flags)
  1108. return
  1109. let af = if n[0].kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr}: {gfAddrOf, gfFieldAccess}
  1110. else: {gfAddrOf}
  1111. let newflags = if isAddr: flags+af else: flags
  1112. # consider:
  1113. # proc foo(f: var ref int) =
  1114. # f = new(int)
  1115. # proc blah() =
  1116. # var x: ref int
  1117. # foo x
  1118. #
  1119. # The type of 'f' is 'var ref int' and of 'x' is 'ref int'. Hence for
  1120. # nkAddr we must not use 'unneededIndirection', but for deref we use it.
  1121. if not isAddr and unneededIndirection(n.sons[0]):
  1122. gen(c, n.sons[0], dest, newflags)
  1123. if gfAddrOf notin flags and fitsRegister(n.typ):
  1124. c.gABC(n, opcNodeToReg, dest, dest)
  1125. elif isAddr and isGlobal(n.sons[0]):
  1126. gen(c, n.sons[0], dest, flags+af)
  1127. else:
  1128. let tmp = c.genx(n.sons[0], newflags)
  1129. if dest < 0: dest = c.getTemp(n.typ)
  1130. if not isAddr:
  1131. gABC(c, n, opc, dest, tmp)
  1132. assert n.typ != nil
  1133. if gfAddrOf notin flags and fitsRegister(n.typ):
  1134. c.gABC(n, opcNodeToReg, dest, dest)
  1135. elif c.prc.slots[tmp].kind >= slotTempUnknown:
  1136. gABC(c, n, opcAddrNode, dest, tmp)
  1137. # hack ahead; in order to fix bug #1781 we mark the temporary as
  1138. # permanent, so that it's not used for anything else:
  1139. c.prc.slots[tmp].kind = slotTempPerm
  1140. # XXX this is still a hack
  1141. #message(n.info, warnUser, "suspicious opcode used")
  1142. else:
  1143. gABC(c, n, opcAddrReg, dest, tmp)
  1144. c.freeTemp(tmp)
  1145. proc whichAsgnOpc(n: PNode): TOpcode =
  1146. case n.typ.skipTypes(abstractRange-{tyTypeDesc}).kind
  1147. of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64:
  1148. opcAsgnInt
  1149. of tyString, tyCString:
  1150. opcAsgnStr
  1151. of tyFloat..tyFloat128:
  1152. opcAsgnFloat
  1153. of tyRef, tyNil, tyVar:
  1154. opcAsgnRef
  1155. else:
  1156. opcAsgnComplex
  1157. proc whichAsgnOpc(n: PNode; opc: TOpcode): TOpcode = opc
  1158. proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
  1159. let tmp = c.genx(ri)
  1160. assert dest >= 0
  1161. gABC(c, ri, whichAsgnOpc(ri), dest, tmp, 1-ord(requiresCopy))
  1162. c.freeTemp(tmp)
  1163. proc setSlot(c: PCtx; v: PSym) =
  1164. # XXX generate type initialization here?
  1165. if v.position == 0:
  1166. if c.prc.maxSlots == 0: c.prc.maxSlots = 1
  1167. if c.prc.maxSlots >= high(TRegister):
  1168. globalError(v.info, "cannot generate code; too many registers required")
  1169. v.position = c.prc.maxSlots
  1170. c.prc.slots[v.position] = (inUse: true,
  1171. kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
  1172. inc c.prc.maxSlots
  1173. proc cannotEval(n: PNode) {.noinline.} =
  1174. globalError(n.info, errGenerated, "cannot evaluate at compile time: " &
  1175. n.renderTree)
  1176. proc isOwnedBy(a, b: PSym): bool =
  1177. var a = a.owner
  1178. while a != nil and a.kind != skModule:
  1179. if a == b: return true
  1180. a = a.owner
  1181. proc getOwner(c: PCtx): PSym =
  1182. result = c.prc.sym
  1183. if result.isNil: result = c.module
  1184. proc checkCanEval(c: PCtx; n: PNode) =
  1185. # we need to ensure that we don't evaluate 'x' here:
  1186. # proc foo() = var x ...
  1187. let s = n.sym
  1188. if {sfCompileTime, sfGlobal} <= s.flags: return
  1189. if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
  1190. not s.isOwnedBy(c.prc.sym) and s.owner != c.module and c.mode != emRepl:
  1191. cannotEval(n)
  1192. elif s.kind in {skProc, skFunc, skConverter, skMethod,
  1193. skIterator} and sfForward in s.flags:
  1194. cannotEval(n)
  1195. proc isTemp(c: PCtx; dest: TDest): bool =
  1196. result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown
  1197. template needsAdditionalCopy(n): untyped =
  1198. not c.isTemp(dest) and not fitsRegister(n.typ)
  1199. proc genAdditionalCopy(c: PCtx; n: PNode; opc: TOpcode;
  1200. dest, idx, value: TRegister) =
  1201. var cc = c.getTemp(n.typ)
  1202. c.gABC(n, whichAsgnOpc(n), cc, value, 0)
  1203. c.gABC(n, opc, dest, idx, cc)
  1204. c.freeTemp(cc)
  1205. proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
  1206. dest, idx, value: TRegister) =
  1207. # opcLdObj et al really means "load address". We sometimes have to create a
  1208. # copy in order to not introduce false aliasing:
  1209. # mylocal = a.b # needs a copy of the data!
  1210. assert n.typ != nil
  1211. if needsAdditionalCopy(n):
  1212. genAdditionalCopy(c, n, opc, dest, idx, value)
  1213. else:
  1214. c.gABC(n, opc, dest, idx, value)
  1215. proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
  1216. case le.kind
  1217. of nkBracketExpr:
  1218. let dest = c.genx(le.sons[0], {gfAddrOf, gfFieldAccess})
  1219. let idx = c.genIndex(le.sons[1], le.sons[0].typ)
  1220. let tmp = c.genx(ri)
  1221. if le.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
  1222. tyString, tyCString}:
  1223. c.preventFalseAlias(le, opcWrStrIdx, dest, idx, tmp)
  1224. else:
  1225. c.preventFalseAlias(le, opcWrArr, dest, idx, tmp)
  1226. c.freeTemp(tmp)
  1227. of nkDotExpr, nkCheckedFieldExpr:
  1228. # XXX field checks here
  1229. let left = if le.kind == nkDotExpr: le else: le.sons[0]
  1230. let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess})
  1231. let idx = genField(left.sons[1])
  1232. let tmp = c.genx(ri)
  1233. c.preventFalseAlias(left, opcWrObj, dest, idx, tmp)
  1234. c.freeTemp(tmp)
  1235. of nkDerefExpr, nkHiddenDeref:
  1236. let dest = c.genx(le.sons[0], {gfAddrOf})
  1237. let tmp = c.genx(ri)
  1238. c.preventFalseAlias(le, opcWrDeref, dest, 0, tmp)
  1239. c.freeTemp(tmp)
  1240. of nkSym:
  1241. let s = le.sym
  1242. checkCanEval(c, le)
  1243. if s.isGlobal:
  1244. withTemp(tmp, le.typ):
  1245. c.gen(le, tmp, {gfAddrOf})
  1246. let val = c.genx(ri)
  1247. c.preventFalseAlias(le, opcWrDeref, tmp, 0, val)
  1248. c.freeTemp(val)
  1249. else:
  1250. if s.kind == skForVar: c.setSlot s
  1251. internalAssert s.position > 0 or (s.position == 0 and
  1252. s.kind in {skParam,skResult})
  1253. var dest: TRegister = s.position + ord(s.kind == skParam)
  1254. assert le.typ != nil
  1255. if needsAdditionalCopy(le) and s.kind in {skResult, skVar, skParam}:
  1256. var cc = c.getTemp(le.typ)
  1257. gen(c, ri, cc)
  1258. c.gABC(le, whichAsgnOpc(le), dest, cc, 1)
  1259. c.freeTemp(cc)
  1260. else:
  1261. gen(c, ri, dest)
  1262. else:
  1263. let dest = c.genx(le, {gfAddrOf})
  1264. genAsgn(c, dest, ri, requiresCopy)
  1265. proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
  1266. var n = newNode(nkType)
  1267. n.typ = t
  1268. genLit(c, n, dest)
  1269. proc importcSym(c: PCtx; info: TLineInfo; s: PSym) =
  1270. when hasFFI:
  1271. if allowFFI in c.features:
  1272. c.globals.add(importcSymbol(s))
  1273. s.position = c.globals.len
  1274. else:
  1275. localError(info, errGenerated, "VM is not allowed to 'importc'")
  1276. else:
  1277. localError(info, errGenerated,
  1278. "cannot 'importc' variable at compile time")
  1279. proc getNullValue*(typ: PType, info: TLineInfo): PNode
  1280. proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
  1281. c.globals.add(getNullValue(s.typ, n.info))
  1282. s.position = c.globals.len
  1283. # This is rather hard to support, due to the laziness of the VM code
  1284. # generator. See tests/compile/tmacro2 for why this is necessary:
  1285. # var decls{.compileTime.}: seq[NimNode] = @[]
  1286. let dest = c.getTemp(s.typ)
  1287. c.gABx(n, opcLdGlobal, dest, s.position)
  1288. if s.ast != nil:
  1289. let tmp = c.genx(s.ast)
  1290. c.genAdditionalCopy(n, opcWrDeref, dest, 0, tmp)
  1291. c.freeTemp(dest)
  1292. c.freeTemp(tmp)
  1293. proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
  1294. let s = n.sym
  1295. if s.isGlobal:
  1296. if sfCompileTime in s.flags or c.mode == emRepl:
  1297. discard
  1298. elif s.position == 0:
  1299. cannotEval(n)
  1300. if s.position == 0:
  1301. if sfImportc in s.flags: c.importcSym(n.info, s)
  1302. else: genGlobalInit(c, n, s)
  1303. if dest < 0: dest = c.getTemp(n.typ)
  1304. assert s.typ != nil
  1305. if gfAddrOf notin flags and fitsRegister(s.typ):
  1306. var cc = c.getTemp(n.typ)
  1307. c.gABx(n, opcLdGlobal, cc, s.position)
  1308. c.gABC(n, opcNodeToReg, dest, cc)
  1309. c.freeTemp(cc)
  1310. elif {gfAddrOf, gfFieldAccess} * flags == {gfAddrOf}:
  1311. c.gABx(n, opcLdGlobalAddr, dest, s.position)
  1312. else:
  1313. c.gABx(n, opcLdGlobal, dest, s.position)
  1314. else:
  1315. if s.kind == skForVar and c.mode == emRepl: c.setSlot(s)
  1316. if s.position > 0 or (s.position == 0 and
  1317. s.kind in {skParam,skResult}):
  1318. if dest < 0:
  1319. dest = s.position + ord(s.kind == skParam)
  1320. internalAssert(c.prc.slots[dest].kind < slotSomeTemp)
  1321. else:
  1322. # we need to generate an assignment:
  1323. genAsgn(c, dest, n, c.prc.slots[dest].kind >= slotSomeTemp)
  1324. else:
  1325. # see tests/t99bott for an example that triggers it:
  1326. cannotEval(n)
  1327. template needsRegLoad(): untyped =
  1328. gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar}))
  1329. proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
  1330. flags: TGenFlags) =
  1331. let a = c.genx(n.sons[0], flags)
  1332. let b = c.genIndex(n.sons[1], n.sons[0].typ)
  1333. if dest < 0: dest = c.getTemp(n.typ)
  1334. if needsRegLoad():
  1335. var cc = c.getTemp(n.typ)
  1336. c.gABC(n, opc, cc, a, b)
  1337. c.gABC(n, opcNodeToReg, dest, cc)
  1338. c.freeTemp(cc)
  1339. else:
  1340. #message(n.info, warnUser, "argh")
  1341. #echo "FLAGS ", flags, " ", fitsRegister(n.typ), " ", typeToString(n.typ)
  1342. c.gABC(n, opc, dest, a, b)
  1343. c.freeTemp(a)
  1344. c.freeTemp(b)
  1345. proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
  1346. let a = c.genx(n.sons[0], flags)
  1347. let b = genField(n.sons[1])
  1348. if dest < 0: dest = c.getTemp(n.typ)
  1349. if needsRegLoad():
  1350. var cc = c.getTemp(n.typ)
  1351. c.gABC(n, opcLdObj, cc, a, b)
  1352. c.gABC(n, opcNodeToReg, dest, cc)
  1353. c.freeTemp(cc)
  1354. else:
  1355. c.gABC(n, opcLdObj, dest, a, b)
  1356. c.freeTemp(a)
  1357. proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
  1358. # XXX implement field checks!
  1359. genObjAccess(c, n.sons[0], dest, flags)
  1360. proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
  1361. let arrayType = n.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
  1362. if arrayType in {tyString, tyCString}:
  1363. genArrAccess2(c, n, dest, opcLdStrIdx, {})
  1364. elif arrayType == tyTypeDesc:
  1365. c.genTypeLit(n.typ, dest)
  1366. else:
  1367. genArrAccess2(c, n, dest, opcLdArr, flags)
  1368. proc getNullValueAux(obj: PNode, result: PNode) =
  1369. case obj.kind
  1370. of nkRecList:
  1371. for i in countup(0, sonsLen(obj) - 1): getNullValueAux(obj.sons[i], result)
  1372. of nkRecCase:
  1373. getNullValueAux(obj.sons[0], result)
  1374. for i in countup(1, sonsLen(obj) - 1):
  1375. getNullValueAux(lastSon(obj.sons[i]), result)
  1376. of nkSym:
  1377. let field = newNodeI(nkExprColonExpr, result.info)
  1378. field.add(obj)
  1379. field.add(getNullValue(obj.sym.typ, result.info))
  1380. addSon(result, field)
  1381. else: globalError(result.info, "cannot create null element for: " & $obj)
  1382. proc getNullValue(typ: PType, info: TLineInfo): PNode =
  1383. var t = skipTypes(typ, abstractRange-{tyTypeDesc})
  1384. result = emptyNode
  1385. case t.kind
  1386. of tyBool, tyEnum, tyChar, tyInt..tyInt64:
  1387. result = newNodeIT(nkIntLit, info, t)
  1388. of tyUInt..tyUInt64:
  1389. result = newNodeIT(nkUIntLit, info, t)
  1390. of tyFloat..tyFloat128:
  1391. result = newNodeIT(nkFloatLit, info, t)
  1392. of tyCString, tyString:
  1393. result = newNodeIT(nkStrLit, info, t)
  1394. of tyVar, tyPointer, tyPtr, tySequence, tyExpr,
  1395. tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil:
  1396. result = newNodeIT(nkNilLit, info, t)
  1397. of tyProc:
  1398. if t.callConv != ccClosure:
  1399. result = newNodeIT(nkNilLit, info, t)
  1400. else:
  1401. result = newNodeIT(nkPar, info, t)
  1402. result.add(newNodeIT(nkNilLit, info, t))
  1403. result.add(newNodeIT(nkNilLit, info, t))
  1404. of tyObject:
  1405. result = newNodeIT(nkObjConstr, info, t)
  1406. result.add(newNodeIT(nkEmpty, info, t))
  1407. # initialize inherited fields:
  1408. var base = t.sons[0]
  1409. while base != nil:
  1410. getNullValueAux(skipTypes(base, skipPtrs).n, result)
  1411. base = base.sons[0]
  1412. getNullValueAux(t.n, result)
  1413. of tyArray:
  1414. result = newNodeIT(nkBracket, info, t)
  1415. for i in countup(0, int(lengthOrd(t)) - 1):
  1416. addSon(result, getNullValue(elemType(t), info))
  1417. of tyTuple:
  1418. result = newNodeIT(nkPar, info, t)
  1419. for i in countup(0, sonsLen(t) - 1):
  1420. addSon(result, getNullValue(t.sons[i], info))
  1421. of tySet:
  1422. result = newNodeIT(nkCurly, info, t)
  1423. of tyOpt:
  1424. result = newNodeIT(nkNilLit, info, t)
  1425. else:
  1426. globalError(info, "cannot create null element for: " & $t.kind)
  1427. proc ldNullOpcode(t: PType): TOpcode =
  1428. assert t != nil
  1429. if fitsRegister(t): opcLdNullReg else: opcLdNull
  1430. proc genVarSection(c: PCtx; n: PNode) =
  1431. for a in n:
  1432. if a.kind == nkCommentStmt: continue
  1433. #assert(a.sons[0].kind == nkSym) can happen for transformed vars
  1434. if a.kind == nkVarTuple:
  1435. for i in 0 .. a.len-3:
  1436. if not a[i].sym.isGlobal: setSlot(c, a[i].sym)
  1437. checkCanEval(c, a[i])
  1438. c.gen(lowerTupleUnpacking(a, c.getOwner))
  1439. elif a.sons[0].kind == nkSym:
  1440. let s = a.sons[0].sym
  1441. checkCanEval(c, a.sons[0])
  1442. if s.isGlobal:
  1443. if s.position == 0:
  1444. if sfImportc in s.flags: c.importcSym(a.info, s)
  1445. else:
  1446. let sa = getNullValue(s.typ, a.info)
  1447. #if s.ast.isNil: getNullValue(s.typ, a.info)
  1448. #else: canonValue(s.ast)
  1449. assert sa.kind != nkCall
  1450. c.globals.add(sa)
  1451. s.position = c.globals.len
  1452. if a.sons[2].kind != nkEmpty:
  1453. let tmp = c.genx(a.sons[0], {gfAddrOf})
  1454. let val = c.genx(a.sons[2])
  1455. c.genAdditionalCopy(a.sons[2], opcWrDeref, tmp, 0, val)
  1456. c.freeTemp(val)
  1457. c.freeTemp(tmp)
  1458. else:
  1459. setSlot(c, s)
  1460. if a.sons[2].kind == nkEmpty:
  1461. c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ))
  1462. else:
  1463. assert s.typ != nil
  1464. if not fitsRegister(s.typ):
  1465. c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ))
  1466. let le = a.sons[0]
  1467. assert le.typ != nil
  1468. if not fitsRegister(le.typ) and s.kind in {skResult, skVar, skParam}:
  1469. var cc = c.getTemp(le.typ)
  1470. gen(c, a.sons[2], cc)
  1471. c.gABC(le, whichAsgnOpc(le), s.position.TRegister, cc, 1)
  1472. c.freeTemp(cc)
  1473. else:
  1474. gen(c, a.sons[2], s.position.TRegister)
  1475. else:
  1476. # assign to a.sons[0]; happens for closures
  1477. if a.sons[2].kind == nkEmpty:
  1478. let tmp = genx(c, a.sons[0])
  1479. c.gABx(a, ldNullOpcode(a[0].typ), tmp, c.genType(a.sons[0].typ))
  1480. c.freeTemp(tmp)
  1481. else:
  1482. genAsgn(c, a.sons[0], a.sons[2], true)
  1483. proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
  1484. if dest < 0: dest = c.getTemp(n.typ)
  1485. c.gABx(n, opcLdNull, dest, c.genType(n.typ))
  1486. let intType = getSysType(tyInt)
  1487. let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
  1488. if seqType.kind == tySequence:
  1489. var tmp = c.getTemp(intType)
  1490. c.gABx(n, opcLdImmInt, tmp, n.len)
  1491. c.gABx(n, opcNewSeq, dest, c.genType(seqType))
  1492. c.gABx(n, opcNewSeq, tmp, 0)
  1493. c.freeTemp(tmp)
  1494. if n.len > 0:
  1495. var tmp = getTemp(c, intType)
  1496. c.gABx(n, opcLdNullReg, tmp, c.genType(intType))
  1497. for x in n:
  1498. let a = c.genx(x)
  1499. c.preventFalseAlias(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a)
  1500. c.gABI(n, opcAddImmInt, tmp, tmp, 1)
  1501. c.freeTemp(a)
  1502. c.freeTemp(tmp)
  1503. proc genSetConstr(c: PCtx, n: PNode, dest: var TDest) =
  1504. if dest < 0: dest = c.getTemp(n.typ)
  1505. c.gABx(n, opcLdNull, dest, c.genType(n.typ))
  1506. for x in n:
  1507. if x.kind == nkRange:
  1508. let a = c.genx(x.sons[0])
  1509. let b = c.genx(x.sons[1])
  1510. c.gABC(n, opcInclRange, dest, a, b)
  1511. c.freeTemp(b)
  1512. c.freeTemp(a)
  1513. else:
  1514. let a = c.genx(x)
  1515. c.gABC(n, opcIncl, dest, a)
  1516. c.freeTemp(a)
  1517. proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) =
  1518. if dest < 0: dest = c.getTemp(n.typ)
  1519. let t = n.typ.skipTypes(abstractRange-{tyTypeDesc})
  1520. if t.kind == tyRef:
  1521. c.gABx(n, opcNew, dest, c.genType(t.sons[0]))
  1522. else:
  1523. c.gABx(n, opcLdNull, dest, c.genType(n.typ))
  1524. for i in 1.. <n.len:
  1525. let it = n.sons[i]
  1526. if it.kind == nkExprColonExpr and it.sons[0].kind == nkSym:
  1527. let idx = genField(it.sons[0])
  1528. let tmp = c.genx(it.sons[1])
  1529. c.preventFalseAlias(it.sons[1], whichAsgnOpc(it.sons[1], opcWrObj),
  1530. dest, idx, tmp)
  1531. c.freeTemp(tmp)
  1532. else:
  1533. globalError(n.info, "invalid object constructor")
  1534. proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
  1535. if dest < 0: dest = c.getTemp(n.typ)
  1536. c.gABx(n, opcLdNull, dest, c.genType(n.typ))
  1537. # XXX x = (x.old, 22) produces wrong code ... stupid self assignments
  1538. for i in 0.. <n.len:
  1539. let it = n.sons[i]
  1540. if it.kind == nkExprColonExpr:
  1541. let idx = genField(it.sons[0])
  1542. let tmp = c.genx(it.sons[1])
  1543. c.preventFalseAlias(it.sons[1], whichAsgnOpc(it.sons[1], opcWrObj),
  1544. dest, idx, tmp)
  1545. c.freeTemp(tmp)
  1546. else:
  1547. let tmp = c.genx(it)
  1548. c.preventFalseAlias(it, whichAsgnOpc(it, opcWrObj), dest, i.TRegister, tmp)
  1549. c.freeTemp(tmp)
  1550. proc genProc*(c: PCtx; s: PSym): int
  1551. proc matches(s: PSym; x: string): bool =
  1552. let y = x.split('.')
  1553. var s = s
  1554. var L = y.len-1
  1555. while L >= 0:
  1556. if s == nil or (y[L].cmpIgnoreStyle(s.name.s) != 0 and y[L] != "*"):
  1557. return false
  1558. s = s.owner
  1559. dec L
  1560. result = true
  1561. proc matches(s: PSym; y: varargs[string]): bool =
  1562. var s = s
  1563. var L = y.len-1
  1564. while L >= 0:
  1565. if s == nil or (y[L].cmpIgnoreStyle(s.name.s) != 0 and y[L] != "*"):
  1566. return false
  1567. s = if sfFromGeneric in s.flags: s.owner.owner else: s.owner
  1568. dec L
  1569. result = true
  1570. proc procIsCallback(c: PCtx; s: PSym): bool =
  1571. if s.offset < -1: return true
  1572. var i = -2
  1573. for key, value in items(c.callbacks):
  1574. if s.matches(key):
  1575. doAssert s.offset == -1
  1576. s.offset = i
  1577. return true
  1578. dec i
  1579. proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
  1580. case n.kind
  1581. of nkSym:
  1582. let s = n.sym
  1583. checkCanEval(c, n)
  1584. case s.kind
  1585. of skVar, skForVar, skTemp, skLet, skParam, skResult:
  1586. genRdVar(c, n, dest, flags)
  1587. of skProc, skFunc, skConverter, skMacro, skTemplate, skMethod, skIterator:
  1588. # 'skTemplate' is only allowed for 'getAst' support:
  1589. if procIsCallback(c, s): discard
  1590. elif sfImportc in s.flags: c.importcSym(n.info, s)
  1591. genLit(c, n, dest)
  1592. of skConst:
  1593. let constVal = if s.ast != nil: s.ast else: s.typ.n
  1594. gen(c, constVal, dest)
  1595. of skEnumField:
  1596. if dest < 0: dest = c.getTemp(n.typ)
  1597. if s.position >= low(int16) and s.position <= high(int16):
  1598. c.gABx(n, opcLdImmInt, dest, s.position)
  1599. else:
  1600. var lit = genLiteral(c, newIntNode(nkIntLit, s.position))
  1601. c.gABx(n, opcLdConst, dest, lit)
  1602. of skType:
  1603. genTypeLit(c, s.typ, dest)
  1604. of skGenericParam:
  1605. if c.prc.sym != nil and c.prc.sym.kind == skMacro:
  1606. genRdVar(c, n, dest, flags)
  1607. else:
  1608. globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
  1609. else:
  1610. globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
  1611. of nkCallKinds:
  1612. if n.sons[0].kind == nkSym:
  1613. let s = n.sons[0].sym
  1614. if s.magic != mNone:
  1615. genMagic(c, n, dest, s.magic)
  1616. elif matches(s, "stdlib", "marshal", "to"):
  1617. genMarshalLoad(c, n, dest)
  1618. elif matches(s, "stdlib", "marshal", "$$"):
  1619. genMarshalStore(c, n, dest)
  1620. else:
  1621. genCall(c, n, dest)
  1622. clearDest(c, n, dest)
  1623. else:
  1624. genCall(c, n, dest)
  1625. clearDest(c, n, dest)
  1626. of nkCharLit..nkInt64Lit:
  1627. if isInt16Lit(n):
  1628. if dest < 0: dest = c.getTemp(n.typ)
  1629. c.gABx(n, opcLdImmInt, dest, n.intVal.int)
  1630. else:
  1631. genLit(c, n, dest)
  1632. of nkUIntLit..pred(nkNilLit): genLit(c, n, dest)
  1633. of nkNilLit:
  1634. if not n.typ.isEmptyType: genLit(c, getNullValue(n.typ, n.info), dest)
  1635. else: unused(n, dest)
  1636. of nkAsgn, nkFastAsgn:
  1637. unused(n, dest)
  1638. genAsgn(c, n.sons[0], n.sons[1], n.kind == nkAsgn)
  1639. of nkDotExpr: genObjAccess(c, n, dest, flags)
  1640. of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags)
  1641. of nkBracketExpr: genArrAccess(c, n, dest, flags)
  1642. of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcLdDeref, flags)
  1643. of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddrNode, flags)
  1644. of nkIfStmt, nkIfExpr: genIf(c, n, dest)
  1645. of nkWhenStmt:
  1646. # This is "when nimvm" node. Chose the first branch.
  1647. gen(c, n.sons[0].sons[1], dest)
  1648. of nkCaseStmt: genCase(c, n, dest)
  1649. of nkWhileStmt:
  1650. unused(n, dest)
  1651. genWhile(c, n)
  1652. of nkBlockExpr, nkBlockStmt: genBlock(c, n, dest)
  1653. of nkReturnStmt:
  1654. unused(n, dest)
  1655. genReturn(c, n)
  1656. of nkRaiseStmt:
  1657. unused(n, dest)
  1658. genRaise(c, n)
  1659. of nkBreakStmt:
  1660. unused(n, dest)
  1661. genBreak(c, n)
  1662. of nkTryStmt: genTry(c, n, dest)
  1663. of nkStmtList:
  1664. #unused(n, dest)
  1665. # XXX Fix this bug properly, lexim triggers it
  1666. for x in n: gen(c, x)
  1667. of nkStmtListExpr:
  1668. let L = n.len-1
  1669. for i in 0 .. <L: gen(c, n.sons[i])
  1670. gen(c, n.sons[L], dest, flags)
  1671. of nkPragmaBlock:
  1672. gen(c, n.lastSon, dest, flags)
  1673. of nkDiscardStmt:
  1674. unused(n, dest)
  1675. gen(c, n.sons[0])
  1676. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  1677. genConv(c, n, n.sons[1], dest)
  1678. of nkObjDownConv:
  1679. genConv(c, n, n.sons[0], dest)
  1680. of nkVarSection, nkLetSection:
  1681. unused(n, dest)
  1682. genVarSection(c, n)
  1683. of declarativeDefs:
  1684. unused(n, dest)
  1685. of nkLambdaKinds:
  1686. #let s = n.sons[namePos].sym
  1687. #discard genProc(c, s)
  1688. genLit(c, newSymNode(n.sons[namePos].sym), dest)
  1689. of nkChckRangeF, nkChckRange64, nkChckRange:
  1690. let
  1691. tmp0 = c.genx(n.sons[0])
  1692. tmp1 = c.genx(n.sons[1])
  1693. tmp2 = c.genx(n.sons[2])
  1694. c.gABC(n, opcRangeChck, tmp0, tmp1, tmp2)
  1695. c.freeTemp(tmp1)
  1696. c.freeTemp(tmp2)
  1697. if dest >= 0:
  1698. gABC(c, n, whichAsgnOpc(n), dest, tmp0, 1)
  1699. c.freeTemp(tmp0)
  1700. else:
  1701. dest = tmp0
  1702. of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
  1703. nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt:
  1704. unused(n, dest)
  1705. of nkStringToCString, nkCStringToString:
  1706. gen(c, n.sons[0], dest)
  1707. of nkBracket: genArrayConstr(c, n, dest)
  1708. of nkCurly: genSetConstr(c, n, dest)
  1709. of nkObjConstr: genObjConstr(c, n, dest)
  1710. of nkPar, nkClosure: genTupleConstr(c, n, dest)
  1711. of nkCast:
  1712. if allowCast in c.features:
  1713. genConv(c, n, n.sons[1], dest, opcCast)
  1714. else:
  1715. globalError(n.info, errGenerated, "VM is not allowed to 'cast'")
  1716. of nkTypeOfExpr:
  1717. genTypeLit(c, n.typ, dest)
  1718. else:
  1719. globalError(n.info, errGenerated, "cannot generate VM code for " & $n)
  1720. proc removeLastEof(c: PCtx) =
  1721. let last = c.code.len-1
  1722. if last >= 0 and c.code[last].opcode == opcEof:
  1723. # overwrite last EOF:
  1724. assert c.code.len == c.debug.len
  1725. c.code.setLen(last)
  1726. c.debug.setLen(last)
  1727. proc genStmt*(c: PCtx; n: PNode): int =
  1728. c.removeLastEof
  1729. result = c.code.len
  1730. var d: TDest = -1
  1731. c.gen(n, d)
  1732. c.gABC(n, opcEof)
  1733. if d >= 0:
  1734. globalError(n.info, errGenerated, "VM problem: dest register is set")
  1735. proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int =
  1736. c.removeLastEof
  1737. result = c.code.len
  1738. var d: TDest = -1
  1739. c.gen(n, d)
  1740. if d < 0:
  1741. if requiresValue:
  1742. globalError(n.info, errGenerated, "VM problem: dest register is not set")
  1743. d = 0
  1744. c.gABC(n, opcEof, d)
  1745. #echo renderTree(n)
  1746. #c.echoCode(result)
  1747. proc genParams(c: PCtx; params: PNode) =
  1748. # res.sym.position is already 0
  1749. c.prc.slots[0] = (inUse: true, kind: slotFixedVar)
  1750. for i in 1.. <params.len:
  1751. c.prc.slots[i] = (inUse: true, kind: slotFixedLet)
  1752. c.prc.maxSlots = max(params.len, 1)
  1753. proc finalJumpTarget(c: PCtx; pc, diff: int) =
  1754. internalAssert(-0x7fff < diff and diff < 0x7fff)
  1755. let oldInstr = c.code[pc]
  1756. # opcode and regA stay the same:
  1757. c.code[pc] = ((oldInstr.uint32 and 0xffff'u32).uint32 or
  1758. uint32(diff+wordExcess) shl 16'u32).TInstr
  1759. proc genGenericParams(c: PCtx; gp: PNode) =
  1760. var base = c.prc.maxSlots
  1761. for i in 0.. <gp.len:
  1762. var param = gp.sons[i].sym
  1763. param.position = base + i # XXX: fix this earlier; make it consistent with templates
  1764. c.prc.slots[base + i] = (inUse: true, kind: slotFixedLet)
  1765. c.prc.maxSlots = base + gp.len
  1766. proc optimizeJumps(c: PCtx; start: int) =
  1767. const maxIterations = 10
  1768. for i in start .. <c.code.len:
  1769. let opc = c.code[i].opcode
  1770. case opc
  1771. of opcTJmp, opcFJmp:
  1772. var reg = c.code[i].regA
  1773. var d = i + c.code[i].jmpDiff
  1774. for iters in countdown(maxIterations, 0):
  1775. case c.code[d].opcode
  1776. of opcJmp, opcJmpBack:
  1777. d = d + c.code[d].jmpDiff
  1778. of opcTJmp, opcFJmp:
  1779. if c.code[d].regA != reg: break
  1780. # tjmp x, 23
  1781. # ...
  1782. # tjmp x, 12
  1783. # -- we know 'x' is true, and so can jump to 12+13:
  1784. if c.code[d].opcode == opc:
  1785. d = d + c.code[d].jmpDiff
  1786. else:
  1787. # tjmp x, 23
  1788. # fjmp x, 22
  1789. # We know 'x' is true so skip to the next instruction:
  1790. d = d + 1
  1791. else: break
  1792. if d != i + c.code[i].jmpDiff:
  1793. c.finalJumpTarget(i, d - i)
  1794. of opcJmp, opcJmpBack:
  1795. var d = i + c.code[i].jmpDiff
  1796. var iters = maxIterations
  1797. while c.code[d].opcode == opcJmp and iters > 0:
  1798. d = d + c.code[d].jmpDiff
  1799. dec iters
  1800. if c.code[d].opcode == opcRet:
  1801. # optimize 'jmp to ret' to 'ret' here
  1802. c.code[i] = c.code[d]
  1803. elif d != i + c.code[i].jmpDiff:
  1804. c.finalJumpTarget(i, d - i)
  1805. else: discard
  1806. proc genProc(c: PCtx; s: PSym): int =
  1807. var x = s.ast.sons[miscPos]
  1808. if x.kind == nkEmpty or x[0].kind == nkEmpty:
  1809. #if s.name.s == "outterMacro" or s.name.s == "innerProc":
  1810. # echo "GENERATING CODE FOR ", s.name.s
  1811. let last = c.code.len-1
  1812. var eofInstr: TInstr
  1813. if last >= 0 and c.code[last].opcode == opcEof:
  1814. eofInstr = c.code[last]
  1815. c.code.setLen(last)
  1816. c.debug.setLen(last)
  1817. #c.removeLastEof
  1818. result = c.code.len+1 # skip the jump instruction
  1819. if x.kind == nkEmpty:
  1820. x = newTree(nkBracket, newIntNode(nkIntLit, result), ast.emptyNode)
  1821. else:
  1822. x.sons[0] = newIntNode(nkIntLit, result)
  1823. s.ast.sons[miscPos] = x
  1824. # thanks to the jmp we can add top level statements easily and also nest
  1825. # procs easily:
  1826. let body = s.getBody
  1827. let procStart = c.xjmp(body, opcJmp, 0)
  1828. var p = PProc(blocks: @[], sym: s)
  1829. let oldPrc = c.prc
  1830. c.prc = p
  1831. # iterate over the parameters and allocate space for them:
  1832. genParams(c, s.typ.n)
  1833. # allocate additional space for any generically bound parameters
  1834. if s.kind == skMacro and
  1835. sfImmediate notin s.flags and
  1836. s.ast[genericParamsPos].kind != nkEmpty:
  1837. genGenericParams(c, s.ast[genericParamsPos])
  1838. if tfCapturesEnv in s.typ.flags:
  1839. #let env = s.ast.sons[paramsPos].lastSon.sym
  1840. #assert env.position == 2
  1841. c.prc.slots[c.prc.maxSlots] = (inUse: true, kind: slotFixedLet)
  1842. inc c.prc.maxSlots
  1843. gen(c, body)
  1844. # generate final 'return' statement:
  1845. c.gABC(body, opcRet)
  1846. c.patch(procStart)
  1847. c.gABC(body, opcEof, eofInstr.regA)
  1848. c.optimizeJumps(result)
  1849. s.offset = c.prc.maxSlots
  1850. #if s.name.s == "calc":
  1851. # echo renderTree(body)
  1852. # c.echoCode(result)
  1853. c.prc = oldPrc
  1854. else:
  1855. c.prc.maxSlots = s.offset
  1856. result = x[0].intVal.int