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