xref: /PHP-8.0/ext/opcache/jit/dynasm/dasm_mips.lua (revision 9a068760)
1------------------------------------------------------------------------------
2-- DynASM MIPS32/MIPS64 module.
3--
4-- Copyright (C) 2005-2016 Mike Pall. All rights reserved.
5-- See dynasm.lua for full copyright notice.
6------------------------------------------------------------------------------
7
8local mips64 = mips64
9
10-- Module information:
11local _info = {
12  arch =	mips64 and "mips64" or "mips",
13  description =	"DynASM MIPS32/MIPS64 module",
14  version =	"1.4.0",
15  vernum =	 10400,
16  release =	"2016-05-24",
17  author =	"Mike Pall",
18  license =	"MIT",
19}
20
21-- Exported glue functions for the arch-specific module.
22local _M = { _info = _info }
23
24-- Cache library functions.
25local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
26local assert, setmetatable = assert, setmetatable
27local _s = string
28local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
29local match, gmatch = _s.match, _s.gmatch
30local concat, sort = table.concat, table.sort
31local bit = bit or require("bit")
32local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift
33local tohex = bit.tohex
34
35-- Inherited tables and callbacks.
36local g_opt, g_arch
37local wline, werror, wfatal, wwarn
38
39-- Action name list.
40-- CHECK: Keep this in sync with the C code!
41local action_names = {
42  "STOP", "SECTION", "ESC", "REL_EXT",
43  "ALIGN", "REL_LG", "LABEL_LG",
44  "REL_PC", "LABEL_PC", "IMM", "IMMS",
45}
46
47-- Maximum number of section buffer positions for dasm_put().
48-- CHECK: Keep this in sync with the C code!
49local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
50
51-- Action name -> action number.
52local map_action = {}
53for n,name in ipairs(action_names) do
54  map_action[name] = n-1
55end
56
57-- Action list buffer.
58local actlist = {}
59
60-- Argument list for next dasm_put(). Start with offset 0 into action list.
61local actargs = { 0 }
62
63-- Current number of section buffer positions for dasm_put().
64local secpos = 1
65
66------------------------------------------------------------------------------
67
68-- Dump action names and numbers.
69local function dumpactions(out)
70  out:write("DynASM encoding engine action codes:\n")
71  for n,name in ipairs(action_names) do
72    local num = map_action[name]
73    out:write(format("  %-10s %02X  %d\n", name, num, num))
74  end
75  out:write("\n")
76end
77
78-- Write action list buffer as a huge static C array.
79local function writeactions(out, name)
80  local nn = #actlist
81  if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
82  out:write("static const unsigned int ", name, "[", nn, "] = {\n")
83  for i = 1,nn-1 do
84    assert(out:write("0x", tohex(actlist[i]), ",\n"))
85  end
86  assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
87end
88
89------------------------------------------------------------------------------
90
91-- Add word to action list.
92local function wputxw(n)
93  assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
94  actlist[#actlist+1] = n
95end
96
97-- Add action to list with optional arg. Advance buffer pos, too.
98local function waction(action, val, a, num)
99  local w = assert(map_action[action], "bad action name `"..action.."'")
100  wputxw(0xff000000 + w * 0x10000 + (val or 0))
101  if a then actargs[#actargs+1] = a end
102  if a or num then secpos = secpos + (num or 1) end
103end
104
105-- Flush action list (intervening C code or buffer pos overflow).
106local function wflush(term)
107  if #actlist == actargs[1] then return end -- Nothing to flush.
108  if not term then waction("STOP") end -- Terminate action list.
109  wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
110  actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
111  secpos = 1 -- The actionlist offset occupies a buffer position, too.
112end
113
114-- Put escaped word.
115local function wputw(n)
116  if n >= 0xff000000 then waction("ESC") end
117  wputxw(n)
118end
119
120-- Reserve position for word.
121local function wpos()
122  local pos = #actlist+1
123  actlist[pos] = ""
124  return pos
125end
126
127-- Store word to reserved position.
128local function wputpos(pos, n)
129  assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
130  actlist[pos] = n
131end
132
133------------------------------------------------------------------------------
134
135-- Global label name -> global label number. With auto assignment on 1st use.
136local next_global = 20
137local map_global = setmetatable({}, { __index = function(t, name)
138  if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
139  local n = next_global
140  if n > 2047 then werror("too many global labels") end
141  next_global = n + 1
142  t[name] = n
143  return n
144end})
145
146-- Dump global labels.
147local function dumpglobals(out, lvl)
148  local t = {}
149  for name, n in pairs(map_global) do t[n] = name end
150  out:write("Global labels:\n")
151  for i=20,next_global-1 do
152    out:write(format("  %s\n", t[i]))
153  end
154  out:write("\n")
155end
156
157-- Write global label enum.
158local function writeglobals(out, prefix)
159  local t = {}
160  for name, n in pairs(map_global) do t[n] = name end
161  out:write("enum {\n")
162  for i=20,next_global-1 do
163    out:write("  ", prefix, t[i], ",\n")
164  end
165  out:write("  ", prefix, "_MAX\n};\n")
166end
167
168-- Write global label names.
169local function writeglobalnames(out, name)
170  local t = {}
171  for name, n in pairs(map_global) do t[n] = name end
172  out:write("static const char *const ", name, "[] = {\n")
173  for i=20,next_global-1 do
174    out:write("  \"", t[i], "\",\n")
175  end
176  out:write("  (const char *)0\n};\n")
177end
178
179------------------------------------------------------------------------------
180
181-- Extern label name -> extern label number. With auto assignment on 1st use.
182local next_extern = 0
183local map_extern_ = {}
184local map_extern = setmetatable({}, { __index = function(t, name)
185  -- No restrictions on the name for now.
186  local n = next_extern
187  if n > 2047 then werror("too many extern labels") end
188  next_extern = n + 1
189  t[name] = n
190  map_extern_[n] = name
191  return n
192end})
193
194-- Dump extern labels.
195local function dumpexterns(out, lvl)
196  out:write("Extern labels:\n")
197  for i=0,next_extern-1 do
198    out:write(format("  %s\n", map_extern_[i]))
199  end
200  out:write("\n")
201end
202
203-- Write extern label names.
204local function writeexternnames(out, name)
205  out:write("static const char *const ", name, "[] = {\n")
206  for i=0,next_extern-1 do
207    out:write("  \"", map_extern_[i], "\",\n")
208  end
209  out:write("  (const char *)0\n};\n")
210end
211
212------------------------------------------------------------------------------
213
214-- Arch-specific maps.
215local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name.
216
217local map_type = {}		-- Type name -> { ctype, reg }
218local ctypenum = 0		-- Type number (for Dt... macros).
219
220-- Reverse defines for registers.
221function _M.revdef(s)
222  if s == "r29" then return "sp"
223  elseif s == "r31" then return "ra" end
224  return s
225end
226
227------------------------------------------------------------------------------
228
229-- Template strings for MIPS instructions.
230local map_op = {
231  -- First-level opcodes.
232  j_1 =		"08000000J",
233  jal_1 =	"0c000000J",
234  b_1 =		"10000000B",
235  beqz_2 =	"10000000SB",
236  beq_3 =	"10000000STB",
237  bnez_2 =	"14000000SB",
238  bne_3 =	"14000000STB",
239  blez_2 =	"18000000SB",
240  bgtz_2 =	"1c000000SB",
241  addi_3 =	"20000000TSI",
242  li_2 =	"24000000TI",
243  addiu_3 =	"24000000TSI",
244  slti_3 =	"28000000TSI",
245  sltiu_3 =	"2c000000TSI",
246  andi_3 =	"30000000TSU",
247  lu_2 =	"34000000TU",
248  ori_3 =	"34000000TSU",
249  xori_3 =	"38000000TSU",
250  lui_2 =	"3c000000TU",
251  beqzl_2 =	"50000000SB",
252  beql_3 =	"50000000STB",
253  bnezl_2 =	"54000000SB",
254  bnel_3 =	"54000000STB",
255  blezl_2 =	"58000000SB",
256  bgtzl_2 =	"5c000000SB",
257  daddi_3 =	mips64 and "60000000TSI",
258  daddiu_3 =	mips64 and "64000000TSI",
259  ldl_2 =	mips64 and "68000000TO",
260  ldr_2 =	mips64 and "6c000000TO",
261  lb_2 =	"80000000TO",
262  lh_2 =	"84000000TO",
263  lwl_2 =	"88000000TO",
264  lw_2 =	"8c000000TO",
265  lbu_2 =	"90000000TO",
266  lhu_2 =	"94000000TO",
267  lwr_2 =	"98000000TO",
268  lwu_2 =	mips64 and "9c000000TO",
269  sb_2 =	"a0000000TO",
270  sh_2 =	"a4000000TO",
271  swl_2 =	"a8000000TO",
272  sw_2 =	"ac000000TO",
273  sdl_2 =	mips64 and "b0000000TO",
274  sdr_2 =	mips64 and "b1000000TO",
275  swr_2 =	"b8000000TO",
276  cache_2 =	"bc000000NO",
277  ll_2 =	"c0000000TO",
278  lwc1_2 =	"c4000000HO",
279  pref_2 =	"cc000000NO",
280  ldc1_2 =	"d4000000HO",
281  ld_2 =	mips64 and "dc000000TO",
282  sc_2 =	"e0000000TO",
283  swc1_2 =	"e4000000HO",
284  scd_2 =	mips64 and "f0000000TO",
285  sdc1_2 =	"f4000000HO",
286  sd_2 =	mips64 and "fc000000TO",
287
288  -- Opcode SPECIAL.
289  nop_0 =	"00000000",
290  sll_3 =	"00000000DTA",
291  sextw_2 =	"00000000DT",
292  movf_2 =	"00000001DS",
293  movf_3 =	"00000001DSC",
294  movt_2 =	"00010001DS",
295  movt_3 =	"00010001DSC",
296  srl_3 =	"00000002DTA",
297  rotr_3 =	"00200002DTA",
298  sra_3 =	"00000003DTA",
299  sllv_3 =	"00000004DTS",
300  srlv_3 =	"00000006DTS",
301  rotrv_3 =	"00000046DTS",
302  drotrv_3 =	mips64 and "00000056DTS",
303  srav_3 =	"00000007DTS",
304  jr_1 =	"00000008S",
305  jalr_1 =	"0000f809S",
306  jalr_2 =	"00000009DS",
307  movz_3 =	"0000000aDST",
308  movn_3 =	"0000000bDST",
309  syscall_0 =	"0000000c",
310  syscall_1 =	"0000000cY",
311  break_0 =	"0000000d",
312  break_1 =	"0000000dY",
313  sync_0 =	"0000000f",
314  mfhi_1 =	"00000010D",
315  mthi_1 =	"00000011S",
316  mflo_1 =	"00000012D",
317  mtlo_1 =	"00000013S",
318  dsllv_3 =	mips64 and "00000014DTS",
319  dsrlv_3 =	mips64 and "00000016DTS",
320  dsrav_3 =	mips64 and "00000017DTS",
321  mult_2 =	"00000018ST",
322  multu_2 =	"00000019ST",
323  div_2 =	"0000001aST",
324  divu_2 =	"0000001bST",
325  dmult_2 =	mips64 and "0000001cST",
326  dmultu_2 =	mips64 and "0000001dST",
327  ddiv_2 =	mips64 and "0000001eST",
328  ddivu_2 =	mips64 and "0000001fST",
329  add_3 =	"00000020DST",
330  move_2 =	mips64 and "00000025DS" or "00000021DS",
331  addu_3 =	"00000021DST",
332  sub_3 =	"00000022DST",
333  negu_2 =	mips64 and "0000002fDT" or "00000023DT",
334  subu_3 =	"00000023DST",
335  and_3 =	"00000024DST",
336  or_3 =	"00000025DST",
337  xor_3 =	"00000026DST",
338  not_2 =	"00000027DS",
339  nor_3 =	"00000027DST",
340  slt_3 =	"0000002aDST",
341  sltu_3 =	"0000002bDST",
342  dadd_3 =	mips64 and "0000002cDST",
343  daddu_3 =	mips64 and "0000002dDST",
344  dsub_3 =	mips64 and "0000002eDST",
345  dsubu_3 =	mips64 and "0000002fDST",
346  tge_2 =	"00000030ST",
347  tge_3 =	"00000030STZ",
348  tgeu_2 =	"00000031ST",
349  tgeu_3 =	"00000031STZ",
350  tlt_2 =	"00000032ST",
351  tlt_3 =	"00000032STZ",
352  tltu_2 =	"00000033ST",
353  tltu_3 =	"00000033STZ",
354  teq_2 =	"00000034ST",
355  teq_3 =	"00000034STZ",
356  tne_2 =	"00000036ST",
357  tne_3 =	"00000036STZ",
358  dsll_3 =	mips64 and "00000038DTa",
359  dsrl_3 =	mips64 and "0000003aDTa",
360  drotr_3 =	mips64 and "0020003aDTa",
361  dsra_3 =	mips64 and "0000003bDTa",
362  dsll32_3 =	mips64 and "0000003cDTA",
363  dsrl32_3 =	mips64 and "0000003eDTA",
364  drotr32_3 =	mips64 and "0020003eDTA",
365  dsra32_3 =	mips64 and "0000003fDTA",
366
367  -- Opcode REGIMM.
368  bltz_2 =	"04000000SB",
369  bgez_2 =	"04010000SB",
370  bltzl_2 =	"04020000SB",
371  bgezl_2 =	"04030000SB",
372  tgei_2 =	"04080000SI",
373  tgeiu_2 =	"04090000SI",
374  tlti_2 =	"040a0000SI",
375  tltiu_2 =	"040b0000SI",
376  teqi_2 =	"040c0000SI",
377  tnei_2 =	"040e0000SI",
378  bltzal_2 =	"04100000SB",
379  bal_1 =	"04110000B",
380  bgezal_2 =	"04110000SB",
381  bltzall_2 =	"04120000SB",
382  bgezall_2 =	"04130000SB",
383  synci_1 =	"041f0000O",
384
385  -- Opcode SPECIAL2.
386  madd_2 =	"70000000ST",
387  maddu_2 =	"70000001ST",
388  mul_3 =	"70000002DST",
389  msub_2 =	"70000004ST",
390  msubu_2 =	"70000005ST",
391  clz_2 =	"70000020DS=",
392  clo_2 =	"70000021DS=",
393  dclz_2 =	mips64 and "70000024DS=",
394  dclo_2 =	mips64 and "70000025DS=",
395  sdbbp_0 =	"7000003f",
396  sdbbp_1 =	"7000003fY",
397
398  -- Opcode SPECIAL3.
399  ext_4 =	"7c000000TSAM", -- Note: last arg is msbd = size-1
400  dextm_4 =	mips64 and "7c000001TSAM", -- Args: pos    | size-1-32
401  dextu_4 =	mips64 and "7c000002TSAM", -- Args: pos-32 | size-1
402  dext_4 =	mips64 and "7c000003TSAM", -- Args: pos    | size-1
403  zextw_2 =	mips64 and "7c00f803TS",
404  ins_4 =	"7c000004TSAM", -- Note: last arg is msb = pos+size-1
405  dinsm_4 =	mips64 and "7c000005TSAM", -- Args: pos    | pos+size-33
406  dinsu_4 =	mips64 and "7c000006TSAM", -- Args: pos-32 | pos+size-33
407  dins_4 =	mips64 and "7c000007TSAM", -- Args: pos    | pos+size-1
408  wsbh_2 =	"7c0000a0DT",
409  dsbh_2 =	mips64 and "7c0000a4DT",
410  dshd_2 =	mips64 and "7c000164DT",
411  seb_2 =	"7c000420DT",
412  seh_2 =	"7c000620DT",
413  rdhwr_2 =	"7c00003bTD",
414
415  -- Opcode COP0.
416  mfc0_2 =	"40000000TD",
417  mfc0_3 =	"40000000TDW",
418  dmfc0_2 =	mips64 and "40200000TD",
419  dmfc0_3 =	mips64 and "40200000TDW",
420  mtc0_2 =	"40800000TD",
421  mtc0_3 =	"40800000TDW",
422  dmtc0_2 =	mips64 and "40a00000TD",
423  dmtc0_3 =	mips64 and "40a00000TDW",
424  rdpgpr_2 =	"41400000DT",
425  di_0 =	"41606000",
426  di_1 =	"41606000T",
427  ei_0 =	"41606020",
428  ei_1 =	"41606020T",
429  wrpgpr_2 =	"41c00000DT",
430  tlbr_0 =	"42000001",
431  tlbwi_0 =	"42000002",
432  tlbwr_0 =	"42000006",
433  tlbp_0 =	"42000008",
434  eret_0 =	"42000018",
435  deret_0 =	"4200001f",
436  wait_0 =	"42000020",
437
438  -- Opcode COP1.
439  mfc1_2 =	"44000000TG",
440  dmfc1_2 =	mips64 and "44200000TG",
441  cfc1_2 =	"44400000TG",
442  mfhc1_2 =	"44600000TG",
443  mtc1_2 =	"44800000TG",
444  dmtc1_2 =	mips64 and "44a00000TG",
445  ctc1_2 =	"44c00000TG",
446  mthc1_2 =	"44e00000TG",
447
448  bc1f_1 =	"45000000B",
449  bc1f_2 =	"45000000CB",
450  bc1t_1 =	"45010000B",
451  bc1t_2 =	"45010000CB",
452  bc1fl_1 =	"45020000B",
453  bc1fl_2 =	"45020000CB",
454  bc1tl_1 =	"45030000B",
455  bc1tl_2 =	"45030000CB",
456
457  ["add.s_3"] =		"46000000FGH",
458  ["sub.s_3"] =		"46000001FGH",
459  ["mul.s_3"] =		"46000002FGH",
460  ["div.s_3"] =		"46000003FGH",
461  ["sqrt.s_2"] =	"46000004FG",
462  ["abs.s_2"] =		"46000005FG",
463  ["mov.s_2"] =		"46000006FG",
464  ["neg.s_2"] =		"46000007FG",
465  ["round.l.s_2"] =	"46000008FG",
466  ["trunc.l.s_2"] =	"46000009FG",
467  ["ceil.l.s_2"] =	"4600000aFG",
468  ["floor.l.s_2"] =	"4600000bFG",
469  ["round.w.s_2"] =	"4600000cFG",
470  ["trunc.w.s_2"] =	"4600000dFG",
471  ["ceil.w.s_2"] =	"4600000eFG",
472  ["floor.w.s_2"] =	"4600000fFG",
473  ["movf.s_2"] =	"46000011FG",
474  ["movf.s_3"] =	"46000011FGC",
475  ["movt.s_2"] =	"46010011FG",
476  ["movt.s_3"] =	"46010011FGC",
477  ["movz.s_3"] =	"46000012FGT",
478  ["movn.s_3"] =	"46000013FGT",
479  ["recip.s_2"] =	"46000015FG",
480  ["rsqrt.s_2"] =	"46000016FG",
481  ["cvt.d.s_2"] =	"46000021FG",
482  ["cvt.w.s_2"] =	"46000024FG",
483  ["cvt.l.s_2"] =	"46000025FG",
484  ["cvt.ps.s_3"] =	"46000026FGH",
485  ["c.f.s_2"] =		"46000030GH",
486  ["c.f.s_3"] =		"46000030VGH",
487  ["c.un.s_2"] =	"46000031GH",
488  ["c.un.s_3"] =	"46000031VGH",
489  ["c.eq.s_2"] =	"46000032GH",
490  ["c.eq.s_3"] =	"46000032VGH",
491  ["c.ueq.s_2"] =	"46000033GH",
492  ["c.ueq.s_3"] =	"46000033VGH",
493  ["c.olt.s_2"] =	"46000034GH",
494  ["c.olt.s_3"] =	"46000034VGH",
495  ["c.ult.s_2"] =	"46000035GH",
496  ["c.ult.s_3"] =	"46000035VGH",
497  ["c.ole.s_2"] =	"46000036GH",
498  ["c.ole.s_3"] =	"46000036VGH",
499  ["c.ule.s_2"] =	"46000037GH",
500  ["c.ule.s_3"] =	"46000037VGH",
501  ["c.sf.s_2"] =	"46000038GH",
502  ["c.sf.s_3"] =	"46000038VGH",
503  ["c.ngle.s_2"] =	"46000039GH",
504  ["c.ngle.s_3"] =	"46000039VGH",
505  ["c.seq.s_2"] =	"4600003aGH",
506  ["c.seq.s_3"] =	"4600003aVGH",
507  ["c.ngl.s_2"] =	"4600003bGH",
508  ["c.ngl.s_3"] =	"4600003bVGH",
509  ["c.lt.s_2"] =	"4600003cGH",
510  ["c.lt.s_3"] =	"4600003cVGH",
511  ["c.nge.s_2"] =	"4600003dGH",
512  ["c.nge.s_3"] =	"4600003dVGH",
513  ["c.le.s_2"] =	"4600003eGH",
514  ["c.le.s_3"] =	"4600003eVGH",
515  ["c.ngt.s_2"] =	"4600003fGH",
516  ["c.ngt.s_3"] =	"4600003fVGH",
517
518  ["add.d_3"] =		"46200000FGH",
519  ["sub.d_3"] =		"46200001FGH",
520  ["mul.d_3"] =		"46200002FGH",
521  ["div.d_3"] =		"46200003FGH",
522  ["sqrt.d_2"] =	"46200004FG",
523  ["abs.d_2"] =		"46200005FG",
524  ["mov.d_2"] =		"46200006FG",
525  ["neg.d_2"] =		"46200007FG",
526  ["round.l.d_2"] =	"46200008FG",
527  ["trunc.l.d_2"] =	"46200009FG",
528  ["ceil.l.d_2"] =	"4620000aFG",
529  ["floor.l.d_2"] =	"4620000bFG",
530  ["round.w.d_2"] =	"4620000cFG",
531  ["trunc.w.d_2"] =	"4620000dFG",
532  ["ceil.w.d_2"] =	"4620000eFG",
533  ["floor.w.d_2"] =	"4620000fFG",
534  ["movf.d_2"] =	"46200011FG",
535  ["movf.d_3"] =	"46200011FGC",
536  ["movt.d_2"] =	"46210011FG",
537  ["movt.d_3"] =	"46210011FGC",
538  ["movz.d_3"] =	"46200012FGT",
539  ["movn.d_3"] =	"46200013FGT",
540  ["recip.d_2"] =	"46200015FG",
541  ["rsqrt.d_2"] =	"46200016FG",
542  ["cvt.s.d_2"] =	"46200020FG",
543  ["cvt.w.d_2"] =	"46200024FG",
544  ["cvt.l.d_2"] =	"46200025FG",
545  ["c.f.d_2"] =		"46200030GH",
546  ["c.f.d_3"] =		"46200030VGH",
547  ["c.un.d_2"] =	"46200031GH",
548  ["c.un.d_3"] =	"46200031VGH",
549  ["c.eq.d_2"] =	"46200032GH",
550  ["c.eq.d_3"] =	"46200032VGH",
551  ["c.ueq.d_2"] =	"46200033GH",
552  ["c.ueq.d_3"] =	"46200033VGH",
553  ["c.olt.d_2"] =	"46200034GH",
554  ["c.olt.d_3"] =	"46200034VGH",
555  ["c.ult.d_2"] =	"46200035GH",
556  ["c.ult.d_3"] =	"46200035VGH",
557  ["c.ole.d_2"] =	"46200036GH",
558  ["c.ole.d_3"] =	"46200036VGH",
559  ["c.ule.d_2"] =	"46200037GH",
560  ["c.ule.d_3"] =	"46200037VGH",
561  ["c.sf.d_2"] =	"46200038GH",
562  ["c.sf.d_3"] =	"46200038VGH",
563  ["c.ngle.d_2"] =	"46200039GH",
564  ["c.ngle.d_3"] =	"46200039VGH",
565  ["c.seq.d_2"] =	"4620003aGH",
566  ["c.seq.d_3"] =	"4620003aVGH",
567  ["c.ngl.d_2"] =	"4620003bGH",
568  ["c.ngl.d_3"] =	"4620003bVGH",
569  ["c.lt.d_2"] =	"4620003cGH",
570  ["c.lt.d_3"] =	"4620003cVGH",
571  ["c.nge.d_2"] =	"4620003dGH",
572  ["c.nge.d_3"] =	"4620003dVGH",
573  ["c.le.d_2"] =	"4620003eGH",
574  ["c.le.d_3"] =	"4620003eVGH",
575  ["c.ngt.d_2"] =	"4620003fGH",
576  ["c.ngt.d_3"] =	"4620003fVGH",
577
578  ["add.ps_3"] =	"46c00000FGH",
579  ["sub.ps_3"] =	"46c00001FGH",
580  ["mul.ps_3"] =	"46c00002FGH",
581  ["abs.ps_2"] =	"46c00005FG",
582  ["mov.ps_2"] =	"46c00006FG",
583  ["neg.ps_2"] =	"46c00007FG",
584  ["movf.ps_2"] =	"46c00011FG",
585  ["movf.ps_3"] =	"46c00011FGC",
586  ["movt.ps_2"] =	"46c10011FG",
587  ["movt.ps_3"] =	"46c10011FGC",
588  ["movz.ps_3"] =	"46c00012FGT",
589  ["movn.ps_3"] =	"46c00013FGT",
590  ["cvt.s.pu_2"] =	"46c00020FG",
591  ["cvt.s.pl_2"] =	"46c00028FG",
592  ["pll.ps_3"] =	"46c0002cFGH",
593  ["plu.ps_3"] =	"46c0002dFGH",
594  ["pul.ps_3"] =	"46c0002eFGH",
595  ["puu.ps_3"] =	"46c0002fFGH",
596  ["c.f.ps_2"] =	"46c00030GH",
597  ["c.f.ps_3"] =	"46c00030VGH",
598  ["c.un.ps_2"] =	"46c00031GH",
599  ["c.un.ps_3"] =	"46c00031VGH",
600  ["c.eq.ps_2"] =	"46c00032GH",
601  ["c.eq.ps_3"] =	"46c00032VGH",
602  ["c.ueq.ps_2"] =	"46c00033GH",
603  ["c.ueq.ps_3"] =	"46c00033VGH",
604  ["c.olt.ps_2"] =	"46c00034GH",
605  ["c.olt.ps_3"] =	"46c00034VGH",
606  ["c.ult.ps_2"] =	"46c00035GH",
607  ["c.ult.ps_3"] =	"46c00035VGH",
608  ["c.ole.ps_2"] =	"46c00036GH",
609  ["c.ole.ps_3"] =	"46c00036VGH",
610  ["c.ule.ps_2"] =	"46c00037GH",
611  ["c.ule.ps_3"] =	"46c00037VGH",
612  ["c.sf.ps_2"] =	"46c00038GH",
613  ["c.sf.ps_3"] =	"46c00038VGH",
614  ["c.ngle.ps_2"] =	"46c00039GH",
615  ["c.ngle.ps_3"] =	"46c00039VGH",
616  ["c.seq.ps_2"] =	"46c0003aGH",
617  ["c.seq.ps_3"] =	"46c0003aVGH",
618  ["c.ngl.ps_2"] =	"46c0003bGH",
619  ["c.ngl.ps_3"] =	"46c0003bVGH",
620  ["c.lt.ps_2"] =	"46c0003cGH",
621  ["c.lt.ps_3"] =	"46c0003cVGH",
622  ["c.nge.ps_2"] =	"46c0003dGH",
623  ["c.nge.ps_3"] =	"46c0003dVGH",
624  ["c.le.ps_2"] =	"46c0003eGH",
625  ["c.le.ps_3"] =	"46c0003eVGH",
626  ["c.ngt.ps_2"] =	"46c0003fGH",
627  ["c.ngt.ps_3"] =	"46c0003fVGH",
628
629  ["cvt.s.w_2"] =	"46800020FG",
630  ["cvt.d.w_2"] =	"46800021FG",
631
632  ["cvt.s.l_2"] =	"46a00020FG",
633  ["cvt.d.l_2"] =	"46a00021FG",
634
635  -- Opcode COP1X.
636  lwxc1_2 =		"4c000000FX",
637  ldxc1_2 =		"4c000001FX",
638  luxc1_2 =		"4c000005FX",
639  swxc1_2 =		"4c000008FX",
640  sdxc1_2 =		"4c000009FX",
641  suxc1_2 =		"4c00000dFX",
642  prefx_2 =		"4c00000fMX",
643  ["alnv.ps_4"] =	"4c00001eFGHS",
644  ["madd.s_4"] =	"4c000020FRGH",
645  ["madd.d_4"] =	"4c000021FRGH",
646  ["madd.ps_4"] =	"4c000026FRGH",
647  ["msub.s_4"] =	"4c000028FRGH",
648  ["msub.d_4"] =	"4c000029FRGH",
649  ["msub.ps_4"] =	"4c00002eFRGH",
650  ["nmadd.s_4"] =	"4c000030FRGH",
651  ["nmadd.d_4"] =	"4c000031FRGH",
652  ["nmadd.ps_4"] =	"4c000036FRGH",
653  ["nmsub.s_4"] =	"4c000038FRGH",
654  ["nmsub.d_4"] =	"4c000039FRGH",
655  ["nmsub.ps_4"] =	"4c00003eFRGH",
656}
657
658------------------------------------------------------------------------------
659
660local function parse_gpr(expr)
661  local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$")
662  local tp = map_type[tname or expr]
663  if tp then
664    local reg = ovreg or tp.reg
665    if not reg then
666      werror("type `"..(tname or expr).."' needs a register override")
667    end
668    expr = reg
669  end
670  local r = match(expr, "^r([1-3]?[0-9])$")
671  if r then
672    r = tonumber(r)
673    if r <= 31 then return r, tp end
674  end
675  werror("bad register name `"..expr.."'")
676end
677
678local function parse_fpr(expr)
679  local r = match(expr, "^f([1-3]?[0-9])$")
680  if r then
681    r = tonumber(r)
682    if r <= 31 then return r end
683  end
684  werror("bad register name `"..expr.."'")
685end
686
687local function parse_imm(imm, bits, shift, scale, signed, action)
688  local n = tonumber(imm)
689  if n then
690    local m = sar(n, scale)
691    if shl(m, scale) == n then
692      if signed then
693	local s = sar(m, bits-1)
694	if s == 0 then return shl(m, shift)
695	elseif s == -1 then return shl(m + shl(1, bits), shift) end
696      else
697	if sar(m, bits) == 0 then return shl(m, shift) end
698      end
699    end
700    werror("out of range immediate `"..imm.."'")
701  elseif match(imm, "^[rf]([1-3]?[0-9])$") or
702	 match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then
703    werror("expected immediate operand, got register")
704  else
705    waction(action or "IMM",
706	    (signed and 32768 or 0)+shl(scale, 10)+shl(bits, 5)+shift, imm)
707    return 0
708  end
709end
710
711local function parse_disp(disp)
712  local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$")
713  if imm then
714    local r = shl(parse_gpr(reg), 21)
715    local extname = match(imm, "^extern%s+(%S+)$")
716    if extname then
717      waction("REL_EXT", map_extern[extname], nil, 1)
718      return r
719    else
720      return r + parse_imm(imm, 16, 0, 0, true)
721    end
722  end
723  local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$")
724  if reg and tailr ~= "" then
725    local r, tp = parse_gpr(reg)
726    if tp then
727      waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr))
728      return shl(r, 21)
729    end
730  end
731  werror("bad displacement `"..disp.."'")
732end
733
734local function parse_index(idx)
735  local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$")
736  if rt then
737    rt = parse_gpr(rt)
738    rs = parse_gpr(rs)
739    return shl(rt, 16) + shl(rs, 21)
740  end
741  werror("bad index `"..idx.."'")
742end
743
744local function parse_label(label, def)
745  local prefix = sub(label, 1, 2)
746  -- =>label (pc label reference)
747  if prefix == "=>" then
748    return "PC", 0, sub(label, 3)
749  end
750  -- ->name (global label reference)
751  if prefix == "->" then
752    return "LG", map_global[sub(label, 3)]
753  end
754  if def then
755    -- [1-9] (local label definition)
756    if match(label, "^[1-9]$") then
757      return "LG", 10+tonumber(label)
758    end
759  else
760    -- [<>][1-9] (local label reference)
761    local dir, lnum = match(label, "^([<>])([1-9])$")
762    if dir then -- Fwd: 1-9, Bkwd: 11-19.
763      return "LG", lnum + (dir == ">" and 0 or 10)
764    end
765    -- extern label (extern label reference)
766    local extname = match(label, "^extern%s+(%S+)$")
767    if extname then
768      return "EXT", map_extern[extname]
769    end
770  end
771  werror("bad label `"..label.."'")
772end
773
774------------------------------------------------------------------------------
775
776-- Handle opcodes defined with template strings.
777map_op[".template__"] = function(params, template, nparams)
778  if not params then return sub(template, 9) end
779  local op = tonumber(sub(template, 1, 8), 16)
780  local n = 1
781
782  -- Limit number of section buffer positions used by a single dasm_put().
783  -- A single opcode needs a maximum of 2 positions (ins/ext).
784  if secpos+2 > maxsecpos then wflush() end
785  local pos = wpos()
786
787  -- Process each character.
788  for p in gmatch(sub(template, 9), ".") do
789    if p == "D" then
790      op = op + shl(parse_gpr(params[n]), 11); n = n + 1
791    elseif p == "T" then
792      op = op + shl(parse_gpr(params[n]), 16); n = n + 1
793    elseif p == "S" then
794      op = op + shl(parse_gpr(params[n]), 21); n = n + 1
795    elseif p == "F" then
796      op = op + shl(parse_fpr(params[n]), 6); n = n + 1
797    elseif p == "G" then
798      op = op + shl(parse_fpr(params[n]), 11); n = n + 1
799    elseif p == "H" then
800      op = op + shl(parse_fpr(params[n]), 16); n = n + 1
801    elseif p == "R" then
802      op = op + shl(parse_fpr(params[n]), 21); n = n + 1
803    elseif p == "I" then
804      op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1
805    elseif p == "U" then
806      op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1
807    elseif p == "O" then
808      op = op + parse_disp(params[n]); n = n + 1
809    elseif p == "X" then
810      op = op + parse_index(params[n]); n = n + 1
811    elseif p == "B" or p == "J" then
812      local mode, n, s = parse_label(params[n], false)
813      if p == "B" then n = n + 2048 end
814      waction("REL_"..mode, n, s, 1)
815      n = n + 1
816    elseif p == "A" then
817      op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1
818    elseif p == "a" then
819      local m = parse_imm(params[n], 6, 6, 0, false, "IMMS"); n = n + 1
820      op = op + band(m, 0x7c0) + band(shr(m, 9), 4)
821    elseif p == "M" then
822      op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1
823    elseif p == "N" then
824      op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1
825    elseif p == "C" then
826      op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1
827    elseif p == "V" then
828      op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1
829    elseif p == "W" then
830      op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1
831    elseif p == "Y" then
832      op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1
833    elseif p == "Z" then
834      op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1
835    elseif p == "=" then
836      op = op + shl(band(op, 0xf800), 5) -- Copy D to T for clz, clo.
837    else
838      assert(false)
839    end
840  end
841  wputpos(pos, op)
842end
843
844------------------------------------------------------------------------------
845
846-- Pseudo-opcode to mark the position where the action list is to be emitted.
847map_op[".actionlist_1"] = function(params)
848  if not params then return "cvar" end
849  local name = params[1] -- No syntax check. You get to keep the pieces.
850  wline(function(out) writeactions(out, name) end)
851end
852
853-- Pseudo-opcode to mark the position where the global enum is to be emitted.
854map_op[".globals_1"] = function(params)
855  if not params then return "prefix" end
856  local prefix = params[1] -- No syntax check. You get to keep the pieces.
857  wline(function(out) writeglobals(out, prefix) end)
858end
859
860-- Pseudo-opcode to mark the position where the global names are to be emitted.
861map_op[".globalnames_1"] = function(params)
862  if not params then return "cvar" end
863  local name = params[1] -- No syntax check. You get to keep the pieces.
864  wline(function(out) writeglobalnames(out, name) end)
865end
866
867-- Pseudo-opcode to mark the position where the extern names are to be emitted.
868map_op[".externnames_1"] = function(params)
869  if not params then return "cvar" end
870  local name = params[1] -- No syntax check. You get to keep the pieces.
871  wline(function(out) writeexternnames(out, name) end)
872end
873
874------------------------------------------------------------------------------
875
876-- Label pseudo-opcode (converted from trailing colon form).
877map_op[".label_1"] = function(params)
878  if not params then return "[1-9] | ->global | =>pcexpr" end
879  if secpos+1 > maxsecpos then wflush() end
880  local mode, n, s = parse_label(params[1], true)
881  if mode == "EXT" then werror("bad label definition") end
882  waction("LABEL_"..mode, n, s, 1)
883end
884
885------------------------------------------------------------------------------
886
887-- Pseudo-opcodes for data storage.
888map_op[".long_*"] = function(params)
889  if not params then return "imm..." end
890  for _,p in ipairs(params) do
891    local n = tonumber(p)
892    if not n then werror("bad immediate `"..p.."'") end
893    if n < 0 then n = n + 2^32 end
894    wputw(n)
895    if secpos+2 > maxsecpos then wflush() end
896  end
897end
898
899-- Alignment pseudo-opcode.
900map_op[".align_1"] = function(params)
901  if not params then return "numpow2" end
902  if secpos+1 > maxsecpos then wflush() end
903  local align = tonumber(params[1])
904  if align then
905    local x = align
906    -- Must be a power of 2 in the range (2 ... 256).
907    for i=1,8 do
908      x = x / 2
909      if x == 1 then
910	waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
911	return
912      end
913    end
914  end
915  werror("bad alignment")
916end
917
918------------------------------------------------------------------------------
919
920-- Pseudo-opcode for (primitive) type definitions (map to C types).
921map_op[".type_3"] = function(params, nparams)
922  if not params then
923    return nparams == 2 and "name, ctype" or "name, ctype, reg"
924  end
925  local name, ctype, reg = params[1], params[2], params[3]
926  if not match(name, "^[%a_][%w_]*$") then
927    werror("bad type name `"..name.."'")
928  end
929  local tp = map_type[name]
930  if tp then
931    werror("duplicate type `"..name.."'")
932  end
933  -- Add #type to defines. A bit unclean to put it in map_archdef.
934  map_archdef["#"..name] = "sizeof("..ctype..")"
935  -- Add new type and emit shortcut define.
936  local num = ctypenum + 1
937  map_type[name] = {
938    ctype = ctype,
939    ctypefmt = format("Dt%X(%%s)", num),
940    reg = reg,
941  }
942  wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
943  ctypenum = num
944end
945map_op[".type_2"] = map_op[".type_3"]
946
947-- Dump type definitions.
948local function dumptypes(out, lvl)
949  local t = {}
950  for name in pairs(map_type) do t[#t+1] = name end
951  sort(t)
952  out:write("Type definitions:\n")
953  for _,name in ipairs(t) do
954    local tp = map_type[name]
955    local reg = tp.reg or ""
956    out:write(format("  %-20s %-20s %s\n", name, tp.ctype, reg))
957  end
958  out:write("\n")
959end
960
961------------------------------------------------------------------------------
962
963-- Set the current section.
964function _M.section(num)
965  waction("SECTION", num)
966  wflush(true) -- SECTION is a terminal action.
967end
968
969------------------------------------------------------------------------------
970
971-- Dump architecture description.
972function _M.dumparch(out)
973  out:write(format("DynASM %s version %s, released %s\n\n",
974    _info.arch, _info.version, _info.release))
975  dumpactions(out)
976end
977
978-- Dump all user defined elements.
979function _M.dumpdef(out, lvl)
980  dumptypes(out, lvl)
981  dumpglobals(out, lvl)
982  dumpexterns(out, lvl)
983end
984
985------------------------------------------------------------------------------
986
987-- Pass callbacks from/to the DynASM core.
988function _M.passcb(wl, we, wf, ww)
989  wline, werror, wfatal, wwarn = wl, we, wf, ww
990  return wflush
991end
992
993-- Setup the arch-specific module.
994function _M.setup(arch, opt)
995  g_arch, g_opt = arch, opt
996end
997
998-- Merge the core maps and the arch-specific maps.
999function _M.mergemaps(map_coreop, map_def)
1000  setmetatable(map_op, { __index = map_coreop })
1001  setmetatable(map_def, { __index = map_archdef })
1002  return map_op, map_def
1003end
1004
1005return _M
1006
1007------------------------------------------------------------------------------
1008
1009