beta-0.89.2
[luatex.git] / source / libs / luajit / LuaJIT-src / dynasm / dasm_x86.lua
blob7ca061d22f63c2a421be6636e74abbf35d56d9e7
1 ------------------------------------------------------------------------------
2 -- DynASM x86/x64 module.
3 --
4 -- Copyright (C) 2005-2015 Mike Pall. All rights reserved.
5 -- See dynasm.lua for full copyright notice.
6 ------------------------------------------------------------------------------
8 local x64 = x64
10 -- Module information:
11 local _info = {
12 arch = x64 and "x64" or "x86",
13 description = "DynASM x86/x64 module",
14 version = "1.3.0",
15 vernum = 10300,
16 release = "2011-05-05",
17 author = "Mike Pall",
18 license = "MIT",
21 -- Exported glue functions for the arch-specific module.
22 local _M = { _info = _info }
24 -- Cache library functions.
25 local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
26 local assert, unpack, setmetatable = assert, unpack or table.unpack, setmetatable
27 local _s = string
28 local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
29 local find, match, gmatch, gsub = _s.find, _s.match, _s.gmatch, _s.gsub
30 local concat, sort = table.concat, table.sort
31 local bit = bit or require("bit")
32 local band, shl, shr = bit.band, bit.lshift, bit.rshift
34 -- Inherited tables and callbacks.
35 local g_opt, g_arch
36 local wline, werror, wfatal, wwarn
38 -- Action name list.
39 -- CHECK: Keep this in sync with the C code!
40 local action_names = {
41 -- int arg, 1 buffer pos:
42 "DISP", "IMM_S", "IMM_B", "IMM_W", "IMM_D", "IMM_WB", "IMM_DB",
43 -- action arg (1 byte), int arg, 1 buffer pos (reg/num):
44 "VREG", "SPACE", -- !x64: VREG support NYI.
45 -- ptrdiff_t arg, 1 buffer pos (address): !x64
46 "SETLABEL", "REL_A",
47 -- action arg (1 byte) or int arg, 2 buffer pos (link, offset):
48 "REL_LG", "REL_PC",
49 -- action arg (1 byte) or int arg, 1 buffer pos (link):
50 "IMM_LG", "IMM_PC",
51 -- action arg (1 byte) or int arg, 1 buffer pos (offset):
52 "LABEL_LG", "LABEL_PC",
53 -- action arg (1 byte), 1 buffer pos (offset):
54 "ALIGN",
55 -- action args (2 bytes), no buffer pos.
56 "EXTERN",
57 -- action arg (1 byte), no buffer pos.
58 "ESC",
59 -- no action arg, no buffer pos.
60 "MARK",
61 -- action arg (1 byte), no buffer pos, terminal action:
62 "SECTION",
63 -- no args, no buffer pos, terminal action:
64 "STOP"
67 -- Maximum number of section buffer positions for dasm_put().
68 -- CHECK: Keep this in sync with the C code!
69 local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
71 -- Action name -> action number (dynamically generated below).
72 local map_action = {}
73 -- First action number. Everything below does not need to be escaped.
74 local actfirst = 256-#action_names
76 -- Action list buffer and string (only used to remove dupes).
77 local actlist = {}
78 local actstr = ""
80 -- Argument list for next dasm_put(). Start with offset 0 into action list.
81 local actargs = { 0 }
83 -- Current number of section buffer positions for dasm_put().
84 local secpos = 1
86 ------------------------------------------------------------------------------
88 -- Compute action numbers for action names.
89 for n,name in ipairs(action_names) do
90 local num = actfirst + n - 1
91 map_action[name] = num
92 end
94 -- Dump action names and numbers.
95 local function dumpactions(out)
96 out:write("DynASM encoding engine action codes:\n")
97 for n,name in ipairs(action_names) do
98 local num = map_action[name]
99 out:write(format(" %-10s %02X %d\n", name, num, num))
101 out:write("\n")
104 -- Write action list buffer as a huge static C array.
105 local function writeactions(out, name)
106 local nn = #actlist
107 local last = actlist[nn] or 255
108 actlist[nn] = nil -- Remove last byte.
109 if nn == 0 then nn = 1 end
110 out:write("static const unsigned char ", name, "[", nn, "] = {\n")
111 local s = " "
112 for n,b in ipairs(actlist) do
113 s = s..b..","
114 if #s >= 75 then
115 assert(out:write(s, "\n"))
116 s = " "
119 out:write(s, last, "\n};\n\n") -- Add last byte back.
122 ------------------------------------------------------------------------------
124 -- Add byte to action list.
125 local function wputxb(n)
126 assert(n >= 0 and n <= 255 and n % 1 == 0, "byte out of range")
127 actlist[#actlist+1] = n
130 -- Add action to list with optional arg. Advance buffer pos, too.
131 local function waction(action, a, num)
132 wputxb(assert(map_action[action], "bad action name `"..action.."'"))
133 if a then actargs[#actargs+1] = a end
134 if a or num then secpos = secpos + (num or 1) end
137 -- Add call to embedded DynASM C code.
138 local function wcall(func, args)
139 wline(format("dasm_%s(Dst, %s);", func, concat(args, ", ")), true)
142 -- Delete duplicate action list chunks. A tad slow, but so what.
143 local function dedupechunk(offset)
144 local al, as = actlist, actstr
145 local chunk = char(unpack(al, offset+1, #al))
146 local orig = find(as, chunk, 1, true)
147 if orig then
148 actargs[1] = orig-1 -- Replace with original offset.
149 for i=offset+1,#al do al[i] = nil end -- Kill dupe.
150 else
151 actstr = as..chunk
155 -- Flush action list (intervening C code or buffer pos overflow).
156 local function wflush(term)
157 local offset = actargs[1]
158 if #actlist == offset then return end -- Nothing to flush.
159 if not term then waction("STOP") end -- Terminate action list.
160 dedupechunk(offset)
161 wcall("put", actargs) -- Add call to dasm_put().
162 actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
163 secpos = 1 -- The actionlist offset occupies a buffer position, too.
166 -- Put escaped byte.
167 local function wputb(n)
168 if n >= actfirst then waction("ESC") end -- Need to escape byte.
169 wputxb(n)
172 ------------------------------------------------------------------------------
174 -- Global label name -> global label number. With auto assignment on 1st use.
175 local next_global = 10
176 local map_global = setmetatable({}, { __index = function(t, name)
177 if not match(name, "^[%a_][%w_@]*$") then werror("bad global label") end
178 local n = next_global
179 if n > 246 then werror("too many global labels") end
180 next_global = n + 1
181 t[name] = n
182 return n
183 end})
185 -- Dump global labels.
186 local function dumpglobals(out, lvl)
187 local t = {}
188 for name, n in pairs(map_global) do t[n] = name end
189 out:write("Global labels:\n")
190 for i=10,next_global-1 do
191 out:write(format(" %s\n", t[i]))
193 out:write("\n")
196 -- Write global label enum.
197 local function writeglobals(out, prefix)
198 local t = {}
199 for name, n in pairs(map_global) do t[n] = name end
200 out:write("enum {\n")
201 for i=10,next_global-1 do
202 out:write(" ", prefix, gsub(t[i], "@.*", ""), ",\n")
204 out:write(" ", prefix, "_MAX\n};\n")
207 -- Write global label names.
208 local function writeglobalnames(out, name)
209 local t = {}
210 for name, n in pairs(map_global) do t[n] = name end
211 out:write("static const char *const ", name, "[] = {\n")
212 for i=10,next_global-1 do
213 out:write(" \"", t[i], "\",\n")
215 out:write(" (const char *)0\n};\n")
218 ------------------------------------------------------------------------------
220 -- Extern label name -> extern label number. With auto assignment on 1st use.
221 local next_extern = -1
222 local map_extern = setmetatable({}, { __index = function(t, name)
223 -- No restrictions on the name for now.
224 local n = next_extern
225 if n < -256 then werror("too many extern labels") end
226 next_extern = n - 1
227 t[name] = n
228 return n
229 end})
231 -- Dump extern labels.
232 local function dumpexterns(out, lvl)
233 local t = {}
234 for name, n in pairs(map_extern) do t[-n] = name end
235 out:write("Extern labels:\n")
236 for i=1,-next_extern-1 do
237 out:write(format(" %s\n", t[i]))
239 out:write("\n")
242 -- Write extern label names.
243 local function writeexternnames(out, name)
244 local t = {}
245 for name, n in pairs(map_extern) do t[-n] = name end
246 out:write("static const char *const ", name, "[] = {\n")
247 for i=1,-next_extern-1 do
248 out:write(" \"", t[i], "\",\n")
250 out:write(" (const char *)0\n};\n")
253 ------------------------------------------------------------------------------
255 -- Arch-specific maps.
256 local map_archdef = {} -- Ext. register name -> int. name.
257 local map_reg_rev = {} -- Int. register name -> ext. name.
258 local map_reg_num = {} -- Int. register name -> register number.
259 local map_reg_opsize = {} -- Int. register name -> operand size.
260 local map_reg_valid_base = {} -- Int. register name -> valid base register?
261 local map_reg_valid_index = {} -- Int. register name -> valid index register?
262 local map_reg_needrex = {} -- Int. register name -> need rex vs. no rex.
263 local reg_list = {} -- Canonical list of int. register names.
265 local map_type = {} -- Type name -> { ctype, reg }
266 local ctypenum = 0 -- Type number (for _PTx macros).
268 local addrsize = x64 and "q" or "d" -- Size for address operands.
270 -- Helper functions to fill register maps.
271 local function mkrmap(sz, cl, names)
272 local cname = format("@%s", sz)
273 reg_list[#reg_list+1] = cname
274 map_archdef[cl] = cname
275 map_reg_rev[cname] = cl
276 map_reg_num[cname] = -1
277 map_reg_opsize[cname] = sz
278 if sz == addrsize or sz == "d" then
279 map_reg_valid_base[cname] = true
280 map_reg_valid_index[cname] = true
282 if names then
283 for n,name in ipairs(names) do
284 local iname = format("@%s%x", sz, n-1)
285 reg_list[#reg_list+1] = iname
286 map_archdef[name] = iname
287 map_reg_rev[iname] = name
288 map_reg_num[iname] = n-1
289 map_reg_opsize[iname] = sz
290 if sz == "b" and n > 4 then map_reg_needrex[iname] = false end
291 if sz == addrsize or sz == "d" then
292 map_reg_valid_base[iname] = true
293 map_reg_valid_index[iname] = true
297 for i=0,(x64 and sz ~= "f") and 15 or 7 do
298 local needrex = sz == "b" and i > 3
299 local iname = format("@%s%x%s", sz, i, needrex and "R" or "")
300 if needrex then map_reg_needrex[iname] = true end
301 local name
302 if sz == "o" then name = format("xmm%d", i)
303 elseif sz == "f" then name = format("st%d", i)
304 else name = format("r%d%s", i, sz == addrsize and "" or sz) end
305 map_archdef[name] = iname
306 if not map_reg_rev[iname] then
307 reg_list[#reg_list+1] = iname
308 map_reg_rev[iname] = name
309 map_reg_num[iname] = i
310 map_reg_opsize[iname] = sz
311 if sz == addrsize or sz == "d" then
312 map_reg_valid_base[iname] = true
313 map_reg_valid_index[iname] = true
317 reg_list[#reg_list+1] = ""
320 -- Integer registers (qword, dword, word and byte sized).
321 if x64 then
322 mkrmap("q", "Rq", {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"})
324 mkrmap("d", "Rd", {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"})
325 mkrmap("w", "Rw", {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"})
326 mkrmap("b", "Rb", {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"})
327 map_reg_valid_index[map_archdef.esp] = false
328 if x64 then map_reg_valid_index[map_archdef.rsp] = false end
329 map_archdef["Ra"] = "@"..addrsize
331 -- FP registers (internally tword sized, but use "f" as operand size).
332 mkrmap("f", "Rf")
334 -- SSE registers (oword sized, but qword and dword accessible).
335 mkrmap("o", "xmm")
337 -- Operand size prefixes to codes.
338 local map_opsize = {
339 byte = "b", word = "w", dword = "d", qword = "q", oword = "o", tword = "t",
340 aword = addrsize,
343 -- Operand size code to number.
344 local map_opsizenum = {
345 b = 1, w = 2, d = 4, q = 8, o = 16, t = 10,
348 -- Operand size code to name.
349 local map_opsizename = {
350 b = "byte", w = "word", d = "dword", q = "qword", o = "oword", t = "tword",
351 f = "fpword",
354 -- Valid index register scale factors.
355 local map_xsc = {
356 ["1"] = 0, ["2"] = 1, ["4"] = 2, ["8"] = 3,
359 -- Condition codes.
360 local map_cc = {
361 o = 0, no = 1, b = 2, nb = 3, e = 4, ne = 5, be = 6, nbe = 7,
362 s = 8, ns = 9, p = 10, np = 11, l = 12, nl = 13, le = 14, nle = 15,
363 c = 2, nae = 2, nc = 3, ae = 3, z = 4, nz = 5, na = 6, a = 7,
364 pe = 10, po = 11, nge = 12, ge = 13, ng = 14, g = 15,
368 -- Reverse defines for registers.
369 function _M.revdef(s)
370 return gsub(s, "@%w+", map_reg_rev)
373 -- Dump register names and numbers
374 local function dumpregs(out)
375 out:write("Register names, sizes and internal numbers:\n")
376 for _,reg in ipairs(reg_list) do
377 if reg == "" then
378 out:write("\n")
379 else
380 local name = map_reg_rev[reg]
381 local num = map_reg_num[reg]
382 local opsize = map_opsizename[map_reg_opsize[reg]]
383 out:write(format(" %-5s %-8s %s\n", name, opsize,
384 num < 0 and "(variable)" or num))
389 ------------------------------------------------------------------------------
391 -- Put action for label arg (IMM_LG, IMM_PC, REL_LG, REL_PC).
392 local function wputlabel(aprefix, imm, num)
393 if type(imm) == "number" then
394 if imm < 0 then
395 waction("EXTERN")
396 wputxb(aprefix == "IMM_" and 0 or 1)
397 imm = -imm-1
398 else
399 waction(aprefix.."LG", nil, num);
401 wputxb(imm)
402 else
403 waction(aprefix.."PC", imm, num)
407 -- Put signed byte or arg.
408 local function wputsbarg(n)
409 if type(n) == "number" then
410 if n < -128 or n > 127 then
411 werror("signed immediate byte out of range")
413 if n < 0 then n = n + 256 end
414 wputb(n)
415 else waction("IMM_S", n) end
418 -- Put unsigned byte or arg.
419 local function wputbarg(n)
420 if type(n) == "number" then
421 if n < 0 or n > 255 then
422 werror("unsigned immediate byte out of range")
424 wputb(n)
425 else waction("IMM_B", n) end
428 -- Put unsigned word or arg.
429 local function wputwarg(n)
430 if type(n) == "number" then
431 if shr(n, 16) ~= 0 then
432 werror("unsigned immediate word out of range")
434 wputb(band(n, 255)); wputb(shr(n, 8));
435 else waction("IMM_W", n) end
438 -- Put signed or unsigned dword or arg.
439 local function wputdarg(n)
440 local tn = type(n)
441 if tn == "number" then
442 wputb(band(n, 255))
443 wputb(band(shr(n, 8), 255))
444 wputb(band(shr(n, 16), 255))
445 wputb(shr(n, 24))
446 elseif tn == "table" then
447 wputlabel("IMM_", n[1], 1)
448 else
449 waction("IMM_D", n)
453 -- Put operand-size dependent number or arg (defaults to dword).
454 local function wputszarg(sz, n)
455 if not sz or sz == "d" or sz == "q" then wputdarg(n)
456 elseif sz == "w" then wputwarg(n)
457 elseif sz == "b" then wputbarg(n)
458 elseif sz == "s" then wputsbarg(n)
459 else werror("bad operand size") end
462 -- Put multi-byte opcode with operand-size dependent modifications.
463 local function wputop(sz, op, rex)
464 local r
465 if rex ~= 0 and not x64 then werror("bad operand size") end
466 if sz == "w" then wputb(102) end
467 -- Needs >32 bit numbers, but only for crc32 eax, word [ebx]
468 if op >= 4294967296 then r = op%4294967296 wputb((op-r)/4294967296) op = r end
469 if op >= 16777216 then wputb(shr(op, 24)); op = band(op, 0xffffff) end
470 if op >= 65536 then
471 if rex ~= 0 then
472 local opc3 = band(op, 0xffff00)
473 if opc3 == 0x0f3a00 or opc3 == 0x0f3800 then
474 wputb(64 + band(rex, 15)); rex = 0
477 wputb(shr(op, 16)); op = band(op, 0xffff)
479 if op >= 256 then
480 local b = shr(op, 8)
481 if b == 15 and rex ~= 0 then wputb(64 + band(rex, 15)); rex = 0 end
482 wputb(b)
483 op = band(op, 255)
485 if rex ~= 0 then wputb(64 + band(rex, 15)) end
486 if sz == "b" then op = op - 1 end
487 wputb(op)
490 -- Put ModRM or SIB formatted byte.
491 local function wputmodrm(m, s, rm, vs, vrm)
492 assert(m < 4 and s < 16 and rm < 16, "bad modrm operands")
493 wputb(shl(m, 6) + shl(band(s, 7), 3) + band(rm, 7))
496 -- Put ModRM/SIB plus optional displacement.
497 local function wputmrmsib(t, imark, s, vsreg)
498 local vreg, vxreg
499 local reg, xreg = t.reg, t.xreg
500 if reg and reg < 0 then reg = 0; vreg = t.vreg end
501 if xreg and xreg < 0 then xreg = 0; vxreg = t.vxreg end
502 if s < 0 then s = 0 end
504 -- Register mode.
505 if sub(t.mode, 1, 1) == "r" then
506 wputmodrm(3, s, reg)
507 if vsreg then waction("VREG", vsreg); wputxb(2) end
508 if vreg then waction("VREG", vreg); wputxb(0) end
509 return
512 local disp = t.disp
513 local tdisp = type(disp)
514 -- No base register?
515 if not reg then
516 local riprel = false
517 if xreg then
518 -- Indexed mode with index register only.
519 -- [xreg*xsc+disp] -> (0, s, esp) (xsc, xreg, ebp)
520 wputmodrm(0, s, 4)
521 if imark == "I" then waction("MARK") end
522 if vsreg then waction("VREG", vsreg); wputxb(2) end
523 wputmodrm(t.xsc, xreg, 5)
524 if vxreg then waction("VREG", vxreg); wputxb(3) end
525 else
526 -- Pure 32 bit displacement.
527 if x64 and tdisp ~= "table" then
528 wputmodrm(0, s, 4) -- [disp] -> (0, s, esp) (0, esp, ebp)
529 if imark == "I" then waction("MARK") end
530 wputmodrm(0, 4, 5)
531 else
532 riprel = x64
533 wputmodrm(0, s, 5) -- [disp|rip-label] -> (0, s, ebp)
534 if imark == "I" then waction("MARK") end
536 if vsreg then waction("VREG", vsreg); wputxb(2) end
538 if riprel then -- Emit rip-relative displacement.
539 if match("UWSiI", imark) then
540 werror("NYI: rip-relative displacement followed by immediate")
542 -- The previous byte in the action buffer cannot be 0xe9 or 0x80-0x8f.
543 wputlabel("REL_", disp[1], 2)
544 else
545 wputdarg(disp)
547 return
550 local m
551 if tdisp == "number" then -- Check displacement size at assembly time.
552 if disp == 0 and band(reg, 7) ~= 5 then -- [ebp] -> [ebp+0] (in SIB, too)
553 if not vreg then m = 0 end -- Force DISP to allow [Rd(5)] -> [ebp+0]
554 elseif disp >= -128 and disp <= 127 then m = 1
555 else m = 2 end
556 elseif tdisp == "table" then
557 m = 2
560 -- Index register present or esp as base register: need SIB encoding.
561 if xreg or band(reg, 7) == 4 then
562 wputmodrm(m or 2, s, 4) -- ModRM.
563 if m == nil or imark == "I" then waction("MARK") end
564 if vsreg then waction("VREG", vsreg); wputxb(2) end
565 wputmodrm(t.xsc or 0, xreg or 4, reg) -- SIB.
566 if vxreg then waction("VREG", vxreg); wputxb(3) end
567 if vreg then waction("VREG", vreg); wputxb(1) end
568 else
569 wputmodrm(m or 2, s, reg) -- ModRM.
570 if (imark == "I" and (m == 1 or m == 2)) or
571 (m == nil and (vsreg or vreg)) then waction("MARK") end
572 if vsreg then waction("VREG", vsreg); wputxb(2) end
573 if vreg then waction("VREG", vreg); wputxb(1) end
576 -- Put displacement.
577 if m == 1 then wputsbarg(disp)
578 elseif m == 2 then wputdarg(disp)
579 elseif m == nil then waction("DISP", disp) end
582 ------------------------------------------------------------------------------
584 -- Return human-readable operand mode string.
585 local function opmodestr(op, args)
586 local m = {}
587 for i=1,#args do
588 local a = args[i]
589 m[#m+1] = sub(a.mode, 1, 1)..(a.opsize or "?")
591 return op.." "..concat(m, ",")
594 -- Convert number to valid integer or nil.
595 local function toint(expr)
596 local n = tonumber(expr)
597 if n then
598 if n % 1 ~= 0 or n < -2147483648 or n > 4294967295 then
599 werror("bad integer number `"..expr.."'")
601 return n
605 -- Parse immediate expression.
606 local function immexpr(expr)
607 -- &expr (pointer)
608 if sub(expr, 1, 1) == "&" then
609 return "iPJ", format("(ptrdiff_t)(%s)", sub(expr,2))
612 local prefix = sub(expr, 1, 2)
613 -- =>expr (pc label reference)
614 if prefix == "=>" then
615 return "iJ", sub(expr, 3)
617 -- ->name (global label reference)
618 if prefix == "->" then
619 return "iJ", map_global[sub(expr, 3)]
622 -- [<>][1-9] (local label reference)
623 local dir, lnum = match(expr, "^([<>])([1-9])$")
624 if dir then -- Fwd: 247-255, Bkwd: 1-9.
625 return "iJ", lnum + (dir == ">" and 246 or 0)
628 local extname = match(expr, "^extern%s+(%S+)$")
629 if extname then
630 return "iJ", map_extern[extname]
633 -- expr (interpreted as immediate)
634 return "iI", expr
637 -- Parse displacement expression: +-num, +-expr, +-opsize*num
638 local function dispexpr(expr)
639 local disp = expr == "" and 0 or toint(expr)
640 if disp then return disp end
641 local c, dispt = match(expr, "^([+-])%s*(.+)$")
642 if c == "+" then
643 expr = dispt
644 elseif not c then
645 werror("bad displacement expression `"..expr.."'")
647 local opsize, tailops = match(dispt, "^(%w+)%s*%*%s*(.+)$")
648 local ops, imm = map_opsize[opsize], toint(tailops)
649 if ops and imm then
650 if c == "-" then imm = -imm end
651 return imm*map_opsizenum[ops]
653 local mode, iexpr = immexpr(dispt)
654 if mode == "iJ" then
655 if c == "-" then werror("cannot invert label reference") end
656 return { iexpr }
658 return expr -- Need to return original signed expression.
661 -- Parse register or type expression.
662 local function rtexpr(expr)
663 if not expr then return end
664 local tname, ovreg = match(expr, "^([%w_]+):(@[%w_]+)$")
665 local tp = map_type[tname or expr]
666 if tp then
667 local reg = ovreg or tp.reg
668 local rnum = map_reg_num[reg]
669 if not rnum then
670 werror("type `"..(tname or expr).."' needs a register override")
672 if not map_reg_valid_base[reg] then
673 werror("bad base register override `"..(map_reg_rev[reg] or reg).."'")
675 return reg, rnum, tp
677 return expr, map_reg_num[expr]
680 -- Parse operand and return { mode, opsize, reg, xreg, xsc, disp, imm }.
681 local function parseoperand(param)
682 local t = {}
684 local expr = param
685 local opsize, tailops = match(param, "^(%w+)%s*(.+)$")
686 if opsize then
687 t.opsize = map_opsize[opsize]
688 if t.opsize then expr = tailops end
691 local br = match(expr, "^%[%s*(.-)%s*%]$")
692 repeat
693 if br then
694 t.mode = "xm"
696 -- [disp]
697 t.disp = toint(br)
698 if t.disp then
699 t.mode = x64 and "xm" or "xmO"
700 break
703 -- [reg...]
704 local tp
705 local reg, tailr = match(br, "^([@%w_:]+)%s*(.*)$")
706 reg, t.reg, tp = rtexpr(reg)
707 if not t.reg then
708 -- [expr]
709 t.mode = x64 and "xm" or "xmO"
710 t.disp = dispexpr("+"..br)
711 break
714 if t.reg == -1 then
715 t.vreg, tailr = match(tailr, "^(%b())(.*)$")
716 if not t.vreg then werror("bad variable register expression") end
719 -- [xreg*xsc] or [xreg*xsc+-disp] or [xreg*xsc+-expr]
720 local xsc, tailsc = match(tailr, "^%*%s*([1248])%s*(.*)$")
721 if xsc then
722 if not map_reg_valid_index[reg] then
723 werror("bad index register `"..map_reg_rev[reg].."'")
725 t.xsc = map_xsc[xsc]
726 t.xreg = t.reg
727 t.vxreg = t.vreg
728 t.reg = nil
729 t.vreg = nil
730 t.disp = dispexpr(tailsc)
731 break
733 if not map_reg_valid_base[reg] then
734 werror("bad base register `"..map_reg_rev[reg].."'")
737 -- [reg] or [reg+-disp]
738 t.disp = toint(tailr) or (tailr == "" and 0)
739 if t.disp then break end
741 -- [reg+xreg...]
742 local xreg, tailx = match(tailr, "^+%s*([@%w_:]+)%s*(.*)$")
743 xreg, t.xreg, tp = rtexpr(xreg)
744 if not t.xreg then
745 -- [reg+-expr]
746 t.disp = dispexpr(tailr)
747 break
749 if not map_reg_valid_index[xreg] then
750 werror("bad index register `"..map_reg_rev[xreg].."'")
753 if t.xreg == -1 then
754 t.vxreg, tailx = match(tailx, "^(%b())(.*)$")
755 if not t.vxreg then werror("bad variable register expression") end
758 -- [reg+xreg*xsc...]
759 local xsc, tailsc = match(tailx, "^%*%s*([1248])%s*(.*)$")
760 if xsc then
761 t.xsc = map_xsc[xsc]
762 tailx = tailsc
765 -- [...] or [...+-disp] or [...+-expr]
766 t.disp = dispexpr(tailx)
767 else
768 -- imm or opsize*imm
769 local imm = toint(expr)
770 if not imm and sub(expr, 1, 1) == "*" and t.opsize then
771 imm = toint(sub(expr, 2))
772 if imm then
773 imm = imm * map_opsizenum[t.opsize]
774 t.opsize = nil
777 if imm then
778 if t.opsize then werror("bad operand size override") end
779 local m = "i"
780 if imm == 1 then m = m.."1" end
781 if imm >= 4294967168 and imm <= 4294967295 then imm = imm-4294967296 end
782 if imm >= -128 and imm <= 127 then m = m.."S" end
783 t.imm = imm
784 t.mode = m
785 break
788 local tp
789 local reg, tailr = match(expr, "^([@%w_:]+)%s*(.*)$")
790 reg, t.reg, tp = rtexpr(reg)
791 if t.reg then
792 if t.reg == -1 then
793 t.vreg, tailr = match(tailr, "^(%b())(.*)$")
794 if not t.vreg then werror("bad variable register expression") end
796 -- reg
797 if tailr == "" then
798 if t.opsize then werror("bad operand size override") end
799 t.opsize = map_reg_opsize[reg]
800 if t.opsize == "f" then
801 t.mode = t.reg == 0 and "fF" or "f"
802 else
803 if reg == "@w4" or (x64 and reg == "@d4") then
804 wwarn("bad idea, try again with `"..(x64 and "rsp'" or "esp'"))
806 t.mode = t.reg == 0 and "rmR" or (reg == "@b1" and "rmC" or "rm")
808 t.needrex = map_reg_needrex[reg]
809 break
812 -- type[idx], type[idx].field, type->field -> [reg+offset_expr]
813 if not tp then werror("bad operand `"..param.."'") end
814 t.mode = "xm"
815 t.disp = format(tp.ctypefmt, tailr)
816 else
817 t.mode, t.imm = immexpr(expr)
818 if sub(t.mode, -1) == "J" then
819 if t.opsize and t.opsize ~= addrsize then
820 werror("bad operand size override")
822 t.opsize = addrsize
826 until true
827 return t
830 ------------------------------------------------------------------------------
831 -- x86 Template String Description
832 -- ===============================
834 -- Each template string is a list of [match:]pattern pairs,
835 -- separated by "|". The first match wins. No match means a
836 -- bad or unsupported combination of operand modes or sizes.
838 -- The match part and the ":" is omitted if the operation has
839 -- no operands. Otherwise the first N characters are matched
840 -- against the mode strings of each of the N operands.
842 -- The mode string for each operand type is (see parseoperand()):
843 -- Integer register: "rm", +"R" for eax, ax, al, +"C" for cl
844 -- FP register: "f", +"F" for st0
845 -- Index operand: "xm", +"O" for [disp] (pure offset)
846 -- Immediate: "i", +"S" for signed 8 bit, +"1" for 1,
847 -- +"I" for arg, +"P" for pointer
848 -- Any: +"J" for valid jump targets
850 -- So a match character "m" (mixed) matches both an integer register
851 -- and an index operand (to be encoded with the ModRM/SIB scheme).
852 -- But "r" matches only a register and "x" only an index operand
853 -- (e.g. for FP memory access operations).
855 -- The operand size match string starts right after the mode match
856 -- characters and ends before the ":". "dwb" or "qdwb" is assumed, if empty.
857 -- The effective data size of the operation is matched against this list.
859 -- If only the regular "b", "w", "d", "q", "t" operand sizes are
860 -- present, then all operands must be the same size. Unspecified sizes
861 -- are ignored, but at least one operand must have a size or the pattern
862 -- won't match (use the "byte", "word", "dword", "qword", "tword"
863 -- operand size overrides. E.g.: mov dword [eax], 1).
865 -- If the list has a "1" or "2" prefix, the operand size is taken
866 -- from the respective operand and any other operand sizes are ignored.
867 -- If the list contains only ".", all operand sizes are ignored.
868 -- If the list has a "/" prefix, the concatenated (mixed) operand sizes
869 -- are compared to the match.
871 -- E.g. "rrdw" matches for either two dword registers or two word
872 -- registers. "Fx2dq" matches an st0 operand plus an index operand
873 -- pointing to a dword (float) or qword (double).
875 -- Every character after the ":" is part of the pattern string:
876 -- Hex chars are accumulated to form the opcode (left to right).
877 -- "n" disables the standard opcode mods
878 -- (otherwise: -1 for "b", o16 prefix for "w", rex.w for "q")
879 -- "X" Force REX.W.
880 -- "r"/"R" adds the reg. number from the 1st/2nd operand to the opcode.
881 -- "m"/"M" generates ModRM/SIB from the 1st/2nd operand.
882 -- The spare 3 bits are either filled with the last hex digit or
883 -- the result from a previous "r"/"R". The opcode is restored.
885 -- All of the following characters force a flush of the opcode:
886 -- "o"/"O" stores a pure 32 bit disp (offset) from the 1st/2nd operand.
887 -- "S" stores a signed 8 bit immediate from the last operand.
888 -- "U" stores an unsigned 8 bit immediate from the last operand.
889 -- "W" stores an unsigned 16 bit immediate from the last operand.
890 -- "i" stores an operand sized immediate from the last operand.
891 -- "I" dito, but generates an action code to optionally modify
892 -- the opcode (+2) for a signed 8 bit immediate.
893 -- "J" generates one of the REL action codes from the last operand.
895 ------------------------------------------------------------------------------
897 -- Template strings for x86 instructions. Ordered by first opcode byte.
898 -- Unimplemented opcodes (deliberate omissions) are marked with *.
899 local map_op = {
900 -- 00-05: add...
901 -- 06: *push es
902 -- 07: *pop es
903 -- 08-0D: or...
904 -- 0E: *push cs
905 -- 0F: two byte opcode prefix
906 -- 10-15: adc...
907 -- 16: *push ss
908 -- 17: *pop ss
909 -- 18-1D: sbb...
910 -- 1E: *push ds
911 -- 1F: *pop ds
912 -- 20-25: and...
913 es_0 = "26",
914 -- 27: *daa
915 -- 28-2D: sub...
916 cs_0 = "2E",
917 -- 2F: *das
918 -- 30-35: xor...
919 ss_0 = "36",
920 -- 37: *aaa
921 -- 38-3D: cmp...
922 ds_0 = "3E",
923 -- 3F: *aas
924 inc_1 = x64 and "m:FF0m" or "rdw:40r|m:FF0m",
925 dec_1 = x64 and "m:FF1m" or "rdw:48r|m:FF1m",
926 push_1 = (x64 and "rq:n50r|rw:50r|mq:nFF6m|mw:FF6m" or
927 "rdw:50r|mdw:FF6m").."|S.:6AS|ib:n6Ai|i.:68i",
928 pop_1 = x64 and "rq:n58r|rw:58r|mq:n8F0m|mw:8F0m" or "rdw:58r|mdw:8F0m",
929 -- 60: *pusha, *pushad, *pushaw
930 -- 61: *popa, *popad, *popaw
931 -- 62: *bound rdw,x
932 -- 63: x86: *arpl mw,rw
933 movsxd_2 = x64 and "rm/qd:63rM",
934 fs_0 = "64",
935 gs_0 = "65",
936 o16_0 = "66",
937 a16_0 = not x64 and "67" or nil,
938 a32_0 = x64 and "67",
939 -- 68: push idw
940 -- 69: imul rdw,mdw,idw
941 -- 6A: push ib
942 -- 6B: imul rdw,mdw,S
943 -- 6C: *insb
944 -- 6D: *insd, *insw
945 -- 6E: *outsb
946 -- 6F: *outsd, *outsw
947 -- 70-7F: jcc lb
948 -- 80: add... mb,i
949 -- 81: add... mdw,i
950 -- 82: *undefined
951 -- 83: add... mdw,S
952 test_2 = "mr:85Rm|rm:85rM|Ri:A9ri|mi:F70mi",
953 -- 86: xchg rb,mb
954 -- 87: xchg rdw,mdw
955 -- 88: mov mb,r
956 -- 89: mov mdw,r
957 -- 8A: mov r,mb
958 -- 8B: mov r,mdw
959 -- 8C: *mov mdw,seg
960 lea_2 = "rx1dq:8DrM",
961 -- 8E: *mov seg,mdw
962 -- 8F: pop mdw
963 nop_0 = "90",
964 xchg_2 = "Rrqdw:90R|rRqdw:90r|rm:87rM|mr:87Rm",
965 cbw_0 = "6698",
966 cwde_0 = "98",
967 cdqe_0 = "4898",
968 cwd_0 = "6699",
969 cdq_0 = "99",
970 cqo_0 = "4899",
971 -- 9A: *call iw:idw
972 wait_0 = "9B",
973 fwait_0 = "9B",
974 pushf_0 = "9C",
975 pushfd_0 = not x64 and "9C",
976 pushfq_0 = x64 and "9C",
977 popf_0 = "9D",
978 popfd_0 = not x64 and "9D",
979 popfq_0 = x64 and "9D",
980 sahf_0 = "9E",
981 lahf_0 = "9F",
982 mov_2 = "OR:A3o|RO:A1O|mr:89Rm|rm:8BrM|rib:nB0ri|ridw:B8ri|mi:C70mi",
983 movsb_0 = "A4",
984 movsw_0 = "66A5",
985 movsd_0 = "A5",
986 cmpsb_0 = "A6",
987 cmpsw_0 = "66A7",
988 cmpsd_0 = "A7",
989 -- A8: test Rb,i
990 -- A9: test Rdw,i
991 stosb_0 = "AA",
992 stosw_0 = "66AB",
993 stosd_0 = "AB",
994 lodsb_0 = "AC",
995 lodsw_0 = "66AD",
996 lodsd_0 = "AD",
997 scasb_0 = "AE",
998 scasw_0 = "66AF",
999 scasd_0 = "AF",
1000 -- B0-B7: mov rb,i
1001 -- B8-BF: mov rdw,i
1002 -- C0: rol... mb,i
1003 -- C1: rol... mdw,i
1004 ret_1 = "i.:nC2W",
1005 ret_0 = "C3",
1006 -- C4: *les rdw,mq
1007 -- C5: *lds rdw,mq
1008 -- C6: mov mb,i
1009 -- C7: mov mdw,i
1010 -- C8: *enter iw,ib
1011 leave_0 = "C9",
1012 -- CA: *retf iw
1013 -- CB: *retf
1014 int3_0 = "CC",
1015 int_1 = "i.:nCDU",
1016 into_0 = "CE",
1017 -- CF: *iret
1018 -- D0: rol... mb,1
1019 -- D1: rol... mdw,1
1020 -- D2: rol... mb,cl
1021 -- D3: rol... mb,cl
1022 -- D4: *aam ib
1023 -- D5: *aad ib
1024 -- D6: *salc
1025 -- D7: *xlat
1026 -- D8-DF: floating point ops
1027 -- E0: *loopne
1028 -- E1: *loope
1029 -- E2: *loop
1030 -- E3: *jcxz, *jecxz
1031 -- E4: *in Rb,ib
1032 -- E5: *in Rdw,ib
1033 -- E6: *out ib,Rb
1034 -- E7: *out ib,Rdw
1035 call_1 = x64 and "mq:nFF2m|J.:E8nJ" or "md:FF2m|J.:E8J",
1036 jmp_1 = x64 and "mq:nFF4m|J.:E9nJ" or "md:FF4m|J.:E9J", -- short: EB
1037 -- EA: *jmp iw:idw
1038 -- EB: jmp ib
1039 -- EC: *in Rb,dx
1040 -- ED: *in Rdw,dx
1041 -- EE: *out dx,Rb
1042 -- EF: *out dx,Rdw
1043 lock_0 = "F0",
1044 int1_0 = "F1",
1045 repne_0 = "F2",
1046 repnz_0 = "F2",
1047 rep_0 = "F3",
1048 repe_0 = "F3",
1049 repz_0 = "F3",
1050 -- F4: *hlt
1051 cmc_0 = "F5",
1052 -- F6: test... mb,i; div... mb
1053 -- F7: test... mdw,i; div... mdw
1054 clc_0 = "F8",
1055 stc_0 = "F9",
1056 -- FA: *cli
1057 cld_0 = "FC",
1058 std_0 = "FD",
1059 -- FE: inc... mb
1060 -- FF: inc... mdw
1062 -- misc ops
1063 not_1 = "m:F72m",
1064 neg_1 = "m:F73m",
1065 mul_1 = "m:F74m",
1066 imul_1 = "m:F75m",
1067 div_1 = "m:F76m",
1068 idiv_1 = "m:F77m",
1070 imul_2 = "rmqdw:0FAFrM|rIqdw:69rmI|rSqdw:6BrmS|riqdw:69rmi",
1071 imul_3 = "rmIqdw:69rMI|rmSqdw:6BrMS|rmiqdw:69rMi",
1073 movzx_2 = "rm/db:0FB6rM|rm/qb:|rm/wb:0FB6rM|rm/dw:0FB7rM|rm/qw:",
1074 movsx_2 = "rm/db:0FBErM|rm/qb:|rm/wb:0FBErM|rm/dw:0FBFrM|rm/qw:",
1076 bswap_1 = "rqd:0FC8r",
1077 bsf_2 = "rmqdw:0FBCrM",
1078 bsr_2 = "rmqdw:0FBDrM",
1079 bt_2 = "mrqdw:0FA3Rm|miqdw:0FBA4mU",
1080 btc_2 = "mrqdw:0FBBRm|miqdw:0FBA7mU",
1081 btr_2 = "mrqdw:0FB3Rm|miqdw:0FBA6mU",
1082 bts_2 = "mrqdw:0FABRm|miqdw:0FBA5mU",
1084 shld_3 = "mriqdw:0FA4RmU|mrCqdw:0FA5Rm",
1085 shrd_3 = "mriqdw:0FACRmU|mrCqdw:0FADRm",
1087 rdtsc_0 = "0F31", -- P1+
1088 cpuid_0 = "0FA2", -- P1+
1090 -- floating point ops
1091 fst_1 = "ff:DDD0r|xd:D92m|xq:nDD2m",
1092 fstp_1 = "ff:DDD8r|xd:D93m|xq:nDD3m|xt:DB7m",
1093 fld_1 = "ff:D9C0r|xd:D90m|xq:nDD0m|xt:DB5m",
1095 fpop_0 = "DDD8", -- Alias for fstp st0.
1097 fist_1 = "xw:nDF2m|xd:DB2m",
1098 fistp_1 = "xw:nDF3m|xd:DB3m|xq:nDF7m",
1099 fild_1 = "xw:nDF0m|xd:DB0m|xq:nDF5m",
1101 fxch_0 = "D9C9",
1102 fxch_1 = "ff:D9C8r",
1103 fxch_2 = "fFf:D9C8r|Fff:D9C8R",
1105 fucom_1 = "ff:DDE0r",
1106 fucom_2 = "Fff:DDE0R",
1107 fucomp_1 = "ff:DDE8r",
1108 fucomp_2 = "Fff:DDE8R",
1109 fucomi_1 = "ff:DBE8r", -- P6+
1110 fucomi_2 = "Fff:DBE8R", -- P6+
1111 fucomip_1 = "ff:DFE8r", -- P6+
1112 fucomip_2 = "Fff:DFE8R", -- P6+
1113 fcomi_1 = "ff:DBF0r", -- P6+
1114 fcomi_2 = "Fff:DBF0R", -- P6+
1115 fcomip_1 = "ff:DFF0r", -- P6+
1116 fcomip_2 = "Fff:DFF0R", -- P6+
1117 fucompp_0 = "DAE9",
1118 fcompp_0 = "DED9",
1120 fldenv_1 = "x.:D94m",
1121 fnstenv_1 = "x.:D96m",
1122 fstenv_1 = "x.:9BD96m",
1123 fldcw_1 = "xw:nD95m",
1124 fstcw_1 = "xw:n9BD97m",
1125 fnstcw_1 = "xw:nD97m",
1126 fstsw_1 = "Rw:n9BDFE0|xw:n9BDD7m",
1127 fnstsw_1 = "Rw:nDFE0|xw:nDD7m",
1128 fclex_0 = "9BDBE2",
1129 fnclex_0 = "DBE2",
1131 fnop_0 = "D9D0",
1132 -- D9D1-D9DF: unassigned
1134 fchs_0 = "D9E0",
1135 fabs_0 = "D9E1",
1136 -- D9E2: unassigned
1137 -- D9E3: unassigned
1138 ftst_0 = "D9E4",
1139 fxam_0 = "D9E5",
1140 -- D9E6: unassigned
1141 -- D9E7: unassigned
1142 fld1_0 = "D9E8",
1143 fldl2t_0 = "D9E9",
1144 fldl2e_0 = "D9EA",
1145 fldpi_0 = "D9EB",
1146 fldlg2_0 = "D9EC",
1147 fldln2_0 = "D9ED",
1148 fldz_0 = "D9EE",
1149 -- D9EF: unassigned
1151 f2xm1_0 = "D9F0",
1152 fyl2x_0 = "D9F1",
1153 fptan_0 = "D9F2",
1154 fpatan_0 = "D9F3",
1155 fxtract_0 = "D9F4",
1156 fprem1_0 = "D9F5",
1157 fdecstp_0 = "D9F6",
1158 fincstp_0 = "D9F7",
1159 fprem_0 = "D9F8",
1160 fyl2xp1_0 = "D9F9",
1161 fsqrt_0 = "D9FA",
1162 fsincos_0 = "D9FB",
1163 frndint_0 = "D9FC",
1164 fscale_0 = "D9FD",
1165 fsin_0 = "D9FE",
1166 fcos_0 = "D9FF",
1168 -- SSE, SSE2
1169 andnpd_2 = "rmo:660F55rM",
1170 andnps_2 = "rmo:0F55rM",
1171 andpd_2 = "rmo:660F54rM",
1172 andps_2 = "rmo:0F54rM",
1173 clflush_1 = "x.:0FAE7m",
1174 cmppd_3 = "rmio:660FC2rMU",
1175 cmpps_3 = "rmio:0FC2rMU",
1176 cmpsd_3 = "rrio:F20FC2rMU|rxi/oq:",
1177 cmpss_3 = "rrio:F30FC2rMU|rxi/od:",
1178 comisd_2 = "rro:660F2FrM|rx/oq:",
1179 comiss_2 = "rro:0F2FrM|rx/od:",
1180 cvtdq2pd_2 = "rro:F30FE6rM|rx/oq:",
1181 cvtdq2ps_2 = "rmo:0F5BrM",
1182 cvtpd2dq_2 = "rmo:F20FE6rM",
1183 cvtpd2ps_2 = "rmo:660F5ArM",
1184 cvtpi2pd_2 = "rx/oq:660F2ArM",
1185 cvtpi2ps_2 = "rx/oq:0F2ArM",
1186 cvtps2dq_2 = "rmo:660F5BrM",
1187 cvtps2pd_2 = "rro:0F5ArM|rx/oq:",
1188 cvtsd2si_2 = "rr/do:F20F2DrM|rr/qo:|rx/dq:|rxq:",
1189 cvtsd2ss_2 = "rro:F20F5ArM|rx/oq:",
1190 cvtsi2sd_2 = "rm/od:F20F2ArM|rm/oq:F20F2ArXM",
1191 cvtsi2ss_2 = "rm/od:F30F2ArM|rm/oq:F30F2ArXM",
1192 cvtss2sd_2 = "rro:F30F5ArM|rx/od:",
1193 cvtss2si_2 = "rr/do:F20F2CrM|rr/qo:|rxd:|rx/qd:",
1194 cvttpd2dq_2 = "rmo:660FE6rM",
1195 cvttps2dq_2 = "rmo:F30F5BrM",
1196 cvttsd2si_2 = "rr/do:F20F2CrM|rr/qo:|rx/dq:|rxq:",
1197 cvttss2si_2 = "rr/do:F30F2CrM|rr/qo:|rxd:|rx/qd:",
1198 fxsave_1 = "x.:0FAE0m",
1199 fxrstor_1 = "x.:0FAE1m",
1200 ldmxcsr_1 = "xd:0FAE2m",
1201 lfence_0 = "0FAEE8",
1202 maskmovdqu_2 = "rro:660FF7rM",
1203 mfence_0 = "0FAEF0",
1204 movapd_2 = "rmo:660F28rM|mro:660F29Rm",
1205 movaps_2 = "rmo:0F28rM|mro:0F29Rm",
1206 movd_2 = "rm/od:660F6ErM|rm/oq:660F6ErXM|mr/do:660F7ERm|mr/qo:",
1207 movdqa_2 = "rmo:660F6FrM|mro:660F7FRm",
1208 movdqu_2 = "rmo:F30F6FrM|mro:F30F7FRm",
1209 movhlps_2 = "rro:0F12rM",
1210 movhpd_2 = "rx/oq:660F16rM|xr/qo:n660F17Rm",
1211 movhps_2 = "rx/oq:0F16rM|xr/qo:n0F17Rm",
1212 movlhps_2 = "rro:0F16rM",
1213 movlpd_2 = "rx/oq:660F12rM|xr/qo:n660F13Rm",
1214 movlps_2 = "rx/oq:0F12rM|xr/qo:n0F13Rm",
1215 movmskpd_2 = "rr/do:660F50rM",
1216 movmskps_2 = "rr/do:0F50rM",
1217 movntdq_2 = "xro:660FE7Rm",
1218 movnti_2 = "xrqd:0FC3Rm",
1219 movntpd_2 = "xro:660F2BRm",
1220 movntps_2 = "xro:0F2BRm",
1221 movq_2 = "rro:F30F7ErM|rx/oq:|xr/qo:n660FD6Rm",
1222 movsd_2 = "rro:F20F10rM|rx/oq:|xr/qo:nF20F11Rm",
1223 movss_2 = "rro:F30F10rM|rx/od:|xr/do:F30F11Rm",
1224 movupd_2 = "rmo:660F10rM|mro:660F11Rm",
1225 movups_2 = "rmo:0F10rM|mro:0F11Rm",
1226 orpd_2 = "rmo:660F56rM",
1227 orps_2 = "rmo:0F56rM",
1228 packssdw_2 = "rmo:660F6BrM",
1229 packsswb_2 = "rmo:660F63rM",
1230 packuswb_2 = "rmo:660F67rM",
1231 paddb_2 = "rmo:660FFCrM",
1232 paddd_2 = "rmo:660FFErM",
1233 paddq_2 = "rmo:660FD4rM",
1234 paddsb_2 = "rmo:660FECrM",
1235 paddsw_2 = "rmo:660FEDrM",
1236 paddusb_2 = "rmo:660FDCrM",
1237 paddusw_2 = "rmo:660FDDrM",
1238 paddw_2 = "rmo:660FFDrM",
1239 pand_2 = "rmo:660FDBrM",
1240 pandn_2 = "rmo:660FDFrM",
1241 pause_0 = "F390",
1242 pavgb_2 = "rmo:660FE0rM",
1243 pavgw_2 = "rmo:660FE3rM",
1244 pcmpeqb_2 = "rmo:660F74rM",
1245 pcmpeqd_2 = "rmo:660F76rM",
1246 pcmpeqw_2 = "rmo:660F75rM",
1247 pcmpgtb_2 = "rmo:660F64rM",
1248 pcmpgtd_2 = "rmo:660F66rM",
1249 pcmpgtw_2 = "rmo:660F65rM",
1250 pextrw_3 = "rri/do:660FC5rMU|xri/wo:660F3A15nrMU", -- Mem op: SSE4.1 only.
1251 pinsrw_3 = "rri/od:660FC4rMU|rxi/ow:",
1252 pmaddwd_2 = "rmo:660FF5rM",
1253 pmaxsw_2 = "rmo:660FEErM",
1254 pmaxub_2 = "rmo:660FDErM",
1255 pminsw_2 = "rmo:660FEArM",
1256 pminub_2 = "rmo:660FDArM",
1257 pmovmskb_2 = "rr/do:660FD7rM",
1258 pmulhuw_2 = "rmo:660FE4rM",
1259 pmulhw_2 = "rmo:660FE5rM",
1260 pmullw_2 = "rmo:660FD5rM",
1261 pmuludq_2 = "rmo:660FF4rM",
1262 por_2 = "rmo:660FEBrM",
1263 prefetchnta_1 = "xb:n0F180m",
1264 prefetcht0_1 = "xb:n0F181m",
1265 prefetcht1_1 = "xb:n0F182m",
1266 prefetcht2_1 = "xb:n0F183m",
1267 psadbw_2 = "rmo:660FF6rM",
1268 pshufd_3 = "rmio:660F70rMU",
1269 pshufhw_3 = "rmio:F30F70rMU",
1270 pshuflw_3 = "rmio:F20F70rMU",
1271 pslld_2 = "rmo:660FF2rM|rio:660F726mU",
1272 pslldq_2 = "rio:660F737mU",
1273 psllq_2 = "rmo:660FF3rM|rio:660F736mU",
1274 psllw_2 = "rmo:660FF1rM|rio:660F716mU",
1275 psrad_2 = "rmo:660FE2rM|rio:660F724mU",
1276 psraw_2 = "rmo:660FE1rM|rio:660F714mU",
1277 psrld_2 = "rmo:660FD2rM|rio:660F722mU",
1278 psrldq_2 = "rio:660F733mU",
1279 psrlq_2 = "rmo:660FD3rM|rio:660F732mU",
1280 psrlw_2 = "rmo:660FD1rM|rio:660F712mU",
1281 psubb_2 = "rmo:660FF8rM",
1282 psubd_2 = "rmo:660FFArM",
1283 psubq_2 = "rmo:660FFBrM",
1284 psubsb_2 = "rmo:660FE8rM",
1285 psubsw_2 = "rmo:660FE9rM",
1286 psubusb_2 = "rmo:660FD8rM",
1287 psubusw_2 = "rmo:660FD9rM",
1288 psubw_2 = "rmo:660FF9rM",
1289 punpckhbw_2 = "rmo:660F68rM",
1290 punpckhdq_2 = "rmo:660F6ArM",
1291 punpckhqdq_2 = "rmo:660F6DrM",
1292 punpckhwd_2 = "rmo:660F69rM",
1293 punpcklbw_2 = "rmo:660F60rM",
1294 punpckldq_2 = "rmo:660F62rM",
1295 punpcklqdq_2 = "rmo:660F6CrM",
1296 punpcklwd_2 = "rmo:660F61rM",
1297 pxor_2 = "rmo:660FEFrM",
1298 rcpps_2 = "rmo:0F53rM",
1299 rcpss_2 = "rro:F30F53rM|rx/od:",
1300 rsqrtps_2 = "rmo:0F52rM",
1301 rsqrtss_2 = "rmo:F30F52rM",
1302 sfence_0 = "0FAEF8",
1303 shufpd_3 = "rmio:660FC6rMU",
1304 shufps_3 = "rmio:0FC6rMU",
1305 stmxcsr_1 = "xd:0FAE3m",
1306 ucomisd_2 = "rro:660F2ErM|rx/oq:",
1307 ucomiss_2 = "rro:0F2ErM|rx/od:",
1308 unpckhpd_2 = "rmo:660F15rM",
1309 unpckhps_2 = "rmo:0F15rM",
1310 unpcklpd_2 = "rmo:660F14rM",
1311 unpcklps_2 = "rmo:0F14rM",
1312 xorpd_2 = "rmo:660F57rM",
1313 xorps_2 = "rmo:0F57rM",
1315 -- SSE3 ops
1316 fisttp_1 = "xw:nDF1m|xd:DB1m|xq:nDD1m",
1317 addsubpd_2 = "rmo:660FD0rM",
1318 addsubps_2 = "rmo:F20FD0rM",
1319 haddpd_2 = "rmo:660F7CrM",
1320 haddps_2 = "rmo:F20F7CrM",
1321 hsubpd_2 = "rmo:660F7DrM",
1322 hsubps_2 = "rmo:F20F7DrM",
1323 lddqu_2 = "rxo:F20FF0rM",
1324 movddup_2 = "rmo:F20F12rM",
1325 movshdup_2 = "rmo:F30F16rM",
1326 movsldup_2 = "rmo:F30F12rM",
1328 -- SSSE3 ops
1329 pabsb_2 = "rmo:660F381CrM",
1330 pabsd_2 = "rmo:660F381ErM",
1331 pabsw_2 = "rmo:660F381DrM",
1332 palignr_3 = "rmio:660F3A0FrMU",
1333 phaddd_2 = "rmo:660F3802rM",
1334 phaddsw_2 = "rmo:660F3803rM",
1335 phaddw_2 = "rmo:660F3801rM",
1336 phsubd_2 = "rmo:660F3806rM",
1337 phsubsw_2 = "rmo:660F3807rM",
1338 phsubw_2 = "rmo:660F3805rM",
1339 pmaddubsw_2 = "rmo:660F3804rM",
1340 pmulhrsw_2 = "rmo:660F380BrM",
1341 pshufb_2 = "rmo:660F3800rM",
1342 psignb_2 = "rmo:660F3808rM",
1343 psignd_2 = "rmo:660F380ArM",
1344 psignw_2 = "rmo:660F3809rM",
1346 -- SSE4.1 ops
1347 blendpd_3 = "rmio:660F3A0DrMU",
1348 blendps_3 = "rmio:660F3A0CrMU",
1349 blendvpd_3 = "rmRo:660F3815rM",
1350 blendvps_3 = "rmRo:660F3814rM",
1351 dppd_3 = "rmio:660F3A41rMU",
1352 dpps_3 = "rmio:660F3A40rMU",
1353 extractps_3 = "mri/do:660F3A17RmU|rri/qo:660F3A17RXmU",
1354 insertps_3 = "rrio:660F3A41rMU|rxi/od:",
1355 movntdqa_2 = "rmo:660F382ArM",
1356 mpsadbw_3 = "rmio:660F3A42rMU",
1357 packusdw_2 = "rmo:660F382BrM",
1358 pblendvb_3 = "rmRo:660F3810rM",
1359 pblendw_3 = "rmio:660F3A0ErMU",
1360 pcmpeqq_2 = "rmo:660F3829rM",
1361 pextrb_3 = "rri/do:660F3A14nRmU|rri/qo:|xri/bo:",
1362 pextrd_3 = "mri/do:660F3A16RmU",
1363 pextrq_3 = "mri/qo:660F3A16RmU",
1364 -- pextrw is SSE2, mem operand is SSE4.1 only
1365 phminposuw_2 = "rmo:660F3841rM",
1366 pinsrb_3 = "rri/od:660F3A20nrMU|rxi/ob:",
1367 pinsrd_3 = "rmi/od:660F3A22rMU",
1368 pinsrq_3 = "rmi/oq:660F3A22rXMU",
1369 pmaxsb_2 = "rmo:660F383CrM",
1370 pmaxsd_2 = "rmo:660F383DrM",
1371 pmaxud_2 = "rmo:660F383FrM",
1372 pmaxuw_2 = "rmo:660F383ErM",
1373 pminsb_2 = "rmo:660F3838rM",
1374 pminsd_2 = "rmo:660F3839rM",
1375 pminud_2 = "rmo:660F383BrM",
1376 pminuw_2 = "rmo:660F383ArM",
1377 pmovsxbd_2 = "rro:660F3821rM|rx/od:",
1378 pmovsxbq_2 = "rro:660F3822rM|rx/ow:",
1379 pmovsxbw_2 = "rro:660F3820rM|rx/oq:",
1380 pmovsxdq_2 = "rro:660F3825rM|rx/oq:",
1381 pmovsxwd_2 = "rro:660F3823rM|rx/oq:",
1382 pmovsxwq_2 = "rro:660F3824rM|rx/od:",
1383 pmovzxbd_2 = "rro:660F3831rM|rx/od:",
1384 pmovzxbq_2 = "rro:660F3832rM|rx/ow:",
1385 pmovzxbw_2 = "rro:660F3830rM|rx/oq:",
1386 pmovzxdq_2 = "rro:660F3835rM|rx/oq:",
1387 pmovzxwd_2 = "rro:660F3833rM|rx/oq:",
1388 pmovzxwq_2 = "rro:660F3834rM|rx/od:",
1389 pmuldq_2 = "rmo:660F3828rM",
1390 pmulld_2 = "rmo:660F3840rM",
1391 ptest_2 = "rmo:660F3817rM",
1392 roundpd_3 = "rmio:660F3A09rMU",
1393 roundps_3 = "rmio:660F3A08rMU",
1394 roundsd_3 = "rrio:660F3A0BrMU|rxi/oq:",
1395 roundss_3 = "rrio:660F3A0ArMU|rxi/od:",
1397 -- SSE4.2 ops
1398 crc32_2 = "rmqd:F20F38F1rM|rm/dw:66F20F38F1rM|rm/db:F20F38F0rM|rm/qb:",
1399 pcmpestri_3 = "rmio:660F3A61rMU",
1400 pcmpestrm_3 = "rmio:660F3A60rMU",
1401 pcmpgtq_2 = "rmo:660F3837rM",
1402 pcmpistri_3 = "rmio:660F3A63rMU",
1403 pcmpistrm_3 = "rmio:660F3A62rMU",
1404 popcnt_2 = "rmqdw:F30FB8rM",
1406 -- SSE4a
1407 extrq_2 = "rro:660F79rM",
1408 extrq_3 = "riio:660F780mUU",
1409 insertq_2 = "rro:F20F79rM",
1410 insertq_4 = "rriio:F20F78rMUU",
1411 lzcnt_2 = "rmqdw:F30FBDrM",
1412 movntsd_2 = "xr/qo:nF20F2BRm",
1413 movntss_2 = "xr/do:F30F2BRm",
1414 -- popcnt is also in SSE4.2
1417 ------------------------------------------------------------------------------
1419 -- Arithmetic ops.
1420 for name,n in pairs{ add = 0, ["or"] = 1, adc = 2, sbb = 3,
1421 ["and"] = 4, sub = 5, xor = 6, cmp = 7 } do
1422 local n8 = shl(n, 3)
1423 map_op[name.."_2"] = format(
1424 "mr:%02XRm|rm:%02XrM|mI1qdw:81%XmI|mS1qdw:83%XmS|Ri1qdwb:%02Xri|mi1qdwb:81%Xmi",
1425 1+n8, 3+n8, n, n, 5+n8, n)
1428 -- Shift ops.
1429 for name,n in pairs{ rol = 0, ror = 1, rcl = 2, rcr = 3,
1430 shl = 4, shr = 5, sar = 7, sal = 4 } do
1431 map_op[name.."_2"] = format("m1:D1%Xm|mC1qdwb:D3%Xm|mi:C1%XmU", n, n, n)
1434 -- Conditional ops.
1435 for cc,n in pairs(map_cc) do
1436 map_op["j"..cc.."_1"] = format("J.:n0F8%XJ", n) -- short: 7%X
1437 map_op["set"..cc.."_1"] = format("mb:n0F9%X2m", n)
1438 map_op["cmov"..cc.."_2"] = format("rmqdw:0F4%XrM", n) -- P6+
1441 -- FP arithmetic ops.
1442 for name,n in pairs{ add = 0, mul = 1, com = 2, comp = 3,
1443 sub = 4, subr = 5, div = 6, divr = 7 } do
1444 local nc = 0xc0 + shl(n, 3)
1445 local nr = nc + (n < 4 and 0 or (n % 2 == 0 and 8 or -8))
1446 local fn = "f"..name
1447 map_op[fn.."_1"] = format("ff:D8%02Xr|xd:D8%Xm|xq:nDC%Xm", nc, n, n)
1448 if n == 2 or n == 3 then
1449 map_op[fn.."_2"] = format("Fff:D8%02XR|Fx2d:D8%XM|Fx2q:nDC%XM", nc, n, n)
1450 else
1451 map_op[fn.."_2"] = format("Fff:D8%02XR|fFf:DC%02Xr|Fx2d:D8%XM|Fx2q:nDC%XM", nc, nr, n, n)
1452 map_op[fn.."p_1"] = format("ff:DE%02Xr", nr)
1453 map_op[fn.."p_2"] = format("fFf:DE%02Xr", nr)
1455 map_op["fi"..name.."_1"] = format("xd:DA%Xm|xw:nDE%Xm", n, n)
1458 -- FP conditional moves.
1459 for cc,n in pairs{ b=0, e=1, be=2, u=3, nb=4, ne=5, nbe=6, nu=7 } do
1460 local nc = 0xdac0 + shl(band(n, 3), 3) + shl(band(n, 4), 6)
1461 map_op["fcmov"..cc.."_1"] = format("ff:%04Xr", nc) -- P6+
1462 map_op["fcmov"..cc.."_2"] = format("Fff:%04XR", nc) -- P6+
1465 -- SSE FP arithmetic ops.
1466 for name,n in pairs{ sqrt = 1, add = 8, mul = 9,
1467 sub = 12, min = 13, div = 14, max = 15 } do
1468 map_op[name.."ps_2"] = format("rmo:0F5%XrM", n)
1469 map_op[name.."ss_2"] = format("rro:F30F5%XrM|rx/od:", n)
1470 map_op[name.."pd_2"] = format("rmo:660F5%XrM", n)
1471 map_op[name.."sd_2"] = format("rro:F20F5%XrM|rx/oq:", n)
1474 ------------------------------------------------------------------------------
1476 -- Process pattern string.
1477 local function dopattern(pat, args, sz, op, needrex)
1478 local digit, addin
1479 local opcode = 0
1480 local szov = sz
1481 local narg = 1
1482 local rex = 0
1484 -- Limit number of section buffer positions used by a single dasm_put().
1485 -- A single opcode needs a maximum of 5 positions.
1486 if secpos+5 > maxsecpos then wflush() end
1488 -- Process each character.
1489 for c in gmatch(pat.."|", ".") do
1490 if match(c, "%x") then -- Hex digit.
1491 digit = byte(c) - 48
1492 if digit > 48 then digit = digit - 39
1493 elseif digit > 16 then digit = digit - 7 end
1494 opcode = opcode*16 + digit
1495 addin = nil
1496 elseif c == "n" then -- Disable operand size mods for opcode.
1497 szov = nil
1498 elseif c == "X" then -- Force REX.W.
1499 rex = 8
1500 elseif c == "r" then -- Merge 1st operand regno. into opcode.
1501 addin = args[1]; opcode = opcode + (addin.reg % 8)
1502 if narg < 2 then narg = 2 end
1503 elseif c == "R" then -- Merge 2nd operand regno. into opcode.
1504 addin = args[2]; opcode = opcode + (addin.reg % 8)
1505 narg = 3
1506 elseif c == "m" or c == "M" then -- Encode ModRM/SIB.
1507 local s
1508 if addin then
1509 s = addin.reg
1510 opcode = opcode - band(s, 7) -- Undo regno opcode merge.
1511 else
1512 s = band(opcode, 15) -- Undo last digit.
1513 opcode = shr(opcode, 4)
1515 local nn = c == "m" and 1 or 2
1516 local t = args[nn]
1517 if narg <= nn then narg = nn + 1 end
1518 if szov == "q" and rex == 0 then rex = rex + 8 end
1519 if t.reg and t.reg > 7 then rex = rex + 1 end
1520 if t.xreg and t.xreg > 7 then rex = rex + 2 end
1521 if s > 7 then rex = rex + 4 end
1522 if needrex then rex = rex + 16 end
1523 wputop(szov, opcode, rex); opcode = nil
1524 local imark = sub(pat, -1) -- Force a mark (ugly).
1525 -- Put ModRM/SIB with regno/last digit as spare.
1526 wputmrmsib(t, imark, s, addin and addin.vreg)
1527 addin = nil
1528 else
1529 if opcode then -- Flush opcode.
1530 if szov == "q" and rex == 0 then rex = rex + 8 end
1531 if needrex then rex = rex + 16 end
1532 if addin and addin.reg == -1 then
1533 wputop(szov, opcode - 7, rex)
1534 waction("VREG", addin.vreg); wputxb(0)
1535 else
1536 if addin and addin.reg > 7 then rex = rex + 1 end
1537 wputop(szov, opcode, rex)
1539 opcode = nil
1541 if c == "|" then break end
1542 if c == "o" then -- Offset (pure 32 bit displacement).
1543 wputdarg(args[1].disp); if narg < 2 then narg = 2 end
1544 elseif c == "O" then
1545 wputdarg(args[2].disp); narg = 3
1546 else
1547 -- Anything else is an immediate operand.
1548 local a = args[narg]
1549 narg = narg + 1
1550 local mode, imm = a.mode, a.imm
1551 if mode == "iJ" and not match("iIJ", c) then
1552 werror("bad operand size for label")
1554 if c == "S" then
1555 wputsbarg(imm)
1556 elseif c == "U" then
1557 wputbarg(imm)
1558 elseif c == "W" then
1559 wputwarg(imm)
1560 elseif c == "i" or c == "I" then
1561 if mode == "iJ" then
1562 wputlabel("IMM_", imm, 1)
1563 elseif mode == "iI" and c == "I" then
1564 waction(sz == "w" and "IMM_WB" or "IMM_DB", imm)
1565 else
1566 wputszarg(sz, imm)
1568 elseif c == "J" then
1569 if mode == "iPJ" then
1570 waction("REL_A", imm) -- !x64 (secpos)
1571 else
1572 wputlabel("REL_", imm, 2)
1574 else
1575 werror("bad char `"..c.."' in pattern `"..pat.."' for `"..op.."'")
1582 ------------------------------------------------------------------------------
1584 -- Mapping of operand modes to short names. Suppress output with '#'.
1585 local map_modename = {
1586 r = "reg", R = "eax", C = "cl", x = "mem", m = "mrm", i = "imm",
1587 f = "stx", F = "st0", J = "lbl", ["1"] = "1",
1588 I = "#", S = "#", O = "#",
1591 -- Return a table/string showing all possible operand modes.
1592 local function templatehelp(template, nparams)
1593 if nparams == 0 then return "" end
1594 local t = {}
1595 for tm in gmatch(template, "[^%|]+") do
1596 local s = map_modename[sub(tm, 1, 1)]
1597 s = s..gsub(sub(tm, 2, nparams), ".", function(c)
1598 return ", "..map_modename[c]
1599 end)
1600 if not match(s, "#") then t[#t+1] = s end
1602 return t
1605 -- Match operand modes against mode match part of template.
1606 local function matchtm(tm, args)
1607 for i=1,#args do
1608 if not match(args[i].mode, sub(tm, i, i)) then return end
1610 return true
1613 -- Handle opcodes defined with template strings.
1614 map_op[".template__"] = function(params, template, nparams)
1615 if not params then return templatehelp(template, nparams) end
1616 local args = {}
1618 -- Zero-operand opcodes have no match part.
1619 if #params == 0 then
1620 dopattern(template, args, "d", params.op, nil)
1621 return
1624 -- Determine common operand size (coerce undefined size) or flag as mixed.
1625 local sz, szmix, needrex
1626 for i,p in ipairs(params) do
1627 args[i] = parseoperand(p)
1628 local nsz = args[i].opsize
1629 if nsz then
1630 if sz and sz ~= nsz then szmix = true else sz = nsz end
1632 local nrex = args[i].needrex
1633 if nrex ~= nil then
1634 if needrex == nil then
1635 needrex = nrex
1636 elseif needrex ~= nrex then
1637 werror("bad mix of byte-addressable registers")
1642 -- Try all match:pattern pairs (separated by '|').
1643 local gotmatch, lastpat
1644 for tm in gmatch(template, "[^%|]+") do
1645 -- Split off size match (starts after mode match) and pattern string.
1646 local szm, pat = match(tm, "^(.-):(.*)$", #args+1)
1647 if pat == "" then pat = lastpat else lastpat = pat end
1648 if matchtm(tm, args) then
1649 local prefix = sub(szm, 1, 1)
1650 if prefix == "/" then -- Match both operand sizes.
1651 if args[1].opsize == sub(szm, 2, 2) and
1652 args[2].opsize == sub(szm, 3, 3) then
1653 dopattern(pat, args, sz, params.op, needrex) -- Process pattern.
1654 return
1656 else -- Match common operand size.
1657 local szp = sz
1658 if szm == "" then szm = x64 and "qdwb" or "dwb" end -- Default sizes.
1659 if prefix == "1" then szp = args[1].opsize; szmix = nil
1660 elseif prefix == "2" then szp = args[2].opsize; szmix = nil end
1661 if not szmix and (prefix == "." or match(szm, szp or "#")) then
1662 dopattern(pat, args, szp, params.op, needrex) -- Process pattern.
1663 return
1666 gotmatch = true
1670 local msg = "bad operand mode"
1671 if gotmatch then
1672 if szmix then
1673 msg = "mixed operand size"
1674 else
1675 msg = sz and "bad operand size" or "missing operand size"
1679 werror(msg.." in `"..opmodestr(params.op, args).."'")
1682 ------------------------------------------------------------------------------
1684 -- x64-specific opcode for 64 bit immediates and displacements.
1685 if x64 then
1686 function map_op.mov64_2(params)
1687 if not params then return { "reg, imm", "reg, [disp]", "[disp], reg" } end
1688 if secpos+2 > maxsecpos then wflush() end
1689 local opcode, op64, sz, rex, vreg
1690 local op64 = match(params[1], "^%[%s*(.-)%s*%]$")
1691 if op64 then
1692 local a = parseoperand(params[2])
1693 if a.mode ~= "rmR" then werror("bad operand mode") end
1694 sz = a.opsize
1695 rex = sz == "q" and 8 or 0
1696 opcode = 0xa3
1697 else
1698 op64 = match(params[2], "^%[%s*(.-)%s*%]$")
1699 local a = parseoperand(params[1])
1700 if op64 then
1701 if a.mode ~= "rmR" then werror("bad operand mode") end
1702 sz = a.opsize
1703 rex = sz == "q" and 8 or 0
1704 opcode = 0xa1
1705 else
1706 if sub(a.mode, 1, 1) ~= "r" or a.opsize ~= "q" then
1707 werror("bad operand mode")
1709 op64 = params[2]
1710 if a.reg == -1 then
1711 vreg = a.vreg
1712 opcode = 0xb8
1713 else
1714 opcode = 0xb8 + band(a.reg, 7)
1716 rex = a.reg > 7 and 9 or 8
1719 wputop(sz, opcode, rex)
1720 if vreg then waction("VREG", vreg); wputxb(0) end
1721 waction("IMM_D", format("(unsigned int)(%s)", op64))
1722 waction("IMM_D", format("(unsigned int)((%s)>>32)", op64))
1726 ------------------------------------------------------------------------------
1728 -- Pseudo-opcodes for data storage.
1729 local function op_data(params)
1730 if not params then return "imm..." end
1731 local sz = sub(params.op, 2, 2)
1732 if sz == "a" then sz = addrsize end
1733 for _,p in ipairs(params) do
1734 local a = parseoperand(p)
1735 if sub(a.mode, 1, 1) ~= "i" or (a.opsize and a.opsize ~= sz) then
1736 werror("bad mode or size in `"..p.."'")
1738 if a.mode == "iJ" then
1739 wputlabel("IMM_", a.imm, 1)
1740 else
1741 wputszarg(sz, a.imm)
1743 if secpos+2 > maxsecpos then wflush() end
1747 map_op[".byte_*"] = op_data
1748 map_op[".sbyte_*"] = op_data
1749 map_op[".word_*"] = op_data
1750 map_op[".dword_*"] = op_data
1751 map_op[".aword_*"] = op_data
1753 ------------------------------------------------------------------------------
1755 -- Pseudo-opcode to mark the position where the action list is to be emitted.
1756 map_op[".actionlist_1"] = function(params)
1757 if not params then return "cvar" end
1758 local name = params[1] -- No syntax check. You get to keep the pieces.
1759 wline(function(out) writeactions(out, name) end)
1762 -- Pseudo-opcode to mark the position where the global enum is to be emitted.
1763 map_op[".globals_1"] = function(params)
1764 if not params then return "prefix" end
1765 local prefix = params[1] -- No syntax check. You get to keep the pieces.
1766 wline(function(out) writeglobals(out, prefix) end)
1769 -- Pseudo-opcode to mark the position where the global names are to be emitted.
1770 map_op[".globalnames_1"] = function(params)
1771 if not params then return "cvar" end
1772 local name = params[1] -- No syntax check. You get to keep the pieces.
1773 wline(function(out) writeglobalnames(out, name) end)
1776 -- Pseudo-opcode to mark the position where the extern names are to be emitted.
1777 map_op[".externnames_1"] = function(params)
1778 if not params then return "cvar" end
1779 local name = params[1] -- No syntax check. You get to keep the pieces.
1780 wline(function(out) writeexternnames(out, name) end)
1783 ------------------------------------------------------------------------------
1785 -- Label pseudo-opcode (converted from trailing colon form).
1786 map_op[".label_2"] = function(params)
1787 if not params then return "[1-9] | ->global | =>pcexpr [, addr]" end
1788 if secpos+2 > maxsecpos then wflush() end
1789 local a = parseoperand(params[1])
1790 local mode, imm = a.mode, a.imm
1791 if type(imm) == "number" and (mode == "iJ" or (imm >= 1 and imm <= 9)) then
1792 -- Local label (1: ... 9:) or global label (->global:).
1793 waction("LABEL_LG", nil, 1)
1794 wputxb(imm)
1795 elseif mode == "iJ" then
1796 -- PC label (=>pcexpr:).
1797 waction("LABEL_PC", imm)
1798 else
1799 werror("bad label definition")
1801 -- SETLABEL must immediately follow LABEL_LG/LABEL_PC.
1802 local addr = params[2]
1803 if addr then
1804 local a = parseoperand(addr)
1805 if a.mode == "iPJ" then
1806 waction("SETLABEL", a.imm)
1807 else
1808 werror("bad label assignment")
1812 map_op[".label_1"] = map_op[".label_2"]
1814 ------------------------------------------------------------------------------
1816 -- Alignment pseudo-opcode.
1817 map_op[".align_1"] = function(params)
1818 if not params then return "numpow2" end
1819 if secpos+1 > maxsecpos then wflush() end
1820 local align = tonumber(params[1]) or map_opsizenum[map_opsize[params[1]]]
1821 if align then
1822 local x = align
1823 -- Must be a power of 2 in the range (2 ... 256).
1824 for i=1,8 do
1825 x = x / 2
1826 if x == 1 then
1827 waction("ALIGN", nil, 1)
1828 wputxb(align-1) -- Action byte is 2**n-1.
1829 return
1833 werror("bad alignment")
1836 -- Spacing pseudo-opcode.
1837 map_op[".space_2"] = function(params)
1838 if not params then return "num [, filler]" end
1839 if secpos+1 > maxsecpos then wflush() end
1840 waction("SPACE", params[1])
1841 local fill = params[2]
1842 if fill then
1843 fill = tonumber(fill)
1844 if not fill or fill < 0 or fill > 255 then werror("bad filler") end
1846 wputxb(fill or 0)
1848 map_op[".space_1"] = map_op[".space_2"]
1850 ------------------------------------------------------------------------------
1852 -- Pseudo-opcode for (primitive) type definitions (map to C types).
1853 map_op[".type_3"] = function(params, nparams)
1854 if not params then
1855 return nparams == 2 and "name, ctype" or "name, ctype, reg"
1857 local name, ctype, reg = params[1], params[2], params[3]
1858 if not match(name, "^[%a_][%w_]*$") then
1859 werror("bad type name `"..name.."'")
1861 local tp = map_type[name]
1862 if tp then
1863 werror("duplicate type `"..name.."'")
1865 if reg and not map_reg_valid_base[reg] then
1866 werror("bad base register `"..(map_reg_rev[reg] or reg).."'")
1868 -- Add #type to defines. A bit unclean to put it in map_archdef.
1869 map_archdef["#"..name] = "sizeof("..ctype..")"
1870 -- Add new type and emit shortcut define.
1871 local num = ctypenum + 1
1872 map_type[name] = {
1873 ctype = ctype,
1874 ctypefmt = format("Dt%X(%%s)", num),
1875 reg = reg,
1877 wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
1878 ctypenum = num
1880 map_op[".type_2"] = map_op[".type_3"]
1882 -- Dump type definitions.
1883 local function dumptypes(out, lvl)
1884 local t = {}
1885 for name in pairs(map_type) do t[#t+1] = name end
1886 sort(t)
1887 out:write("Type definitions:\n")
1888 for _,name in ipairs(t) do
1889 local tp = map_type[name]
1890 local reg = tp.reg and map_reg_rev[tp.reg] or ""
1891 out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
1893 out:write("\n")
1896 ------------------------------------------------------------------------------
1898 -- Set the current section.
1899 function _M.section(num)
1900 waction("SECTION")
1901 wputxb(num)
1902 wflush(true) -- SECTION is a terminal action.
1905 ------------------------------------------------------------------------------
1907 -- Dump architecture description.
1908 function _M.dumparch(out)
1909 out:write(format("DynASM %s version %s, released %s\n\n",
1910 _info.arch, _info.version, _info.release))
1911 dumpregs(out)
1912 dumpactions(out)
1915 -- Dump all user defined elements.
1916 function _M.dumpdef(out, lvl)
1917 dumptypes(out, lvl)
1918 dumpglobals(out, lvl)
1919 dumpexterns(out, lvl)
1922 ------------------------------------------------------------------------------
1924 -- Pass callbacks from/to the DynASM core.
1925 function _M.passcb(wl, we, wf, ww)
1926 wline, werror, wfatal, wwarn = wl, we, wf, ww
1927 return wflush
1930 -- Setup the arch-specific module.
1931 function _M.setup(arch, opt)
1932 g_arch, g_opt = arch, opt
1935 -- Merge the core maps and the arch-specific maps.
1936 function _M.mergemaps(map_coreop, map_def)
1937 setmetatable(map_op, { __index = map_coreop })
1938 setmetatable(map_def, { __index = map_archdef })
1939 return map_op, map_def
1942 return _M
1944 ------------------------------------------------------------------------------