aboutsummaryrefslogtreecommitdiff
path: root/src/jit
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit')
-rw-r--r--src/jit/bc.lua19
-rw-r--r--src/jit/bcsave.lua106
-rw-r--r--src/jit/dis_arm.lua18
-rw-r--r--src/jit/dis_arm64.lua1216
-rw-r--r--src/jit/dis_arm64be.lua12
-rw-r--r--src/jit/dis_mips.lua372
-rw-r--r--src/jit/dis_mips64.lua17
-rw-r--r--src/jit/dis_mips64el.lua17
-rw-r--r--src/jit/dis_mips64r6.lua17
-rw-r--r--src/jit/dis_mips64r6el.lua17
-rw-r--r--src/jit/dis_mipsel.lua15
-rw-r--r--src/jit/dis_ppc.lua18
-rw-r--r--src/jit/dis_x64.lua15
-rw-r--r--src/jit/dis_x86.lua297
-rw-r--r--src/jit/dump.lua54
-rw-r--r--src/jit/p.lua311
-rw-r--r--src/jit/v.lua17
-rw-r--r--src/jit/zone.lua45
18 files changed, 2318 insertions, 265 deletions
diff --git a/src/jit/bc.lua b/src/jit/bc.lua
index 37c4d3f6..e58a3fef 100644
--- a/src/jit/bc.lua
+++ b/src/jit/bc.lua
@@ -41,7 +41,7 @@
41 41
42-- Cache some library functions and objects. 42-- Cache some library functions and objects.
43local jit = require("jit") 43local jit = require("jit")
44assert(jit.version_num == 20005, "LuaJIT core/library version mismatch") 44assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
45local jutil = require("jit.util") 45local jutil = require("jit.util")
46local vmdef = require("jit.vmdef") 46local vmdef = require("jit.vmdef")
47local bit = require("bit") 47local bit = require("bit")
@@ -179,13 +179,12 @@ local function bcliston(outfile)
179end 179end
180 180
181-- Public module functions. 181-- Public module functions.
182module(...) 182return {
183 183 line = bcline,
184line = bcline 184 dump = bcdump,
185dump = bcdump 185 targets = bctargets,
186targets = bctargets 186 on = bcliston,
187 187 off = bclistoff,
188on = bcliston 188 start = bcliston -- For -j command line option.
189off = bclistoff 189}
190start = bcliston -- For -j command line option.
191 190
diff --git a/src/jit/bcsave.lua b/src/jit/bcsave.lua
index 73654297..ab13667a 100644
--- a/src/jit/bcsave.lua
+++ b/src/jit/bcsave.lua
@@ -11,12 +11,16 @@
11------------------------------------------------------------------------------ 11------------------------------------------------------------------------------
12 12
13local jit = require("jit") 13local jit = require("jit")
14assert(jit.version_num == 20005, "LuaJIT core/library version mismatch") 14assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
15local bit = require("bit") 15local bit = require("bit")
16 16
17-- Symbol name prefix for LuaJIT bytecode. 17-- Symbol name prefix for LuaJIT bytecode.
18local LJBC_PREFIX = "luaJIT_BC_" 18local LJBC_PREFIX = "luaJIT_BC_"
19 19
20local type, assert = type, assert
21local format = string.format
22local tremove, tconcat = table.remove, table.concat
23
20------------------------------------------------------------------------------ 24------------------------------------------------------------------------------
21 25
22local function usage() 26local function usage()
@@ -63,8 +67,18 @@ local map_type = {
63} 67}
64 68
65local map_arch = { 69local map_arch = {
66 x86 = true, x64 = true, arm = true, ppc = true, ppcspe = true, 70 x86 = { e = "le", b = 32, m = 3, p = 0x14c, },
67 mips = true, mipsel = true, 71 x64 = { e = "le", b = 64, m = 62, p = 0x8664, },
72 arm = { e = "le", b = 32, m = 40, p = 0x1c0, },
73 arm64 = { e = "le", b = 64, m = 183, p = 0xaa64, },
74 arm64be = { e = "be", b = 64, m = 183, },
75 ppc = { e = "be", b = 32, m = 20, },
76 mips = { e = "be", b = 32, m = 8, f = 0x50001006, },
77 mipsel = { e = "le", b = 32, m = 8, f = 0x50001006, },
78 mips64 = { e = "be", b = 64, m = 8, f = 0x80000007, },
79 mips64el = { e = "le", b = 64, m = 8, f = 0x80000007, },
80 mips64r6 = { e = "be", b = 64, m = 8, f = 0xa0000407, },
81 mips64r6el = { e = "le", b = 64, m = 8, f = 0xa0000407, },
68} 82}
69 83
70local map_os = { 84local map_os = {
@@ -73,33 +87,33 @@ local map_os = {
73} 87}
74 88
75local function checkarg(str, map, err) 89local function checkarg(str, map, err)
76 str = string.lower(str) 90 str = str:lower()
77 local s = check(map[str], "unknown ", err) 91 local s = check(map[str], "unknown ", err)
78 return s == true and str or s 92 return type(s) == "string" and s or str
79end 93end
80 94
81local function detecttype(str) 95local function detecttype(str)
82 local ext = string.match(string.lower(str), "%.(%a+)$") 96 local ext = str:lower():match("%.(%a+)$")
83 return map_type[ext] or "raw" 97 return map_type[ext] or "raw"
84end 98end
85 99
86local function checkmodname(str) 100local function checkmodname(str)
87 check(string.match(str, "^[%w_.%-]+$"), "bad module name") 101 check(str:match("^[%w_.%-]+$"), "bad module name")
88 return string.gsub(str, "[%.%-]", "_") 102 return str:gsub("[%.%-]", "_")
89end 103end
90 104
91local function detectmodname(str) 105local function detectmodname(str)
92 if type(str) == "string" then 106 if type(str) == "string" then
93 local tail = string.match(str, "[^/\\]+$") 107 local tail = str:match("[^/\\]+$")
94 if tail then str = tail end 108 if tail then str = tail end
95 local head = string.match(str, "^(.*)%.[^.]*$") 109 local head = str:match("^(.*)%.[^.]*$")
96 if head then str = head end 110 if head then str = head end
97 str = string.match(str, "^[%w_.%-]+") 111 str = str:match("^[%w_.%-]+")
98 else 112 else
99 str = nil 113 str = nil
100 end 114 end
101 check(str, "cannot derive module name, use -n name") 115 check(str, "cannot derive module name, use -n name")
102 return string.gsub(str, "[%.%-]", "_") 116 return str:gsub("[%.%-]", "_")
103end 117end
104 118
105------------------------------------------------------------------------------ 119------------------------------------------------------------------------------
@@ -118,19 +132,19 @@ end
118local function bcsave_c(ctx, output, s) 132local function bcsave_c(ctx, output, s)
119 local fp = savefile(output, "w") 133 local fp = savefile(output, "w")
120 if ctx.type == "c" then 134 if ctx.type == "c" then
121 fp:write(string.format([[ 135 fp:write(format([[
122#ifdef __cplusplus 136#ifdef __cplusplus
123extern "C" 137extern "C"
124#endif 138#endif
125#ifdef _WIN32 139#ifdef _WIN32
126__declspec(dllexport) 140__declspec(dllexport)
127#endif 141#endif
128const char %s%s[] = { 142const unsigned char %s%s[] = {
129]], LJBC_PREFIX, ctx.modname)) 143]], LJBC_PREFIX, ctx.modname))
130 else 144 else
131 fp:write(string.format([[ 145 fp:write(format([[
132#define %s%s_SIZE %d 146#define %s%s_SIZE %d
133static const char %s%s[] = { 147static const unsigned char %s%s[] = {
134]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname)) 148]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname))
135 end 149 end
136 local t, n, m = {}, 0, 0 150 local t, n, m = {}, 0, 0
@@ -138,13 +152,13 @@ static const char %s%s[] = {
138 local b = tostring(string.byte(s, i)) 152 local b = tostring(string.byte(s, i))
139 m = m + #b + 1 153 m = m + #b + 1
140 if m > 78 then 154 if m > 78 then
141 fp:write(table.concat(t, ",", 1, n), ",\n") 155 fp:write(tconcat(t, ",", 1, n), ",\n")
142 n, m = 0, #b + 1 156 n, m = 0, #b + 1
143 end 157 end
144 n = n + 1 158 n = n + 1
145 t[n] = b 159 t[n] = b
146 end 160 end
147 bcsave_tail(fp, output, table.concat(t, ",", 1, n).."\n};\n") 161 bcsave_tail(fp, output, tconcat(t, ",", 1, n).."\n};\n")
148end 162end
149 163
150local function bcsave_elfobj(ctx, output, s, ffi) 164local function bcsave_elfobj(ctx, output, s, ffi)
@@ -199,12 +213,8 @@ typedef struct {
199} ELF64obj; 213} ELF64obj;
200]] 214]]
201 local symname = LJBC_PREFIX..ctx.modname 215 local symname = LJBC_PREFIX..ctx.modname
202 local is64, isbe = false, false 216 local ai = assert(map_arch[ctx.arch])
203 if ctx.arch == "x64" then 217 local is64, isbe = ai.b == 64, ai.e == "be"
204 is64 = true
205 elseif ctx.arch == "ppc" or ctx.arch == "ppcspe" or ctx.arch == "mips" then
206 isbe = true
207 end
208 218
209 -- Handle different host/target endianess. 219 -- Handle different host/target endianess.
210 local function f32(x) return x end 220 local function f32(x) return x end
@@ -237,10 +247,8 @@ typedef struct {
237 hdr.eendian = isbe and 2 or 1 247 hdr.eendian = isbe and 2 or 1
238 hdr.eversion = 1 248 hdr.eversion = 1
239 hdr.type = f16(1) 249 hdr.type = f16(1)
240 hdr.machine = f16(({ x86=3, x64=62, arm=40, ppc=20, ppcspe=20, mips=8, mipsel=8 })[ctx.arch]) 250 hdr.machine = f16(ai.m)
241 if ctx.arch == "mips" or ctx.arch == "mipsel" then 251 hdr.flags = f32(ai.f or 0)
242 hdr.flags = f32(0x50001006)
243 end
244 hdr.version = f32(1) 252 hdr.version = f32(1)
245 hdr.shofs = fofs(ffi.offsetof(o, "sect")) 253 hdr.shofs = fofs(ffi.offsetof(o, "sect"))
246 hdr.ehsize = f16(ffi.sizeof(hdr)) 254 hdr.ehsize = f16(ffi.sizeof(hdr))
@@ -336,12 +344,8 @@ typedef struct {
336} PEobj; 344} PEobj;
337]] 345]]
338 local symname = LJBC_PREFIX..ctx.modname 346 local symname = LJBC_PREFIX..ctx.modname
339 local is64 = false 347 local ai = assert(map_arch[ctx.arch])
340 if ctx.arch == "x86" then 348 local is64 = ai.b == 64
341 symname = "_"..symname
342 elseif ctx.arch == "x64" then
343 is64 = true
344 end
345 local symexport = " /EXPORT:"..symname..",DATA " 349 local symexport = " /EXPORT:"..symname..",DATA "
346 350
347 -- The file format is always little-endian. Swap if the host is big-endian. 351 -- The file format is always little-endian. Swap if the host is big-endian.
@@ -355,7 +359,7 @@ typedef struct {
355 -- Create PE object and fill in header. 359 -- Create PE object and fill in header.
356 local o = ffi.new("PEobj") 360 local o = ffi.new("PEobj")
357 local hdr = o.hdr 361 local hdr = o.hdr
358 hdr.arch = f16(({ x86=0x14c, x64=0x8664, arm=0x1c0, ppc=0x1f2, mips=0x366, mipsel=0x366 })[ctx.arch]) 362 hdr.arch = f16(assert(ai.p))
359 hdr.nsects = f16(2) 363 hdr.nsects = f16(2)
360 hdr.symtabofs = f32(ffi.offsetof(o, "sym0")) 364 hdr.symtabofs = f32(ffi.offsetof(o, "sym0"))
361 hdr.nsyms = f32(6) 365 hdr.nsyms = f32(6)
@@ -477,13 +481,13 @@ typedef struct {
477} mach_obj_64; 481} mach_obj_64;
478typedef struct { 482typedef struct {
479 mach_fat_header fat; 483 mach_fat_header fat;
480 mach_fat_arch fat_arch[4]; 484 mach_fat_arch fat_arch[2];
481 struct { 485 struct {
482 mach_header hdr; 486 mach_header hdr;
483 mach_segment_command seg; 487 mach_segment_command seg;
484 mach_section sec; 488 mach_section sec;
485 mach_symtab_command sym; 489 mach_symtab_command sym;
486 } arch[4]; 490 } arch[2];
487 mach_nlist sym_entry; 491 mach_nlist sym_entry;
488 uint8_t space[4096]; 492 uint8_t space[4096];
489} mach_fat_obj; 493} mach_fat_obj;
@@ -494,6 +498,8 @@ typedef struct {
494 is64, align, mobj = true, 8, "mach_obj_64" 498 is64, align, mobj = true, 8, "mach_obj_64"
495 elseif ctx.arch == "arm" then 499 elseif ctx.arch == "arm" then
496 isfat, mobj = true, "mach_fat_obj" 500 isfat, mobj = true, "mach_fat_obj"
501 elseif ctx.arch == "arm64" then
502 is64, align, isfat, mobj = true, 8, true, "mach_fat_obj"
497 else 503 else
498 check(ctx.arch == "x86", "unsupported architecture for OSX") 504 check(ctx.arch == "x86", "unsupported architecture for OSX")
499 end 505 end
@@ -503,8 +509,8 @@ typedef struct {
503 -- Create Mach-O object and fill in header. 509 -- Create Mach-O object and fill in header.
504 local o = ffi.new(mobj) 510 local o = ffi.new(mobj)
505 local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align) 511 local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align)
506 local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12,12,12} })[ctx.arch] 512 local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12}, arm64={0x01000007,0x0100000c} })[ctx.arch]
507 local cpusubtype = ({ x86={3}, x64={3}, arm={3,6,9,11} })[ctx.arch] 513 local cpusubtype = ({ x86={3}, x64={3}, arm={3,9}, arm64={3,0} })[ctx.arch]
508 if isfat then 514 if isfat then
509 o.fat.magic = be32(0xcafebabe) 515 o.fat.magic = be32(0xcafebabe)
510 o.fat.nfat_arch = be32(#cpusubtype) 516 o.fat.nfat_arch = be32(#cpusubtype)
@@ -603,16 +609,16 @@ local function docmd(...)
603 local n = 1 609 local n = 1
604 local list = false 610 local list = false
605 local ctx = { 611 local ctx = {
606 strip = true, arch = jit.arch, os = string.lower(jit.os), 612 strip = true, arch = jit.arch, os = jit.os:lower(),
607 type = false, modname = false, 613 type = false, modname = false,
608 } 614 }
609 while n <= #arg do 615 while n <= #arg do
610 local a = arg[n] 616 local a = arg[n]
611 if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then 617 if type(a) == "string" and a:sub(1, 1) == "-" and a ~= "-" then
612 table.remove(arg, n) 618 tremove(arg, n)
613 if a == "--" then break end 619 if a == "--" then break end
614 for m=2,#a do 620 for m=2,#a do
615 local opt = string.sub(a, m, m) 621 local opt = a:sub(m, m)
616 if opt == "l" then 622 if opt == "l" then
617 list = true 623 list = true
618 elseif opt == "s" then 624 elseif opt == "s" then
@@ -625,13 +631,13 @@ local function docmd(...)
625 if n ~= 1 then usage() end 631 if n ~= 1 then usage() end
626 arg[1] = check(loadstring(arg[1])) 632 arg[1] = check(loadstring(arg[1]))
627 elseif opt == "n" then 633 elseif opt == "n" then
628 ctx.modname = checkmodname(table.remove(arg, n)) 634 ctx.modname = checkmodname(tremove(arg, n))
629 elseif opt == "t" then 635 elseif opt == "t" then
630 ctx.type = checkarg(table.remove(arg, n), map_type, "file type") 636 ctx.type = checkarg(tremove(arg, n), map_type, "file type")
631 elseif opt == "a" then 637 elseif opt == "a" then
632 ctx.arch = checkarg(table.remove(arg, n), map_arch, "architecture") 638 ctx.arch = checkarg(tremove(arg, n), map_arch, "architecture")
633 elseif opt == "o" then 639 elseif opt == "o" then
634 ctx.os = checkarg(table.remove(arg, n), map_os, "OS name") 640 ctx.os = checkarg(tremove(arg, n), map_os, "OS name")
635 else 641 else
636 usage() 642 usage()
637 end 643 end
@@ -653,7 +659,7 @@ end
653------------------------------------------------------------------------------ 659------------------------------------------------------------------------------
654 660
655-- Public module functions. 661-- Public module functions.
656module(...) 662return {
657 663 start = docmd -- Process -b command line option.
658start = docmd -- Process -b command line option. 664}
659 665
diff --git a/src/jit/dis_arm.lua b/src/jit/dis_arm.lua
index cd3acbd7..ba79c47e 100644
--- a/src/jit/dis_arm.lua
+++ b/src/jit/dis_arm.lua
@@ -658,7 +658,7 @@ local function disass_block(ctx, ofs, len)
658end 658end
659 659
660-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). 660-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
661local function create_(code, addr, out) 661local function create(code, addr, out)
662 local ctx = {} 662 local ctx = {}
663 ctx.code = code 663 ctx.code = code
664 ctx.addr = addr or 0 664 ctx.addr = addr or 0
@@ -670,20 +670,20 @@ local function create_(code, addr, out)
670end 670end
671 671
672-- Simple API: disassemble code (a string) at address and output via out. 672-- Simple API: disassemble code (a string) at address and output via out.
673local function disass_(code, addr, out) 673local function disass(code, addr, out)
674 create_(code, addr, out):disass() 674 create(code, addr, out):disass()
675end 675end
676 676
677-- Return register name for RID. 677-- Return register name for RID.
678local function regname_(r) 678local function regname(r)
679 if r < 16 then return map_gpr[r] end 679 if r < 16 then return map_gpr[r] end
680 return "d"..(r-16) 680 return "d"..(r-16)
681end 681end
682 682
683-- Public module functions. 683-- Public module functions.
684module(...) 684return {
685 685 create = create,
686create = create_ 686 disass = disass,
687disass = disass_ 687 regname = regname
688regname = regname_ 688}
689 689
diff --git a/src/jit/dis_arm64.lua b/src/jit/dis_arm64.lua
new file mode 100644
index 00000000..ea7ca828
--- /dev/null
+++ b/src/jit/dis_arm64.lua
@@ -0,0 +1,1216 @@
1----------------------------------------------------------------------------
2-- LuaJIT ARM64 disassembler module.
3--
4-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
5-- Released under the MIT license. See Copyright Notice in luajit.h
6--
7-- Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com.
8-- Sponsored by Cisco Systems, Inc.
9----------------------------------------------------------------------------
10-- This is a helper module used by the LuaJIT machine code dumper module.
11--
12-- It disassembles most user-mode AArch64 instructions.
13-- NYI: Advanced SIMD and VFP instructions.
14------------------------------------------------------------------------------
15
16local type = type
17local sub, byte, format = string.sub, string.byte, string.format
18local match, gmatch, gsub = string.match, string.gmatch, string.gsub
19local concat = table.concat
20local bit = require("bit")
21local band, bor, bxor, tohex = bit.band, bit.bor, bit.bxor, bit.tohex
22local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
23local ror = bit.ror
24
25------------------------------------------------------------------------------
26-- Opcode maps
27------------------------------------------------------------------------------
28
29local map_adr = { -- PC-relative addressing.
30 shift = 31, mask = 1,
31 [0] = "adrDBx", "adrpDBx"
32}
33
34local map_addsubi = { -- Add/subtract immediate.
35 shift = 29, mask = 3,
36 [0] = "add|movDNIg", "adds|cmnD0NIg", "subDNIg", "subs|cmpD0NIg",
37}
38
39local map_logi = { -- Logical immediate.
40 shift = 31, mask = 1,
41 [0] = {
42 shift = 22, mask = 1,
43 [0] = {
44 shift = 29, mask = 3,
45 [0] = "andDNig", "orr|movDN0ig", "eorDNig", "ands|tstD0Nig"
46 },
47 false -- unallocated
48 },
49 {
50 shift = 29, mask = 3,
51 [0] = "andDNig", "orr|movDN0ig", "eorDNig", "ands|tstD0Nig"
52 }
53}
54
55local map_movwi = { -- Move wide immediate.
56 shift = 31, mask = 1,
57 [0] = {
58 shift = 22, mask = 1,
59 [0] = {
60 shift = 29, mask = 3,
61 [0] = "movnDWRg", false, "movz|movDYRg", "movkDWRg"
62 }, false -- unallocated
63 },
64 {
65 shift = 29, mask = 3,
66 [0] = "movnDWRg", false, "movz|movDYRg", "movkDWRg"
67 },
68}
69
70local map_bitf = { -- Bitfield.
71 shift = 31, mask = 1,
72 [0] = {
73 shift = 22, mask = 1,
74 [0] = {
75 shift = 29, mask = 3,
76 [0] = "sbfm|sbfiz|sbfx|asr|sxtw|sxth|sxtbDN12w",
77 "bfm|bfi|bfxilDN13w",
78 "ubfm|ubfiz|ubfx|lsr|lsl|uxth|uxtbDN12w"
79 }
80 },
81 {
82 shift = 22, mask = 1,
83 {
84 shift = 29, mask = 3,
85 [0] = "sbfm|sbfiz|sbfx|asr|sxtw|sxth|sxtbDN12x",
86 "bfm|bfi|bfxilDN13x",
87 "ubfm|ubfiz|ubfx|lsr|lsl|uxth|uxtbDN12x"
88 }
89 }
90}
91
92local map_datai = { -- Data processing - immediate.
93 shift = 23, mask = 7,
94 [0] = map_adr, map_adr, map_addsubi, false,
95 map_logi, map_movwi, map_bitf,
96 {
97 shift = 15, mask = 0x1c0c1,
98 [0] = "extr|rorDNM4w", [0x10080] = "extr|rorDNM4x",
99 [0x10081] = "extr|rorDNM4x"
100 }
101}
102
103local map_logsr = { -- Logical, shifted register.
104 shift = 31, mask = 1,
105 [0] = {
106 shift = 15, mask = 1,
107 [0] = {
108 shift = 29, mask = 3,
109 [0] = {
110 shift = 21, mask = 7,
111 [0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg",
112 "andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg"
113 },
114 {
115 shift = 21, mask = 7,
116 [0] ="orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg",
117 "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg"
118 },
119 {
120 shift = 21, mask = 7,
121 [0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg",
122 "eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg"
123 },
124 {
125 shift = 21, mask = 7,
126 [0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg",
127 "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg"
128 }
129 },
130 false -- unallocated
131 },
132 {
133 shift = 29, mask = 3,
134 [0] = {
135 shift = 21, mask = 7,
136 [0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg",
137 "andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg"
138 },
139 {
140 shift = 21, mask = 7,
141 [0] = "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg",
142 "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg"
143 },
144 {
145 shift = 21, mask = 7,
146 [0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg",
147 "eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg"
148 },
149 {
150 shift = 21, mask = 7,
151 [0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg",
152 "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg"
153 }
154 }
155}
156
157local map_assh = {
158 shift = 31, mask = 1,
159 [0] = {
160 shift = 15, mask = 1,
161 [0] = {
162 shift = 29, mask = 3,
163 [0] = {
164 shift = 22, mask = 3,
165 [0] = "addDNMSg", "addDNMSg", "addDNMSg", "addDNMg"
166 },
167 {
168 shift = 22, mask = 3,
169 [0] = "adds|cmnD0NMSg", "adds|cmnD0NMSg",
170 "adds|cmnD0NMSg", "adds|cmnD0NMg"
171 },
172 {
173 shift = 22, mask = 3,
174 [0] = "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0Mg"
175 },
176 {
177 shift = 22, mask = 3,
178 [0] = "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg",
179 "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0Mzg"
180 },
181 },
182 false -- unallocated
183 },
184 {
185 shift = 29, mask = 3,
186 [0] = {
187 shift = 22, mask = 3,
188 [0] = "addDNMSg", "addDNMSg", "addDNMSg", "addDNMg"
189 },
190 {
191 shift = 22, mask = 3,
192 [0] = "adds|cmnD0NMSg", "adds|cmnD0NMSg", "adds|cmnD0NMSg",
193 "adds|cmnD0NMg"
194 },
195 {
196 shift = 22, mask = 3,
197 [0] = "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0Mg"
198 },
199 {
200 shift = 22, mask = 3,
201 [0] = "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg",
202 "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0Mzg"
203 }
204 }
205}
206
207local map_addsubsh = { -- Add/subtract, shifted register.
208 shift = 22, mask = 3,
209 [0] = map_assh, map_assh, map_assh
210}
211
212local map_addsubex = { -- Add/subtract, extended register.
213 shift = 22, mask = 3,
214 [0] = {
215 shift = 29, mask = 3,
216 [0] = "addDNMXg", "adds|cmnD0NMXg", "subDNMXg", "subs|cmpD0NMzXg",
217 }
218}
219
220local map_addsubc = { -- Add/subtract, with carry.
221 shift = 10, mask = 63,
222 [0] = {
223 shift = 29, mask = 3,
224 [0] = "adcDNMg", "adcsDNMg", "sbc|ngcDN0Mg", "sbcs|ngcsDN0Mg",
225 }
226}
227
228local map_ccomp = {
229 shift = 4, mask = 1,
230 [0] = {
231 shift = 10, mask = 3,
232 [0] = { -- Conditional compare register.
233 shift = 29, mask = 3,
234 "ccmnNMVCg", false, "ccmpNMVCg",
235 },
236 [2] = { -- Conditional compare immediate.
237 shift = 29, mask = 3,
238 "ccmnN5VCg", false, "ccmpN5VCg",
239 }
240 }
241}
242
243local map_csel = { -- Conditional select.
244 shift = 11, mask = 1,
245 [0] = {
246 shift = 10, mask = 1,
247 [0] = {
248 shift = 29, mask = 3,
249 [0] = "cselDNMzCg", false, "csinv|cinv|csetmDNMcg", false,
250 },
251 {
252 shift = 29, mask = 3,
253 [0] = "csinc|cinc|csetDNMcg", false, "csneg|cnegDNMcg", false,
254 }
255 }
256}
257
258local map_data1s = { -- Data processing, 1 source.
259 shift = 29, mask = 1,
260 [0] = {
261 shift = 31, mask = 1,
262 [0] = {
263 shift = 10, mask = 0x7ff,
264 [0] = "rbitDNg", "rev16DNg", "revDNw", false, "clzDNg", "clsDNg"
265 },
266 {
267 shift = 10, mask = 0x7ff,
268 [0] = "rbitDNg", "rev16DNg", "rev32DNx", "revDNx", "clzDNg", "clsDNg"
269 }
270 }
271}
272
273local map_data2s = { -- Data processing, 2 sources.
274 shift = 29, mask = 1,
275 [0] = {
276 shift = 10, mask = 63,
277 false, "udivDNMg", "sdivDNMg", false, false, false, false, "lslDNMg",
278 "lsrDNMg", "asrDNMg", "rorDNMg"
279 }
280}
281
282local map_data3s = { -- Data processing, 3 sources.
283 shift = 29, mask = 7,
284 [0] = {
285 shift = 21, mask = 7,
286 [0] = {
287 shift = 15, mask = 1,
288 [0] = "madd|mulDNMA0g", "msub|mnegDNMA0g"
289 }
290 }, false, false, false,
291 {
292 shift = 15, mask = 1,
293 [0] = {
294 shift = 21, mask = 7,
295 [0] = "madd|mulDNMA0g", "smaddl|smullDxNMwA0x", "smulhDNMx", false,
296 false, "umaddl|umullDxNMwA0x", "umulhDNMx"
297 },
298 {
299 shift = 21, mask = 7,
300 [0] = "msub|mnegDNMA0g", "smsubl|smneglDxNMwA0x", false, false,
301 false, "umsubl|umneglDxNMwA0x"
302 }
303 }
304}
305
306local map_datar = { -- Data processing, register.
307 shift = 28, mask = 1,
308 [0] = {
309 shift = 24, mask = 1,
310 [0] = map_logsr,
311 {
312 shift = 21, mask = 1,
313 [0] = map_addsubsh, map_addsubex
314 }
315 },
316 {
317 shift = 21, mask = 15,
318 [0] = map_addsubc, false, map_ccomp, false, map_csel, false,
319 {
320 shift = 30, mask = 1,
321 [0] = map_data2s, map_data1s
322 },
323 false, map_data3s, map_data3s, map_data3s, map_data3s, map_data3s,
324 map_data3s, map_data3s, map_data3s
325 }
326}
327
328local map_lrl = { -- Load register, literal.
329 shift = 26, mask = 1,
330 [0] = {
331 shift = 30, mask = 3,
332 [0] = "ldrDwB", "ldrDxB", "ldrswDxB"
333 },
334 {
335 shift = 30, mask = 3,
336 [0] = "ldrDsB", "ldrDdB"
337 }
338}
339
340local map_lsriind = { -- Load/store register, immediate pre/post-indexed.
341 shift = 30, mask = 3,
342 [0] = {
343 shift = 26, mask = 1,
344 [0] = {
345 shift = 22, mask = 3,
346 [0] = "strbDwzL", "ldrbDwzL", "ldrsbDxzL", "ldrsbDwzL"
347 }
348 },
349 {
350 shift = 26, mask = 1,
351 [0] = {
352 shift = 22, mask = 3,
353 [0] = "strhDwzL", "ldrhDwzL", "ldrshDxzL", "ldrshDwzL"
354 }
355 },
356 {
357 shift = 26, mask = 1,
358 [0] = {
359 shift = 22, mask = 3,
360 [0] = "strDwzL", "ldrDwzL", "ldrswDxzL"
361 },
362 {
363 shift = 22, mask = 3,
364 [0] = "strDszL", "ldrDszL"
365 }
366 },
367 {
368 shift = 26, mask = 1,
369 [0] = {
370 shift = 22, mask = 3,
371 [0] = "strDxzL", "ldrDxzL"
372 },
373 {
374 shift = 22, mask = 3,
375 [0] = "strDdzL", "ldrDdzL"
376 }
377 }
378}
379
380local map_lsriro = {
381 shift = 21, mask = 1,
382 [0] = { -- Load/store register immediate.
383 shift = 10, mask = 3,
384 [0] = { -- Unscaled immediate.
385 shift = 26, mask = 1,
386 [0] = {
387 shift = 30, mask = 3,
388 [0] = {
389 shift = 22, mask = 3,
390 [0] = "sturbDwK", "ldurbDwK"
391 },
392 {
393 shift = 22, mask = 3,
394 [0] = "sturhDwK", "ldurhDwK"
395 },
396 {
397 shift = 22, mask = 3,
398 [0] = "sturDwK", "ldurDwK"
399 },
400 {
401 shift = 22, mask = 3,
402 [0] = "sturDxK", "ldurDxK"
403 }
404 }
405 }, map_lsriind, false, map_lsriind
406 },
407 { -- Load/store register, register offset.
408 shift = 10, mask = 3,
409 [2] = {
410 shift = 26, mask = 1,
411 [0] = {
412 shift = 30, mask = 3,
413 [0] = {
414 shift = 22, mask = 3,
415 [0] = "strbDwO", "ldrbDwO", "ldrsbDxO", "ldrsbDwO"
416 },
417 {
418 shift = 22, mask = 3,
419 [0] = "strhDwO", "ldrhDwO", "ldrshDxO", "ldrshDwO"
420 },
421 {
422 shift = 22, mask = 3,
423 [0] = "strDwO", "ldrDwO", "ldrswDxO"
424 },
425 {
426 shift = 22, mask = 3,
427 [0] = "strDxO", "ldrDxO"
428 }
429 },
430 {
431 shift = 30, mask = 3,
432 [2] = {
433 shift = 22, mask = 3,
434 [0] = "strDsO", "ldrDsO"
435 },
436 [3] = {
437 shift = 22, mask = 3,
438 [0] = "strDdO", "ldrDdO"
439 }
440 }
441 }
442 }
443}
444
445local map_lsp = { -- Load/store register pair, offset.
446 shift = 22, mask = 1,
447 [0] = {
448 shift = 30, mask = 3,
449 [0] = {
450 shift = 26, mask = 1,
451 [0] = "stpDzAzwP", "stpDzAzsP",
452 },
453 {
454 shift = 26, mask = 1,
455 "stpDzAzdP"
456 },
457 {
458 shift = 26, mask = 1,
459 [0] = "stpDzAzxP"
460 }
461 },
462 {
463 shift = 30, mask = 3,
464 [0] = {
465 shift = 26, mask = 1,
466 [0] = "ldpDzAzwP", "ldpDzAzsP",
467 },
468 {
469 shift = 26, mask = 1,
470 [0] = "ldpswDAxP", "ldpDzAzdP"
471 },
472 {
473 shift = 26, mask = 1,
474 [0] = "ldpDzAzxP"
475 }
476 }
477}
478
479local map_ls = { -- Loads and stores.
480 shift = 24, mask = 0x31,
481 [0x10] = map_lrl, [0x30] = map_lsriro,
482 [0x20] = {
483 shift = 23, mask = 3,
484 map_lsp, map_lsp, map_lsp
485 },
486 [0x21] = {
487 shift = 23, mask = 3,
488 map_lsp, map_lsp, map_lsp
489 },
490 [0x31] = {
491 shift = 26, mask = 1,
492 [0] = {
493 shift = 30, mask = 3,
494 [0] = {
495 shift = 22, mask = 3,
496 [0] = "strbDwzU", "ldrbDwzU"
497 },
498 {
499 shift = 22, mask = 3,
500 [0] = "strhDwzU", "ldrhDwzU"
501 },
502 {
503 shift = 22, mask = 3,
504 [0] = "strDwzU", "ldrDwzU"
505 },
506 {
507 shift = 22, mask = 3,
508 [0] = "strDxzU", "ldrDxzU"
509 }
510 },
511 {
512 shift = 30, mask = 3,
513 [2] = {
514 shift = 22, mask = 3,
515 [0] = "strDszU", "ldrDszU"
516 },
517 [3] = {
518 shift = 22, mask = 3,
519 [0] = "strDdzU", "ldrDdzU"
520 }
521 }
522 },
523}
524
525local map_datafp = { -- Data processing, SIMD and FP.
526 shift = 28, mask = 7,
527 { -- 001
528 shift = 24, mask = 1,
529 [0] = {
530 shift = 21, mask = 1,
531 {
532 shift = 10, mask = 3,
533 [0] = {
534 shift = 12, mask = 1,
535 [0] = {
536 shift = 13, mask = 1,
537 [0] = {
538 shift = 14, mask = 1,
539 [0] = {
540 shift = 15, mask = 1,
541 [0] = { -- FP/int conversion.
542 shift = 31, mask = 1,
543 [0] = {
544 shift = 16, mask = 0xff,
545 [0x20] = "fcvtnsDwNs", [0x21] = "fcvtnuDwNs",
546 [0x22] = "scvtfDsNw", [0x23] = "ucvtfDsNw",
547 [0x24] = "fcvtasDwNs", [0x25] = "fcvtauDwNs",
548 [0x26] = "fmovDwNs", [0x27] = "fmovDsNw",
549 [0x28] = "fcvtpsDwNs", [0x29] = "fcvtpuDwNs",
550 [0x30] = "fcvtmsDwNs", [0x31] = "fcvtmuDwNs",
551 [0x38] = "fcvtzsDwNs", [0x39] = "fcvtzuDwNs",
552 [0x60] = "fcvtnsDwNd", [0x61] = "fcvtnuDwNd",
553 [0x62] = "scvtfDdNw", [0x63] = "ucvtfDdNw",
554 [0x64] = "fcvtasDwNd", [0x65] = "fcvtauDwNd",
555 [0x68] = "fcvtpsDwNd", [0x69] = "fcvtpuDwNd",
556 [0x70] = "fcvtmsDwNd", [0x71] = "fcvtmuDwNd",
557 [0x78] = "fcvtzsDwNd", [0x79] = "fcvtzuDwNd"
558 },
559 {
560 shift = 16, mask = 0xff,
561 [0x20] = "fcvtnsDxNs", [0x21] = "fcvtnuDxNs",
562 [0x22] = "scvtfDsNx", [0x23] = "ucvtfDsNx",
563 [0x24] = "fcvtasDxNs", [0x25] = "fcvtauDxNs",
564 [0x28] = "fcvtpsDxNs", [0x29] = "fcvtpuDxNs",
565 [0x30] = "fcvtmsDxNs", [0x31] = "fcvtmuDxNs",
566 [0x38] = "fcvtzsDxNs", [0x39] = "fcvtzuDxNs",
567 [0x60] = "fcvtnsDxNd", [0x61] = "fcvtnuDxNd",
568 [0x62] = "scvtfDdNx", [0x63] = "ucvtfDdNx",
569 [0x64] = "fcvtasDxNd", [0x65] = "fcvtauDxNd",
570 [0x66] = "fmovDxNd", [0x67] = "fmovDdNx",
571 [0x68] = "fcvtpsDxNd", [0x69] = "fcvtpuDxNd",
572 [0x70] = "fcvtmsDxNd", [0x71] = "fcvtmuDxNd",
573 [0x78] = "fcvtzsDxNd", [0x79] = "fcvtzuDxNd"
574 }
575 }
576 },
577 { -- FP data-processing, 1 source.
578 shift = 31, mask = 1,
579 [0] = {
580 shift = 22, mask = 3,
581 [0] = {
582 shift = 15, mask = 63,
583 [0] = "fmovDNf", "fabsDNf", "fnegDNf",
584 "fsqrtDNf", false, "fcvtDdNs", false, false,
585 "frintnDNf", "frintpDNf", "frintmDNf", "frintzDNf",
586 "frintaDNf", false, "frintxDNf", "frintiDNf",
587 },
588 {
589 shift = 15, mask = 63,
590 [0] = "fmovDNf", "fabsDNf", "fnegDNf",
591 "fsqrtDNf", "fcvtDsNd", false, false, false,
592 "frintnDNf", "frintpDNf", "frintmDNf", "frintzDNf",
593 "frintaDNf", false, "frintxDNf", "frintiDNf",
594 }
595 }
596 }
597 },
598 { -- FP compare.
599 shift = 31, mask = 1,
600 [0] = {
601 shift = 14, mask = 3,
602 [0] = {
603 shift = 23, mask = 1,
604 [0] = {
605 shift = 0, mask = 31,
606 [0] = "fcmpNMf", [8] = "fcmpNZf",
607 [16] = "fcmpeNMf", [24] = "fcmpeNZf",
608 }
609 }
610 }
611 }
612 },
613 { -- FP immediate.
614 shift = 31, mask = 1,
615 [0] = {
616 shift = 5, mask = 31,
617 [0] = {
618 shift = 23, mask = 1,
619 [0] = "fmovDFf"
620 }
621 }
622 }
623 },
624 { -- FP conditional compare.
625 shift = 31, mask = 1,
626 [0] = {
627 shift = 23, mask = 1,
628 [0] = {
629 shift = 4, mask = 1,
630 [0] = "fccmpNMVCf", "fccmpeNMVCf"
631 }
632 }
633 },
634 { -- FP data-processing, 2 sources.
635 shift = 31, mask = 1,
636 [0] = {
637 shift = 23, mask = 1,
638 [0] = {
639 shift = 12, mask = 15,
640 [0] = "fmulDNMf", "fdivDNMf", "faddDNMf", "fsubDNMf",
641 "fmaxDNMf", "fminDNMf", "fmaxnmDNMf", "fminnmDNMf",
642 "fnmulDNMf"
643 }
644 }
645 },
646 { -- FP conditional select.
647 shift = 31, mask = 1,
648 [0] = {
649 shift = 23, mask = 1,
650 [0] = "fcselDNMCf"
651 }
652 }
653 }
654 },
655 { -- FP data-processing, 3 sources.
656 shift = 31, mask = 1,
657 [0] = {
658 shift = 15, mask = 1,
659 [0] = {
660 shift = 21, mask = 5,
661 [0] = "fmaddDNMAf", "fnmaddDNMAf"
662 },
663 {
664 shift = 21, mask = 5,
665 [0] = "fmsubDNMAf", "fnmsubDNMAf"
666 }
667 }
668 }
669 }
670}
671
672local map_br = { -- Branches, exception generating and system instructions.
673 shift = 29, mask = 7,
674 [0] = "bB",
675 { -- Compare & branch, immediate.
676 shift = 24, mask = 3,
677 [0] = "cbzDBg", "cbnzDBg", "tbzDTBw", "tbnzDTBw"
678 },
679 { -- Conditional branch, immediate.
680 shift = 24, mask = 3,
681 [0] = {
682 shift = 4, mask = 1,
683 [0] = {
684 shift = 0, mask = 15,
685 [0] = "beqB", "bneB", "bhsB", "bloB", "bmiB", "bplB", "bvsB", "bvcB",
686 "bhiB", "blsB", "bgeB", "bltB", "bgtB", "bleB", "balB"
687 }
688 }
689 }, false, "blB",
690 { -- Compare & branch, immediate.
691 shift = 24, mask = 3,
692 [0] = "cbzDBg", "cbnzDBg", "tbzDTBx", "tbnzDTBx"
693 },
694 {
695 shift = 24, mask = 3,
696 [0] = { -- Exception generation.
697 shift = 0, mask = 0xe0001f,
698 [0x200000] = "brkW"
699 },
700 { -- System instructions.
701 shift = 0, mask = 0x3fffff,
702 [0x03201f] = "nop"
703 },
704 { -- Unconditional branch, register.
705 shift = 0, mask = 0xfffc1f,
706 [0x1f0000] = "brNx", [0x3f0000] = "blrNx",
707 [0x5f0000] = "retNx"
708 },
709 }
710}
711
712local map_init = {
713 shift = 25, mask = 15,
714 [0] = false, false, false, false, map_ls, map_datar, map_ls, map_datafp,
715 map_datai, map_datai, map_br, map_br, map_ls, map_datar, map_ls, map_datafp
716}
717
718------------------------------------------------------------------------------
719
720local map_regs = { x = {}, w = {}, d = {}, s = {} }
721
722for i=0,30 do
723 map_regs.x[i] = "x"..i
724 map_regs.w[i] = "w"..i
725 map_regs.d[i] = "d"..i
726 map_regs.s[i] = "s"..i
727end
728map_regs.x[31] = "sp"
729map_regs.w[31] = "wsp"
730map_regs.d[31] = "d31"
731map_regs.s[31] = "s31"
732
733local map_cond = {
734 [0] = "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
735 "hi", "ls", "ge", "lt", "gt", "le", "al",
736}
737
738local map_shift = { [0] = "lsl", "lsr", "asr", }
739
740local map_extend = {
741 [0] = "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx",
742}
743
744------------------------------------------------------------------------------
745
746-- Output a nicely formatted line with an opcode and operands.
747local function putop(ctx, text, operands)
748 local pos = ctx.pos
749 local extra = ""
750 if ctx.rel then
751 local sym = ctx.symtab[ctx.rel]
752 if sym then
753 extra = "\t->"..sym
754 end
755 end
756 if ctx.hexdump > 0 then
757 ctx.out(format("%08x %s %-5s %s%s\n",
758 ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
759 else
760 ctx.out(format("%08x %-5s %s%s\n",
761 ctx.addr+pos, text, concat(operands, ", "), extra))
762 end
763 ctx.pos = pos + 4
764end
765
766-- Fallback for unknown opcodes.
767local function unknown(ctx)
768 return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
769end
770
771local function match_reg(p, pat, regnum)
772 return map_regs[match(pat, p.."%w-([xwds])")][regnum]
773end
774
775local function fmt_hex32(x)
776 if x < 0 then
777 return tohex(x)
778 else
779 return format("%x", x)
780 end
781end
782
783local imm13_rep = { 0x55555555, 0x11111111, 0x01010101, 0x00010001, 0x00000001 }
784
785local function decode_imm13(op)
786 local imms = band(rshift(op, 10), 63)
787 local immr = band(rshift(op, 16), 63)
788 if band(op, 0x00400000) == 0 then
789 local len = 5
790 if imms >= 56 then
791 if imms >= 60 then len = 1 else len = 2 end
792 elseif imms >= 48 then len = 3 elseif imms >= 32 then len = 4 end
793 local l = lshift(1, len)-1
794 local s = band(imms, l)
795 local r = band(immr, l)
796 local imm = ror(rshift(-1, 31-s), r)
797 if len ~= 5 then imm = band(imm, lshift(1, l)-1) + rshift(imm, 31-l) end
798 imm = imm * imm13_rep[len]
799 local ix = fmt_hex32(imm)
800 if rshift(op, 31) ~= 0 then
801 return ix..tohex(imm)
802 else
803 return ix
804 end
805 else
806 local lo, hi = -1, 0
807 if imms < 32 then lo = rshift(-1, 31-imms) else hi = rshift(-1, 63-imms) end
808 if immr ~= 0 then
809 lo, hi = ror(lo, immr), ror(hi, immr)
810 local x = immr == 32 and 0 or band(bxor(lo, hi), lshift(-1, 32-immr))
811 lo, hi = bxor(lo, x), bxor(hi, x)
812 if immr >= 32 then lo, hi = hi, lo end
813 end
814 if hi ~= 0 then
815 return fmt_hex32(hi)..tohex(lo)
816 else
817 return fmt_hex32(lo)
818 end
819 end
820end
821
822local function parse_immpc(op, name)
823 if name == "b" or name == "bl" then
824 return arshift(lshift(op, 6), 4)
825 elseif name == "adr" or name == "adrp" then
826 local immlo = band(rshift(op, 29), 3)
827 local immhi = lshift(arshift(lshift(op, 8), 13), 2)
828 return bor(immhi, immlo)
829 elseif name == "tbz" or name == "tbnz" then
830 return lshift(arshift(lshift(op, 13), 18), 2)
831 else
832 return lshift(arshift(lshift(op, 8), 13), 2)
833 end
834end
835
836local function parse_fpimm8(op)
837 local sign = band(op, 0x100000) == 0 and 1 or -1
838 local exp = bxor(rshift(arshift(lshift(op, 12), 5), 24), 0x80) - 131
839 local frac = 16+band(rshift(op, 13), 15)
840 return sign * frac * 2^exp
841end
842
843local function prefer_bfx(sf, uns, imms, immr)
844 if imms < immr or imms == 31 or imms == 63 then
845 return false
846 end
847 if immr == 0 then
848 if sf == 0 and (imms == 7 or imms == 15) then
849 return false
850 end
851 if sf ~= 0 and uns == 0 and (imms == 7 or imms == 15 or imms == 31) then
852 return false
853 end
854 end
855 return true
856end
857
858-- Disassemble a single instruction.
859local function disass_ins(ctx)
860 local pos = ctx.pos
861 local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
862 local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
863 local operands = {}
864 local suffix = ""
865 local last, name, pat
866 local map_reg
867 ctx.op = op
868 ctx.rel = nil
869 last = nil
870 local opat
871 opat = map_init[band(rshift(op, 25), 15)]
872 while type(opat) ~= "string" do
873 if not opat then return unknown(ctx) end
874 opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
875 end
876 name, pat = match(opat, "^([a-z0-9]*)(.*)")
877 local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)")
878 if altname then pat = pat2 end
879 if sub(pat, 1, 1) == "." then
880 local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)")
881 suffix = suffix..s2
882 pat = p2
883 end
884
885 local rt = match(pat, "[gf]")
886 if rt then
887 if rt == "g" then
888 map_reg = band(op, 0x80000000) ~= 0 and map_regs.x or map_regs.w
889 else
890 map_reg = band(op, 0x400000) ~= 0 and map_regs.d or map_regs.s
891 end
892 end
893
894 local second0, immr
895
896 for p in gmatch(pat, ".") do
897 local x = nil
898 if p == "D" then
899 local regnum = band(op, 31)
900 x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
901 elseif p == "N" then
902 local regnum = band(rshift(op, 5), 31)
903 x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
904 elseif p == "M" then
905 local regnum = band(rshift(op, 16), 31)
906 x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
907 elseif p == "A" then
908 local regnum = band(rshift(op, 10), 31)
909 x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
910 elseif p == "B" then
911 local addr = ctx.addr + pos + parse_immpc(op, name)
912 ctx.rel = addr
913 x = "0x"..tohex(addr)
914 elseif p == "T" then
915 x = bor(band(rshift(op, 26), 32), band(rshift(op, 19), 31))
916 elseif p == "V" then
917 x = band(op, 15)
918 elseif p == "C" then
919 x = map_cond[band(rshift(op, 12), 15)]
920 elseif p == "c" then
921 local rn = band(rshift(op, 5), 31)
922 local rm = band(rshift(op, 16), 31)
923 local cond = band(rshift(op, 12), 15)
924 local invc = bxor(cond, 1)
925 x = map_cond[cond]
926 if altname and cond ~= 14 and cond ~= 15 then
927 local a1, a2 = match(altname, "([^|]*)|(.*)")
928 if rn == rm then
929 local n = #operands
930 operands[n] = nil
931 x = map_cond[invc]
932 if rn ~= 31 then
933 if a1 then name = a1 else name = altname end
934 else
935 operands[n-1] = nil
936 name = a2
937 end
938 end
939 end
940 elseif p == "W" then
941 x = band(rshift(op, 5), 0xffff)
942 elseif p == "Y" then
943 x = band(rshift(op, 5), 0xffff)
944 local hw = band(rshift(op, 21), 3)
945 if altname and (hw == 0 or x ~= 0) then
946 name = altname
947 end
948 elseif p == "L" then
949 local rn = map_regs.x[band(rshift(op, 5), 31)]
950 local imm9 = arshift(lshift(op, 11), 23)
951 if band(op, 0x800) ~= 0 then
952 x = "["..rn..", #"..imm9.."]!"
953 else
954 x = "["..rn.."], #"..imm9
955 end
956 elseif p == "U" then
957 local rn = map_regs.x[band(rshift(op, 5), 31)]
958 local sz = band(rshift(op, 30), 3)
959 local imm12 = lshift(arshift(lshift(op, 10), 20), sz)
960 if imm12 ~= 0 then
961 x = "["..rn..", #"..imm12.."]"
962 else
963 x = "["..rn.."]"
964 end
965 elseif p == "K" then
966 local rn = map_regs.x[band(rshift(op, 5), 31)]
967 local imm9 = arshift(lshift(op, 11), 23)
968 if imm9 ~= 0 then
969 x = "["..rn..", #"..imm9.."]"
970 else
971 x = "["..rn.."]"
972 end
973 elseif p == "O" then
974 local rn, rm = map_regs.x[band(rshift(op, 5), 31)]
975 local m = band(rshift(op, 13), 1)
976 if m == 0 then
977 rm = map_regs.w[band(rshift(op, 16), 31)]
978 else
979 rm = map_regs.x[band(rshift(op, 16), 31)]
980 end
981 x = "["..rn..", "..rm
982 local opt = band(rshift(op, 13), 7)
983 local s = band(rshift(op, 12), 1)
984 local sz = band(rshift(op, 30), 3)
985 -- extension to be applied
986 if opt == 3 then
987 if s == 0 then x = x.."]"
988 else x = x..", lsl #"..sz.."]" end
989 elseif opt == 2 or opt == 6 or opt == 7 then
990 if s == 0 then x = x..", "..map_extend[opt].."]"
991 else x = x..", "..map_extend[opt].." #"..sz.."]" end
992 else
993 x = x.."]"
994 end
995 elseif p == "P" then
996 local opcv, sh = rshift(op, 26), 2
997 if opcv >= 0x2a then sh = 4 elseif opcv >= 0x1b then sh = 3 end
998 local imm7 = lshift(arshift(lshift(op, 10), 25), sh)
999 local rn = map_regs.x[band(rshift(op, 5), 31)]
1000 local ind = band(rshift(op, 23), 3)
1001 if ind == 1 then
1002 x = "["..rn.."], #"..imm7
1003 elseif ind == 2 then
1004 if imm7 == 0 then
1005 x = "["..rn.."]"
1006 else
1007 x = "["..rn..", #"..imm7.."]"
1008 end
1009 elseif ind == 3 then
1010 x = "["..rn..", #"..imm7.."]!"
1011 end
1012 elseif p == "I" then
1013 local shf = band(rshift(op, 22), 3)
1014 local imm12 = band(rshift(op, 10), 0x0fff)
1015 local rn, rd = band(rshift(op, 5), 31), band(op, 31)
1016 if altname == "mov" and shf == 0 and imm12 == 0 and (rn == 31 or rd == 31) then
1017 name = altname
1018 x = nil
1019 elseif shf == 0 then
1020 x = imm12
1021 elseif shf == 1 then
1022 x = imm12..", lsl #12"
1023 end
1024 elseif p == "i" then
1025 x = "#0x"..decode_imm13(op)
1026 elseif p == "1" then
1027 immr = band(rshift(op, 16), 63)
1028 x = immr
1029 elseif p == "2" then
1030 x = band(rshift(op, 10), 63)
1031 if altname then
1032 local a1, a2, a3, a4, a5, a6 =
1033 match(altname, "([^|]*)|([^|]*)|([^|]*)|([^|]*)|([^|]*)|(.*)")
1034 local sf = band(rshift(op, 26), 32)
1035 local uns = band(rshift(op, 30), 1)
1036 if prefer_bfx(sf, uns, x, immr) then
1037 name = a2
1038 x = x - immr + 1
1039 elseif immr == 0 and x == 7 then
1040 local n = #operands
1041 operands[n] = nil
1042 if sf ~= 0 then
1043 operands[n-1] = gsub(operands[n-1], "x", "w")
1044 end
1045 last = operands[n-1]
1046 name = a6
1047 x = nil
1048 elseif immr == 0 and x == 15 then
1049 local n = #operands
1050 operands[n] = nil
1051 if sf ~= 0 then
1052 operands[n-1] = gsub(operands[n-1], "x", "w")
1053 end
1054 last = operands[n-1]
1055 name = a5
1056 x = nil
1057 elseif x == 31 or x == 63 then
1058 if x == 31 and immr == 0 and name == "sbfm" then
1059 name = a4
1060 local n = #operands
1061 operands[n] = nil
1062 if sf ~= 0 then
1063 operands[n-1] = gsub(operands[n-1], "x", "w")
1064 end
1065 last = operands[n-1]
1066 else
1067 name = a3
1068 end
1069 x = nil
1070 elseif band(x, 31) ~= 31 and immr == x+1 and name == "ubfm" then
1071 name = a4
1072 last = "#"..(sf+32 - immr)
1073 operands[#operands] = last
1074 x = nil
1075 elseif x < immr then
1076 name = a1
1077 last = "#"..(sf+32 - immr)
1078 operands[#operands] = last
1079 x = x + 1
1080 end
1081 end
1082 elseif p == "3" then
1083 x = band(rshift(op, 10), 63)
1084 if altname then
1085 local a1, a2 = match(altname, "([^|]*)|(.*)")
1086 if x < immr then
1087 name = a1
1088 local sf = band(rshift(op, 26), 32)
1089 last = "#"..(sf+32 - immr)
1090 operands[#operands] = last
1091 x = x + 1
1092 elseif x >= immr then
1093 name = a2
1094 x = x - immr + 1
1095 end
1096 end
1097 elseif p == "4" then
1098 x = band(rshift(op, 10), 63)
1099 local rn = band(rshift(op, 5), 31)
1100 local rm = band(rshift(op, 16), 31)
1101 if altname and rn == rm then
1102 local n = #operands
1103 operands[n] = nil
1104 last = operands[n-1]
1105 name = altname
1106 end
1107 elseif p == "5" then
1108 x = band(rshift(op, 16), 31)
1109 elseif p == "S" then
1110 x = band(rshift(op, 10), 63)
1111 if x == 0 then x = nil
1112 else x = map_shift[band(rshift(op, 22), 3)].." #"..x end
1113 elseif p == "X" then
1114 local opt = band(rshift(op, 13), 7)
1115 -- Width specifier <R>.
1116 if opt ~= 3 and opt ~= 7 then
1117 last = map_regs.w[band(rshift(op, 16), 31)]
1118 operands[#operands] = last
1119 end
1120 x = band(rshift(op, 10), 7)
1121 -- Extension.
1122 if opt == 2 + band(rshift(op, 31), 1) and
1123 band(rshift(op, second0 and 5 or 0), 31) == 31 then
1124 if x == 0 then x = nil
1125 else x = "lsl #"..x end
1126 else
1127 if x == 0 then x = map_extend[band(rshift(op, 13), 7)]
1128 else x = map_extend[band(rshift(op, 13), 7)].." #"..x end
1129 end
1130 elseif p == "R" then
1131 x = band(rshift(op,21), 3)
1132 if x == 0 then x = nil
1133 else x = "lsl #"..x*16 end
1134 elseif p == "z" then
1135 local n = #operands
1136 if operands[n] == "sp" then operands[n] = "xzr"
1137 elseif operands[n] == "wsp" then operands[n] = "wzr"
1138 end
1139 elseif p == "Z" then
1140 x = 0
1141 elseif p == "F" then
1142 x = parse_fpimm8(op)
1143 elseif p == "g" or p == "f" or p == "x" or p == "w" or
1144 p == "d" or p == "s" then
1145 -- These are handled in D/N/M/A.
1146 elseif p == "0" then
1147 if last == "sp" or last == "wsp" then
1148 local n = #operands
1149 operands[n] = nil
1150 last = operands[n-1]
1151 if altname then
1152 local a1, a2 = match(altname, "([^|]*)|(.*)")
1153 if not a1 then
1154 name = altname
1155 elseif second0 then
1156 name, altname = a2, a1
1157 else
1158 name, altname = a1, a2
1159 end
1160 end
1161 end
1162 second0 = true
1163 else
1164 assert(false)
1165 end
1166 if x then
1167 last = x
1168 if type(x) == "number" then x = "#"..x end
1169 operands[#operands+1] = x
1170 end
1171 end
1172
1173 return putop(ctx, name..suffix, operands)
1174end
1175
1176------------------------------------------------------------------------------
1177
1178-- Disassemble a block of code.
1179local function disass_block(ctx, ofs, len)
1180 if not ofs then ofs = 0 end
1181 local stop = len and ofs+len or #ctx.code
1182 ctx.pos = ofs
1183 ctx.rel = nil
1184 while ctx.pos < stop do disass_ins(ctx) end
1185end
1186
1187-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
1188local function create(code, addr, out)
1189 local ctx = {}
1190 ctx.code = code
1191 ctx.addr = addr or 0
1192 ctx.out = out or io.write
1193 ctx.symtab = {}
1194 ctx.disass = disass_block
1195 ctx.hexdump = 8
1196 return ctx
1197end
1198
1199-- Simple API: disassemble code (a string) at address and output via out.
1200local function disass(code, addr, out)
1201 create(code, addr, out):disass()
1202end
1203
1204-- Return register name for RID.
1205local function regname(r)
1206 if r < 32 then return map_regs.x[r] end
1207 return map_regs.d[r-32]
1208end
1209
1210-- Public module functions.
1211return {
1212 create = create,
1213 disass = disass,
1214 regname = regname
1215}
1216
diff --git a/src/jit/dis_arm64be.lua b/src/jit/dis_arm64be.lua
new file mode 100644
index 00000000..edcbffa8
--- /dev/null
+++ b/src/jit/dis_arm64be.lua
@@ -0,0 +1,12 @@
1----------------------------------------------------------------------------
2-- LuaJIT ARM64BE disassembler wrapper module.
3--
4-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
5-- Released under the MIT license. See Copyright Notice in luajit.h
6----------------------------------------------------------------------------
7-- ARM64 instructions are always little-endian. So just forward to the
8-- common ARM64 disassembler module. All the interesting stuff is there.
9------------------------------------------------------------------------------
10
11return require((string.match(..., ".*%.") or "").."dis_arm64")
12
diff --git a/src/jit/dis_mips.lua b/src/jit/dis_mips.lua
index 8f5734ed..6ad17f54 100644
--- a/src/jit/dis_mips.lua
+++ b/src/jit/dis_mips.lua
@@ -19,13 +19,34 @@ local band, bor, tohex = bit.band, bit.bor, bit.tohex
19local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift 19local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
20 20
21------------------------------------------------------------------------------ 21------------------------------------------------------------------------------
22-- Primary and extended opcode maps 22-- Extended opcode maps common to all MIPS releases
23------------------------------------------------------------------------------ 23------------------------------------------------------------------------------
24 24
25local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", }
26local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", } 25local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", }
27local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", } 26local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", }
28 27
28local map_cop0 = {
29 shift = 25, mask = 1,
30 [0] = {
31 shift = 21, mask = 15,
32 [0] = "mfc0TDW", [4] = "mtc0TDW",
33 [10] = "rdpgprDT",
34 [11] = { shift = 5, mask = 1, [0] = "diT0", "eiT0", },
35 [14] = "wrpgprDT",
36 }, {
37 shift = 0, mask = 63,
38 [1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp",
39 [24] = "eret", [31] = "deret",
40 [32] = "wait",
41 },
42}
43
44------------------------------------------------------------------------------
45-- Primary and extended opcode maps for MIPS R1-R5
46------------------------------------------------------------------------------
47
48local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", }
49
29local map_special = { 50local map_special = {
30 shift = 0, mask = 63, 51 shift = 0, mask = 63,
31 [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" }, 52 [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
@@ -34,15 +55,17 @@ local map_special = {
34 "jrS", "jalrD1S", "movzDST", "movnDST", 55 "jrS", "jalrD1S", "movzDST", "movnDST",
35 "syscallY", "breakY", false, "sync", 56 "syscallY", "breakY", false, "sync",
36 "mfhiD", "mthiS", "mfloD", "mtloS", 57 "mfhiD", "mthiS", "mfloD", "mtloS",
37 false, false, false, false, 58 "dsllvDST", false, "dsrlvDST", "dsravDST",
38 "multST", "multuST", "divST", "divuST", 59 "multST", "multuST", "divST", "divuST",
39 false, false, false, false, 60 "dmultST", "dmultuST", "ddivST", "ddivuST",
40 "addDST", "addu|moveDST0", "subDST", "subu|neguDS0T", 61 "addDST", "addu|moveDST0", "subDST", "subu|neguDS0T",
41 "andDST", "orDST", "xorDST", "nor|notDST0", 62 "andDST", "or|moveDST0", "xorDST", "nor|notDST0",
42 false, false, "sltDST", "sltuDST", 63 false, false, "sltDST", "sltuDST",
43 false, false, false, false, 64 "daddDST", "dadduDST", "dsubDST", "dsubuDST",
44 "tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ", 65 "tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ",
45 "teqSTZ", false, "tneSTZ", 66 "teqSTZ", false, "tneSTZ", false,
67 "dsllDTA", false, "dsrlDTA", "dsraDTA",
68 "dsll32DTA", false, "dsrl32DTA", "dsra32DTA",
46} 69}
47 70
48local map_special2 = { 71local map_special2 = {
@@ -60,11 +83,17 @@ local map_bshfl = {
60 [24] = "sehDT", 83 [24] = "sehDT",
61} 84}
62 85
86local map_dbshfl = {
87 shift = 6, mask = 31,
88 [2] = "dsbhDT",
89 [5] = "dshdDT",
90}
91
63local map_special3 = { 92local map_special3 = {
64 shift = 0, mask = 63, 93 shift = 0, mask = 63,
65 [0] = "extTSAK", [4] = "insTSAL", 94 [0] = "extTSAK", [1] = "dextmTSAP", [3] = "dextTSAK",
66 [32] = map_bshfl, 95 [4] = "insTSAL", [6] = "dinsuTSEQ", [7] = "dinsTSAL",
67 [59] = "rdhwrTD", 96 [32] = map_bshfl, [36] = map_dbshfl, [59] = "rdhwrTD",
68} 97}
69 98
70local map_regimm = { 99local map_regimm = {
@@ -79,22 +108,6 @@ local map_regimm = {
79 false, false, false, "synciSO", 108 false, false, false, "synciSO",
80} 109}
81 110
82local map_cop0 = {
83 shift = 25, mask = 1,
84 [0] = {
85 shift = 21, mask = 15,
86 [0] = "mfc0TDW", [4] = "mtc0TDW",
87 [10] = "rdpgprDT",
88 [11] = { shift = 5, mask = 1, [0] = "diT0", "eiT0", },
89 [14] = "wrpgprDT",
90 }, {
91 shift = 0, mask = 63,
92 [1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp",
93 [24] = "eret", [31] = "deret",
94 [32] = "wait",
95 },
96}
97
98local map_cop1s = { 111local map_cop1s = {
99 shift = 0, mask = 63, 112 shift = 0, mask = 63,
100 [0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH", 113 [0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH",
@@ -178,8 +191,8 @@ local map_cop1bc = {
178 191
179local map_cop1 = { 192local map_cop1 = {
180 shift = 21, mask = 31, 193 shift = 21, mask = 31,
181 [0] = "mfc1TG", false, "cfc1TG", "mfhc1TG", 194 [0] = "mfc1TG", "dmfc1TG", "cfc1TG", "mfhc1TG",
182 "mtc1TG", false, "ctc1TG", "mthc1TG", 195 "mtc1TG", "dmtc1TG", "ctc1TG", "mthc1TG",
183 map_cop1bc, false, false, false, 196 map_cop1bc, false, false, false,
184 false, false, false, false, 197 false, false, false, false,
185 map_cop1s, map_cop1d, false, false, 198 map_cop1s, map_cop1d, false, false,
@@ -213,16 +226,218 @@ local map_pri = {
213 "andiTSU", "ori|liTS0U", "xoriTSU", "luiTU", 226 "andiTSU", "ori|liTS0U", "xoriTSU", "luiTU",
214 map_cop0, map_cop1, false, map_cop1x, 227 map_cop0, map_cop1, false, map_cop1x,
215 "beql|beqzlST0B", "bnel|bnezlST0B", "blezlSB", "bgtzlSB", 228 "beql|beqzlST0B", "bnel|bnezlST0B", "blezlSB", "bgtzlSB",
216 false, false, false, false, 229 "daddiTSI", "daddiuTSI", false, false,
217 map_special2, false, false, map_special3, 230 map_special2, "jalxJ", false, map_special3,
218 "lbTSO", "lhTSO", "lwlTSO", "lwTSO", 231 "lbTSO", "lhTSO", "lwlTSO", "lwTSO",
219 "lbuTSO", "lhuTSO", "lwrTSO", false, 232 "lbuTSO", "lhuTSO", "lwrTSO", false,
220 "sbTSO", "shTSO", "swlTSO", "swTSO", 233 "sbTSO", "shTSO", "swlTSO", "swTSO",
221 false, false, "swrTSO", "cacheNSO", 234 false, false, "swrTSO", "cacheNSO",
222 "llTSO", "lwc1HSO", "lwc2TSO", "prefNSO", 235 "llTSO", "lwc1HSO", "lwc2TSO", "prefNSO",
223 false, "ldc1HSO", "ldc2TSO", false, 236 false, "ldc1HSO", "ldc2TSO", "ldTSO",
224 "scTSO", "swc1HSO", "swc2TSO", false, 237 "scTSO", "swc1HSO", "swc2TSO", false,
225 false, "sdc1HSO", "sdc2TSO", false, 238 false, "sdc1HSO", "sdc2TSO", "sdTSO",
239}
240
241------------------------------------------------------------------------------
242-- Primary and extended opcode maps for MIPS R6
243------------------------------------------------------------------------------
244
245local map_mul_r6 = { shift = 6, mask = 3, [2] = "mulDST", [3] = "muhDST" }
246local map_mulu_r6 = { shift = 6, mask = 3, [2] = "muluDST", [3] = "muhuDST" }
247local map_div_r6 = { shift = 6, mask = 3, [2] = "divDST", [3] = "modDST" }
248local map_divu_r6 = { shift = 6, mask = 3, [2] = "divuDST", [3] = "moduDST" }
249local map_dmul_r6 = { shift = 6, mask = 3, [2] = "dmulDST", [3] = "dmuhDST" }
250local map_dmulu_r6 = { shift = 6, mask = 3, [2] = "dmuluDST", [3] = "dmuhuDST" }
251local map_ddiv_r6 = { shift = 6, mask = 3, [2] = "ddivDST", [3] = "dmodDST" }
252local map_ddivu_r6 = { shift = 6, mask = 3, [2] = "ddivuDST", [3] = "dmoduDST" }
253
254local map_special_r6 = {
255 shift = 0, mask = 63,
256 [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
257 false, map_srl, "sraDTA",
258 "sllvDTS", false, map_srlv, "sravDTS",
259 "jrS", "jalrD1S", false, false,
260 "syscallY", "breakY", false, "sync",
261 "clzDS", "cloDS", "dclzDS", "dcloDS",
262 "dsllvDST", "dlsaDSTA", "dsrlvDST", "dsravDST",
263 map_mul_r6, map_mulu_r6, map_div_r6, map_divu_r6,
264 map_dmul_r6, map_dmulu_r6, map_ddiv_r6, map_ddivu_r6,
265 "addDST", "addu|moveDST0", "subDST", "subu|neguDS0T",
266 "andDST", "or|moveDST0", "xorDST", "nor|notDST0",
267 false, false, "sltDST", "sltuDST",
268 "daddDST", "dadduDST", "dsubDST", "dsubuDST",
269 "tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ",
270 "teqSTZ", "seleqzDST", "tneSTZ", "selnezDST",
271 "dsllDTA", false, "dsrlDTA", "dsraDTA",
272 "dsll32DTA", false, "dsrl32DTA", "dsra32DTA",
273}
274
275local map_bshfl_r6 = {
276 shift = 9, mask = 3,
277 [1] = "alignDSTa",
278 _ = {
279 shift = 6, mask = 31,
280 [0] = "bitswapDT",
281 [2] = "wsbhDT",
282 [16] = "sebDT",
283 [24] = "sehDT",
284 }
285}
286
287local map_dbshfl_r6 = {
288 shift = 9, mask = 3,
289 [1] = "dalignDSTa",
290 _ = {
291 shift = 6, mask = 31,
292 [0] = "dbitswapDT",
293 [2] = "dsbhDT",
294 [5] = "dshdDT",
295 }
296}
297
298local map_special3_r6 = {
299 shift = 0, mask = 63,
300 [0] = "extTSAK", [1] = "dextmTSAP", [3] = "dextTSAK",
301 [4] = "insTSAL", [6] = "dinsuTSEQ", [7] = "dinsTSAL",
302 [32] = map_bshfl_r6, [36] = map_dbshfl_r6, [59] = "rdhwrTD",
303}
304
305local map_regimm_r6 = {
306 shift = 16, mask = 31,
307 [0] = "bltzSB", [1] = "bgezSB",
308 [6] = "dahiSI", [30] = "datiSI",
309 [23] = "sigrieI", [31] = "synciSO",
310}
311
312local map_pcrel_r6 = {
313 shift = 19, mask = 3,
314 [0] = "addiupcS2", "lwpcS2", "lwupcS2", {
315 shift = 18, mask = 1,
316 [0] = "ldpcS3", { shift = 16, mask = 3, [2] = "auipcSI", [3] = "aluipcSI" }
317 }
318}
319
320local map_cop1s_r6 = {
321 shift = 0, mask = 63,
322 [0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH",
323 "sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG",
324 "round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG",
325 "round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG",
326 "sel.sFGH", false, false, false,
327 "seleqz.sFGH", "recip.sFG", "rsqrt.sFG", "selnez.sFGH",
328 "maddf.sFGH", "msubf.sFGH", "rint.sFG", "class.sFG",
329 "min.sFGH", "mina.sFGH", "max.sFGH", "maxa.sFGH",
330 false, "cvt.d.sFG", false, false,
331 "cvt.w.sFG", "cvt.l.sFG",
332}
333
334local map_cop1d_r6 = {
335 shift = 0, mask = 63,
336 [0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH",
337 "sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG",
338 "round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG",
339 "round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG",
340 "sel.dFGH", false, false, false,
341 "seleqz.dFGH", "recip.dFG", "rsqrt.dFG", "selnez.dFGH",
342 "maddf.dFGH", "msubf.dFGH", "rint.dFG", "class.dFG",
343 "min.dFGH", "mina.dFGH", "max.dFGH", "maxa.dFGH",
344 "cvt.s.dFG", false, false, false,
345 "cvt.w.dFG", "cvt.l.dFG",
346}
347
348local map_cop1w_r6 = {
349 shift = 0, mask = 63,
350 [0] = "cmp.af.sFGH", "cmp.un.sFGH", "cmp.eq.sFGH", "cmp.ueq.sFGH",
351 "cmp.lt.sFGH", "cmp.ult.sFGH", "cmp.le.sFGH", "cmp.ule.sFGH",
352 "cmp.saf.sFGH", "cmp.sun.sFGH", "cmp.seq.sFGH", "cmp.sueq.sFGH",
353 "cmp.slt.sFGH", "cmp.sult.sFGH", "cmp.sle.sFGH", "cmp.sule.sFGH",
354 false, "cmp.or.sFGH", "cmp.une.sFGH", "cmp.ne.sFGH",
355 false, false, false, false,
356 false, "cmp.sor.sFGH", "cmp.sune.sFGH", "cmp.sne.sFGH",
357 false, false, false, false,
358 "cvt.s.wFG", "cvt.d.wFG",
359}
360
361local map_cop1l_r6 = {
362 shift = 0, mask = 63,
363 [0] = "cmp.af.dFGH", "cmp.un.dFGH", "cmp.eq.dFGH", "cmp.ueq.dFGH",
364 "cmp.lt.dFGH", "cmp.ult.dFGH", "cmp.le.dFGH", "cmp.ule.dFGH",
365 "cmp.saf.dFGH", "cmp.sun.dFGH", "cmp.seq.dFGH", "cmp.sueq.dFGH",
366 "cmp.slt.dFGH", "cmp.sult.dFGH", "cmp.sle.dFGH", "cmp.sule.dFGH",
367 false, "cmp.or.dFGH", "cmp.une.dFGH", "cmp.ne.dFGH",
368 false, false, false, false,
369 false, "cmp.sor.dFGH", "cmp.sune.dFGH", "cmp.sne.dFGH",
370 false, false, false, false,
371 "cvt.s.lFG", "cvt.d.lFG",
372}
373
374local map_cop1_r6 = {
375 shift = 21, mask = 31,
376 [0] = "mfc1TG", "dmfc1TG", "cfc1TG", "mfhc1TG",
377 "mtc1TG", "dmtc1TG", "ctc1TG", "mthc1TG",
378 false, "bc1eqzHB", false, false,
379 false, "bc1nezHB", false, false,
380 map_cop1s_r6, map_cop1d_r6, false, false,
381 map_cop1w_r6, map_cop1l_r6,
382}
383
384local function maprs_popTS(rs, rt)
385 if rt == 0 then return 0 elseif rs == 0 then return 1
386 elseif rs == rt then return 2 else return 3 end
387end
388
389local map_pop06_r6 = {
390 maprs = maprs_popTS, [0] = "blezSB", "blezalcTB", "bgezalcTB", "bgeucSTB"
391}
392local map_pop07_r6 = {
393 maprs = maprs_popTS, [0] = "bgtzSB", "bgtzalcTB", "bltzalcTB", "bltucSTB"
394}
395local map_pop26_r6 = {
396 maprs = maprs_popTS, "blezcTB", "bgezcTB", "bgecSTB"
397}
398local map_pop27_r6 = {
399 maprs = maprs_popTS, "bgtzcTB", "bltzcTB", "bltcSTB"
400}
401
402local function maprs_popS(rs, rt)
403 if rs == 0 then return 0 else return 1 end
404end
405
406local map_pop66_r6 = {
407 maprs = maprs_popS, [0] = "jicTI", "beqzcSb"
408}
409local map_pop76_r6 = {
410 maprs = maprs_popS, [0] = "jialcTI", "bnezcSb"
411}
412
413local function maprs_popST(rs, rt)
414 if rs >= rt then return 0 elseif rs == 0 then return 1 else return 2 end
415end
416
417local map_pop10_r6 = {
418 maprs = maprs_popST, [0] = "bovcSTB", "beqzalcTB", "beqcSTB"
419}
420local map_pop30_r6 = {
421 maprs = maprs_popST, [0] = "bnvcSTB", "bnezalcTB", "bnecSTB"
422}
423
424local map_pri_r6 = {
425 [0] = map_special_r6, map_regimm_r6, "jJ", "jalJ",
426 "beq|beqz|bST00B", "bne|bnezST0B", map_pop06_r6, map_pop07_r6,
427 map_pop10_r6, "addiu|liTS0I", "sltiTSI", "sltiuTSI",
428 "andiTSU", "ori|liTS0U", "xoriTSU", "aui|luiTS0U",
429 map_cop0, map_cop1_r6, false, false,
430 false, false, map_pop26_r6, map_pop27_r6,
431 map_pop30_r6, "daddiuTSI", false, false,
432 false, "dauiTSI", false, map_special3_r6,
433 "lbTSO", "lhTSO", false, "lwTSO",
434 "lbuTSO", "lhuTSO", false, false,
435 "sbTSO", "shTSO", false, "swTSO",
436 false, false, false, false,
437 false, "lwc1HSO", "bc#", false,
438 false, "ldc1HSO", map_pop66_r6, "ldTSO",
439 false, "swc1HSO", "balc#", map_pcrel_r6,
440 false, "sdc1HSO", map_pop76_r6, "sdTSO",
226} 441}
227 442
228------------------------------------------------------------------------------ 443------------------------------------------------------------------------------
@@ -279,10 +494,14 @@ local function disass_ins(ctx)
279 ctx.op = op 494 ctx.op = op
280 ctx.rel = nil 495 ctx.rel = nil
281 496
282 local opat = map_pri[rshift(op, 26)] 497 local opat = ctx.map_pri[rshift(op, 26)]
283 while type(opat) ~= "string" do 498 while type(opat) ~= "string" do
284 if not opat then return unknown(ctx) end 499 if not opat then return unknown(ctx) end
285 opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._ 500 if opat.maprs then
501 opat = opat[opat.maprs(band(rshift(op,21),31), band(rshift(op,16),31))]
502 else
503 opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
504 end
286 end 505 end
287 local name, pat = match(opat, "^([a-z0-9_.]*)(.*)") 506 local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
288 local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)") 507 local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)")
@@ -306,6 +525,10 @@ local function disass_ins(ctx)
306 x = "f"..band(rshift(op, 21), 31) 525 x = "f"..band(rshift(op, 21), 31)
307 elseif p == "A" then 526 elseif p == "A" then
308 x = band(rshift(op, 6), 31) 527 x = band(rshift(op, 6), 31)
528 elseif p == "a" then
529 x = band(rshift(op, 6), 7)
530 elseif p == "E" then
531 x = band(rshift(op, 6), 31) + 32
309 elseif p == "M" then 532 elseif p == "M" then
310 x = band(rshift(op, 11), 31) 533 x = band(rshift(op, 11), 31)
311 elseif p == "N" then 534 elseif p == "N" then
@@ -315,10 +538,18 @@ local function disass_ins(ctx)
315 if x == 0 then x = nil end 538 if x == 0 then x = nil end
316 elseif p == "K" then 539 elseif p == "K" then
317 x = band(rshift(op, 11), 31) + 1 540 x = band(rshift(op, 11), 31) + 1
541 elseif p == "P" then
542 x = band(rshift(op, 11), 31) + 33
318 elseif p == "L" then 543 elseif p == "L" then
319 x = band(rshift(op, 11), 31) - last + 1 544 x = band(rshift(op, 11), 31) - last + 1
545 elseif p == "Q" then
546 x = band(rshift(op, 11), 31) - last + 33
320 elseif p == "I" then 547 elseif p == "I" then
321 x = arshift(lshift(op, 16), 16) 548 x = arshift(lshift(op, 16), 16)
549 elseif p == "2" then
550 x = arshift(lshift(op, 13), 11)
551 elseif p == "3" then
552 x = arshift(lshift(op, 14), 11)
322 elseif p == "U" then 553 elseif p == "U" then
323 x = band(op, 0xffff) 554 x = band(op, 0xffff)
324 elseif p == "O" then 555 elseif p == "O" then
@@ -328,13 +559,22 @@ local function disass_ins(ctx)
328 local index = map_gpr[band(rshift(op, 16), 31)] 559 local index = map_gpr[band(rshift(op, 16), 31)]
329 operands[#operands] = format("%s(%s)", index, last) 560 operands[#operands] = format("%s(%s)", index, last)
330 elseif p == "B" then 561 elseif p == "B" then
331 x = ctx.addr + ctx.pos + arshift(lshift(op, 16), 16)*4 + 4 562 x = ctx.addr + ctx.pos + arshift(lshift(op, 16), 14) + 4
563 ctx.rel = x
564 x = format("0x%08x", x)
565 elseif p == "b" then
566 x = ctx.addr + ctx.pos + arshift(lshift(op, 11), 9) + 4
332 ctx.rel = x 567 ctx.rel = x
333 x = "0x"..tohex(x) 568 x = format("0x%08x", x)
569 elseif p == "#" then
570 x = ctx.addr + ctx.pos + arshift(lshift(op, 6), 4) + 4
571 ctx.rel = x
572 x = format("0x%08x", x)
334 elseif p == "J" then 573 elseif p == "J" then
335 x = band(ctx.addr + ctx.pos, 0xf0000000) + band(op, 0x03ffffff)*4 574 local a = ctx.addr + ctx.pos
575 x = a - band(a, 0x0fffffff) + band(op, 0x03ffffff)*4
336 ctx.rel = x 576 ctx.rel = x
337 x = "0x"..tohex(x) 577 x = format("0x%08x", x)
338 elseif p == "V" then 578 elseif p == "V" then
339 x = band(rshift(op, 8), 7) 579 x = band(rshift(op, 8), 7)
340 if x == 0 then x = nil end 580 if x == 0 then x = nil end
@@ -384,7 +624,7 @@ local function disass_block(ctx, ofs, len)
384end 624end
385 625
386-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). 626-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
387local function create_(code, addr, out) 627local function create(code, addr, out)
388 local ctx = {} 628 local ctx = {}
389 ctx.code = code 629 ctx.code = code
390 ctx.addr = addr or 0 630 ctx.addr = addr or 0
@@ -393,36 +633,62 @@ local function create_(code, addr, out)
393 ctx.disass = disass_block 633 ctx.disass = disass_block
394 ctx.hexdump = 8 634 ctx.hexdump = 8
395 ctx.get = get_be 635 ctx.get = get_be
636 ctx.map_pri = map_pri
637 return ctx
638end
639
640local function create_el(code, addr, out)
641 local ctx = create(code, addr, out)
642 ctx.get = get_le
643 return ctx
644end
645
646local function create_r6(code, addr, out)
647 local ctx = create(code, addr, out)
648 ctx.map_pri = map_pri_r6
396 return ctx 649 return ctx
397end 650end
398 651
399local function create_el_(code, addr, out) 652local function create_r6_el(code, addr, out)
400 local ctx = create_(code, addr, out) 653 local ctx = create(code, addr, out)
401 ctx.get = get_le 654 ctx.get = get_le
655 ctx.map_pri = map_pri_r6
402 return ctx 656 return ctx
403end 657end
404 658
405-- Simple API: disassemble code (a string) at address and output via out. 659-- Simple API: disassemble code (a string) at address and output via out.
406local function disass_(code, addr, out) 660local function disass(code, addr, out)
407 create_(code, addr, out):disass() 661 create(code, addr, out):disass()
662end
663
664local function disass_el(code, addr, out)
665 create_el(code, addr, out):disass()
408end 666end
409 667
410local function disass_el_(code, addr, out) 668local function disass_r6(code, addr, out)
411 create_el_(code, addr, out):disass() 669 create_r6(code, addr, out):disass()
670end
671
672local function disass_r6_el(code, addr, out)
673 create_r6_el(code, addr, out):disass()
412end 674end
413 675
414-- Return register name for RID. 676-- Return register name for RID.
415local function regname_(r) 677local function regname(r)
416 if r < 32 then return map_gpr[r] end 678 if r < 32 then return map_gpr[r] end
417 return "f"..(r-32) 679 return "f"..(r-32)
418end 680end
419 681
420-- Public module functions. 682-- Public module functions.
421module(...) 683return {
422 684 create = create,
423create = create_ 685 create_el = create_el,
424create_el = create_el_ 686 create_r6 = create_r6,
425disass = disass_ 687 create_r6_el = create_r6_el,
426disass_el = disass_el_ 688 disass = disass,
427regname = regname_ 689 disass_el = disass_el,
690 disass_r6 = disass_r6,
691 disass_r6_el = disass_r6_el,
692 regname = regname
693}
428 694
diff --git a/src/jit/dis_mips64.lua b/src/jit/dis_mips64.lua
new file mode 100644
index 00000000..5ad48f8f
--- /dev/null
+++ b/src/jit/dis_mips64.lua
@@ -0,0 +1,17 @@
1----------------------------------------------------------------------------
2-- LuaJIT MIPS64 disassembler wrapper module.
3--
4-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
5-- Released under the MIT license. See Copyright Notice in luajit.h
6----------------------------------------------------------------------------
7-- This module just exports the big-endian functions from the
8-- MIPS disassembler module. All the interesting stuff is there.
9------------------------------------------------------------------------------
10
11local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
12return {
13 create = dis_mips.create,
14 disass = dis_mips.disass,
15 regname = dis_mips.regname
16}
17
diff --git a/src/jit/dis_mips64el.lua b/src/jit/dis_mips64el.lua
new file mode 100644
index 00000000..d50e3a18
--- /dev/null
+++ b/src/jit/dis_mips64el.lua
@@ -0,0 +1,17 @@
1----------------------------------------------------------------------------
2-- LuaJIT MIPS64EL disassembler wrapper module.
3--
4-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
5-- Released under the MIT license. See Copyright Notice in luajit.h
6----------------------------------------------------------------------------
7-- This module just exports the little-endian functions from the
8-- MIPS disassembler module. All the interesting stuff is there.
9------------------------------------------------------------------------------
10
11local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
12return {
13 create = dis_mips.create_el,
14 disass = dis_mips.disass_el,
15 regname = dis_mips.regname
16}
17
diff --git a/src/jit/dis_mips64r6.lua b/src/jit/dis_mips64r6.lua
new file mode 100644
index 00000000..921b3cbe
--- /dev/null
+++ b/src/jit/dis_mips64r6.lua
@@ -0,0 +1,17 @@
1----------------------------------------------------------------------------
2-- LuaJIT MIPS64R6 disassembler wrapper module.
3--
4-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
5-- Released under the MIT license. See Copyright Notice in luajit.h
6----------------------------------------------------------------------------
7-- This module just exports the r6 big-endian functions from the
8-- MIPS disassembler module. All the interesting stuff is there.
9------------------------------------------------------------------------------
10
11local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
12return {
13 create = dis_mips.create_r6,
14 disass = dis_mips.disass_r6,
15 regname = dis_mips.regname
16}
17
diff --git a/src/jit/dis_mips64r6el.lua b/src/jit/dis_mips64r6el.lua
new file mode 100644
index 00000000..aadef9f3
--- /dev/null
+++ b/src/jit/dis_mips64r6el.lua
@@ -0,0 +1,17 @@
1----------------------------------------------------------------------------
2-- LuaJIT MIPS64R6EL disassembler wrapper module.
3--
4-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
5-- Released under the MIT license. See Copyright Notice in luajit.h
6----------------------------------------------------------------------------
7-- This module just exports the r6 little-endian functions from the
8-- MIPS disassembler module. All the interesting stuff is there.
9------------------------------------------------------------------------------
10
11local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
12return {
13 create = dis_mips.create_r6_el,
14 disass = dis_mips.disass_r6_el,
15 regname = dis_mips.regname
16}
17
diff --git a/src/jit/dis_mipsel.lua b/src/jit/dis_mipsel.lua
index 5f3e1402..52cebefb 100644
--- a/src/jit/dis_mipsel.lua
+++ b/src/jit/dis_mipsel.lua
@@ -8,13 +8,10 @@
8-- MIPS disassembler module. All the interesting stuff is there. 8-- MIPS disassembler module. All the interesting stuff is there.
9------------------------------------------------------------------------------ 9------------------------------------------------------------------------------
10 10
11local require = require 11local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
12 12return {
13module(...) 13 create = dis_mips.create_el,
14 14 disass = dis_mips.disass_el,
15local dis_mips = require(_PACKAGE.."dis_mips") 15 regname = dis_mips.regname
16 16}
17create = dis_mips.create_el
18disass = dis_mips.disass_el
19regname = dis_mips.regname
20 17
diff --git a/src/jit/dis_ppc.lua b/src/jit/dis_ppc.lua
index eda1c4f9..08d742f1 100644
--- a/src/jit/dis_ppc.lua
+++ b/src/jit/dis_ppc.lua
@@ -560,7 +560,7 @@ local function disass_block(ctx, ofs, len)
560end 560end
561 561
562-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). 562-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
563local function create_(code, addr, out) 563local function create(code, addr, out)
564 local ctx = {} 564 local ctx = {}
565 ctx.code = code 565 ctx.code = code
566 ctx.addr = addr or 0 566 ctx.addr = addr or 0
@@ -572,20 +572,20 @@ local function create_(code, addr, out)
572end 572end
573 573
574-- Simple API: disassemble code (a string) at address and output via out. 574-- Simple API: disassemble code (a string) at address and output via out.
575local function disass_(code, addr, out) 575local function disass(code, addr, out)
576 create_(code, addr, out):disass() 576 create(code, addr, out):disass()
577end 577end
578 578
579-- Return register name for RID. 579-- Return register name for RID.
580local function regname_(r) 580local function regname(r)
581 if r < 32 then return map_gpr[r] end 581 if r < 32 then return map_gpr[r] end
582 return "f"..(r-32) 582 return "f"..(r-32)
583end 583end
584 584
585-- Public module functions. 585-- Public module functions.
586module(...) 586return {
587 587 create = create,
588create = create_ 588 disass = disass,
589disass = disass_ 589 regname = regname
590regname = regname_ 590}
591 591
diff --git a/src/jit/dis_x64.lua b/src/jit/dis_x64.lua
index 9222c1d9..2d37423e 100644
--- a/src/jit/dis_x64.lua
+++ b/src/jit/dis_x64.lua
@@ -8,13 +8,10 @@
8-- x86/x64 disassembler module. All the interesting stuff is there. 8-- x86/x64 disassembler module. All the interesting stuff is there.
9------------------------------------------------------------------------------ 9------------------------------------------------------------------------------
10 10
11local require = require 11local dis_x86 = require((string.match(..., ".*%.") or "").."dis_x86")
12 12return {
13module(...) 13 create = dis_x86.create64,
14 14 disass = dis_x86.disass64,
15local dis_x86 = require(_PACKAGE.."dis_x86") 15 regname = dis_x86.regname64
16 16}
17create = dis_x86.create64
18disass = dis_x86.disass64
19regname = dis_x86.regname64
20 17
diff --git a/src/jit/dis_x86.lua b/src/jit/dis_x86.lua
index f804476b..5480854c 100644
--- a/src/jit/dis_x86.lua
+++ b/src/jit/dis_x86.lua
@@ -15,19 +15,20 @@
15-- Intel and AMD manuals. The supported instruction set is quite extensive 15-- Intel and AMD manuals. The supported instruction set is quite extensive
16-- and reflects what a current generation Intel or AMD CPU implements in 16-- and reflects what a current generation Intel or AMD CPU implements in
17-- 32 bit and 64 bit mode. Yes, this includes MMX, SSE, SSE2, SSE3, SSSE3, 17-- 32 bit and 64 bit mode. Yes, this includes MMX, SSE, SSE2, SSE3, SSSE3,
18-- SSE4.1, SSE4.2, SSE4a and even privileged and hypervisor (VMX/SVM) 18-- SSE4.1, SSE4.2, SSE4a, AVX, AVX2 and even privileged and hypervisor
19-- instructions. 19-- (VMX/SVM) instructions.
20-- 20--
21-- Notes: 21-- Notes:
22-- * The (useless) a16 prefix, 3DNow and pre-586 opcodes are unsupported. 22-- * The (useless) a16 prefix, 3DNow and pre-586 opcodes are unsupported.
23-- * No attempt at optimization has been made -- it's fast enough for my needs. 23-- * No attempt at optimization has been made -- it's fast enough for my needs.
24-- * The public API may change when more architectures are added.
25------------------------------------------------------------------------------ 24------------------------------------------------------------------------------
26 25
27local type = type 26local type = type
28local sub, byte, format = string.sub, string.byte, string.format 27local sub, byte, format = string.sub, string.byte, string.format
29local match, gmatch, gsub = string.match, string.gmatch, string.gsub 28local match, gmatch, gsub = string.match, string.gmatch, string.gsub
30local lower, rep = string.lower, string.rep 29local lower, rep = string.lower, string.rep
30local bit = require("bit")
31local tohex = bit.tohex
31 32
32-- Map for 1st opcode byte in 32 bit mode. Ugly? Well ... read on. 33-- Map for 1st opcode byte in 32 bit mode. Ugly? Well ... read on.
33local map_opc1_32 = { 34local map_opc1_32 = {
@@ -76,7 +77,7 @@ local map_opc1_32 = {
76"movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi", 77"movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi",
77"movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI", 78"movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI",
78--Cx 79--Cx
79"shift!Bmu","shift!Vmu","retBw","ret","$lesVrm","$ldsVrm","movBmi","movVmi", 80"shift!Bmu","shift!Vmu","retBw","ret","vex*3$lesVrm","vex*2$ldsVrm","movBmi","movVmi",
80"enterBwu","leave","retfBw","retf","int3","intBu","into","iretVS", 81"enterBwu","leave","retfBw","retf","int3","intBu","into","iretVS",
81--Dx 82--Dx
82"shift!Bm1","shift!Vm1","shift!Bmc","shift!Vmc","aamBu","aadBu","salc","xlatb", 83"shift!Bm1","shift!Vm1","shift!Bmc","shift!Vmc","aamBu","aadBu","salc","xlatb",
@@ -101,7 +102,7 @@ local map_opc1_64 = setmetatable({
101 [0x44]="rex*r", [0x45]="rex*rb", [0x46]="rex*rx", [0x47]="rex*rxb", 102 [0x44]="rex*r", [0x45]="rex*rb", [0x46]="rex*rx", [0x47]="rex*rxb",
102 [0x48]="rex*w", [0x49]="rex*wb", [0x4a]="rex*wx", [0x4b]="rex*wxb", 103 [0x48]="rex*w", [0x49]="rex*wb", [0x4a]="rex*wx", [0x4b]="rex*wxb",
103 [0x4c]="rex*wr", [0x4d]="rex*wrb", [0x4e]="rex*wrx", [0x4f]="rex*wrxb", 104 [0x4c]="rex*wr", [0x4d]="rex*wrb", [0x4e]="rex*wrx", [0x4f]="rex*wrxb",
104 [0x82]=false, [0x9a]=false, [0xc4]=false, [0xc5]=false, [0xce]=false, 105 [0x82]=false, [0x9a]=false, [0xc4]="vex*3", [0xc5]="vex*2", [0xce]=false,
105 [0xd4]=false, [0xd5]=false, [0xd6]=false, [0xea]=false, 106 [0xd4]=false, [0xd5]=false, [0xd6]=false, [0xea]=false,
106}, { __index = map_opc1_32 }) 107}, { __index = map_opc1_32 })
107 108
@@ -112,12 +113,12 @@ local map_opc2 = {
112[0]="sldt!Dmp","sgdt!Ump","larVrm","lslVrm",nil,"syscall","clts","sysret", 113[0]="sldt!Dmp","sgdt!Ump","larVrm","lslVrm",nil,"syscall","clts","sysret",
113"invd","wbinvd",nil,"ud1",nil,"$prefetch!Bm","femms","3dnowMrmu", 114"invd","wbinvd",nil,"ud1",nil,"$prefetch!Bm","femms","3dnowMrmu",
114--1x 115--1x
115"movupsXrm|movssXrm|movupdXrm|movsdXrm", 116"movupsXrm|movssXrvm|movupdXrm|movsdXrvm",
116"movupsXmr|movssXmr|movupdXmr|movsdXmr", 117"movupsXmr|movssXmvr|movupdXmr|movsdXmvr",
117"movhlpsXrm$movlpsXrm|movsldupXrm|movlpdXrm|movddupXrm", 118"movhlpsXrm$movlpsXrm|movsldupXrm|movlpdXrm|movddupXrm",
118"movlpsXmr||movlpdXmr", 119"movlpsXmr||movlpdXmr",
119"unpcklpsXrm||unpcklpdXrm", 120"unpcklpsXrvm||unpcklpdXrvm",
120"unpckhpsXrm||unpckhpdXrm", 121"unpckhpsXrvm||unpckhpdXrvm",
121"movlhpsXrm$movhpsXrm|movshdupXrm|movhpdXrm", 122"movlhpsXrm$movhpsXrm|movshdupXrm|movhpdXrm",
122"movhpsXmr||movhpdXmr", 123"movhpsXmr||movhpdXmr",
123"$prefetcht!Bm","hintnopVm","hintnopVm","hintnopVm", 124"$prefetcht!Bm","hintnopVm","hintnopVm","hintnopVm",
@@ -126,7 +127,7 @@ local map_opc2 = {
126"movUmx$","movUmy$","movUxm$","movUym$","movUmz$",nil,"movUzm$",nil, 127"movUmx$","movUmy$","movUxm$","movUym$","movUmz$",nil,"movUzm$",nil,
127"movapsXrm||movapdXrm", 128"movapsXrm||movapdXrm",
128"movapsXmr||movapdXmr", 129"movapsXmr||movapdXmr",
129"cvtpi2psXrMm|cvtsi2ssXrVmt|cvtpi2pdXrMm|cvtsi2sdXrVmt", 130"cvtpi2psXrMm|cvtsi2ssXrvVmt|cvtpi2pdXrMm|cvtsi2sdXrvVmt",
130"movntpsXmr|movntssXmr|movntpdXmr|movntsdXmr", 131"movntpsXmr|movntssXmr|movntpdXmr|movntsdXmr",
131"cvttps2piMrXm|cvttss2siVrXm|cvttpd2piMrXm|cvttsd2siVrXm", 132"cvttps2piMrXm|cvttss2siVrXm|cvttpd2piMrXm|cvttsd2siVrXm",
132"cvtps2piMrXm|cvtss2siVrXm|cvtpd2piMrXm|cvtsd2siVrXm", 133"cvtps2piMrXm|cvtss2siVrXm|cvtpd2piMrXm|cvtsd2siVrXm",
@@ -142,27 +143,27 @@ local map_opc2 = {
142"cmovlVrm","cmovgeVrm","cmovleVrm","cmovgVrm", 143"cmovlVrm","cmovgeVrm","cmovleVrm","cmovgVrm",
143--5x 144--5x
144"movmskpsVrXm$||movmskpdVrXm$","sqrtpsXrm|sqrtssXrm|sqrtpdXrm|sqrtsdXrm", 145"movmskpsVrXm$||movmskpdVrXm$","sqrtpsXrm|sqrtssXrm|sqrtpdXrm|sqrtsdXrm",
145"rsqrtpsXrm|rsqrtssXrm","rcppsXrm|rcpssXrm", 146"rsqrtpsXrm|rsqrtssXrvm","rcppsXrm|rcpssXrvm",
146"andpsXrm||andpdXrm","andnpsXrm||andnpdXrm", 147"andpsXrvm||andpdXrvm","andnpsXrvm||andnpdXrvm",
147"orpsXrm||orpdXrm","xorpsXrm||xorpdXrm", 148"orpsXrvm||orpdXrvm","xorpsXrvm||xorpdXrvm",
148"addpsXrm|addssXrm|addpdXrm|addsdXrm","mulpsXrm|mulssXrm|mulpdXrm|mulsdXrm", 149"addpsXrvm|addssXrvm|addpdXrvm|addsdXrvm","mulpsXrvm|mulssXrvm|mulpdXrvm|mulsdXrvm",
149"cvtps2pdXrm|cvtss2sdXrm|cvtpd2psXrm|cvtsd2ssXrm", 150"cvtps2pdXrm|cvtss2sdXrvm|cvtpd2psXrm|cvtsd2ssXrvm",
150"cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm", 151"cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm",
151"subpsXrm|subssXrm|subpdXrm|subsdXrm","minpsXrm|minssXrm|minpdXrm|minsdXrm", 152"subpsXrvm|subssXrvm|subpdXrvm|subsdXrvm","minpsXrvm|minssXrvm|minpdXrvm|minsdXrvm",
152"divpsXrm|divssXrm|divpdXrm|divsdXrm","maxpsXrm|maxssXrm|maxpdXrm|maxsdXrm", 153"divpsXrvm|divssXrvm|divpdXrvm|divsdXrvm","maxpsXrvm|maxssXrvm|maxpdXrvm|maxsdXrvm",
153--6x 154--6x
154"punpcklbwPrm","punpcklwdPrm","punpckldqPrm","packsswbPrm", 155"punpcklbwPrvm","punpcklwdPrvm","punpckldqPrvm","packsswbPrvm",
155"pcmpgtbPrm","pcmpgtwPrm","pcmpgtdPrm","packuswbPrm", 156"pcmpgtbPrvm","pcmpgtwPrvm","pcmpgtdPrvm","packuswbPrvm",
156"punpckhbwPrm","punpckhwdPrm","punpckhdqPrm","packssdwPrm", 157"punpckhbwPrvm","punpckhwdPrvm","punpckhdqPrvm","packssdwPrvm",
157"||punpcklqdqXrm","||punpckhqdqXrm", 158"||punpcklqdqXrvm","||punpckhqdqXrvm",
158"movPrVSm","movqMrm|movdquXrm|movdqaXrm", 159"movPrVSm","movqMrm|movdquXrm|movdqaXrm",
159--7x 160--7x
160"pshufwMrmu|pshufhwXrmu|pshufdXrmu|pshuflwXrmu","pshiftw!Pmu", 161"pshufwMrmu|pshufhwXrmu|pshufdXrmu|pshuflwXrmu","pshiftw!Pvmu",
161"pshiftd!Pmu","pshiftq!Mmu||pshiftdq!Xmu", 162"pshiftd!Pvmu","pshiftq!Mvmu||pshiftdq!Xvmu",
162"pcmpeqbPrm","pcmpeqwPrm","pcmpeqdPrm","emms|", 163"pcmpeqbPrvm","pcmpeqwPrvm","pcmpeqdPrvm","emms*|",
163"vmreadUmr||extrqXmuu$|insertqXrmuu$","vmwriteUrm||extrqXrm$|insertqXrm$", 164"vmreadUmr||extrqXmuu$|insertqXrmuu$","vmwriteUrm||extrqXrm$|insertqXrm$",
164nil,nil, 165nil,nil,
165"||haddpdXrm|haddpsXrm","||hsubpdXrm|hsubpsXrm", 166"||haddpdXrvm|haddpsXrvm","||hsubpdXrvm|hsubpsXrvm",
166"movVSmMr|movqXrm|movVSmXr","movqMmr|movdquXmr|movdqaXmr", 167"movVSmMr|movqXrm|movVSmXr","movqMmr|movdquXmr|movdqaXmr",
167--8x 168--8x
168"joVj","jnoVj","jbVj","jnbVj","jzVj","jnzVj","jbeVj","jaVj", 169"joVj","jnoVj","jbVj","jnbVj","jzVj","jnzVj","jbeVj","jaVj",
@@ -180,27 +181,27 @@ nil,nil,
180"bsfVrm","bsrVrm|lzcntVrm|bsrWrm","movsxVrBmt","movsxVrWmt", 181"bsfVrm","bsrVrm|lzcntVrm|bsrWrm","movsxVrBmt","movsxVrWmt",
181--Cx 182--Cx
182"xaddBmr","xaddVmr", 183"xaddBmr","xaddVmr",
183"cmppsXrmu|cmpssXrmu|cmppdXrmu|cmpsdXrmu","$movntiVmr|", 184"cmppsXrvmu|cmpssXrvmu|cmppdXrvmu|cmpsdXrvmu","$movntiVmr|",
184"pinsrwPrWmu","pextrwDrPmu", 185"pinsrwPrvWmu","pextrwDrPmu",
185"shufpsXrmu||shufpdXrmu","$cmpxchg!Qmp", 186"shufpsXrvmu||shufpdXrvmu","$cmpxchg!Qmp",
186"bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR", 187"bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR",
187--Dx 188--Dx
188"||addsubpdXrm|addsubpsXrm","psrlwPrm","psrldPrm","psrlqPrm", 189"||addsubpdXrvm|addsubpsXrvm","psrlwPrvm","psrldPrvm","psrlqPrvm",
189"paddqPrm","pmullwPrm", 190"paddqPrvm","pmullwPrvm",
190"|movq2dqXrMm|movqXmr|movdq2qMrXm$","pmovmskbVrMm||pmovmskbVrXm", 191"|movq2dqXrMm|movqXmr|movdq2qMrXm$","pmovmskbVrMm||pmovmskbVrXm",
191"psubusbPrm","psubuswPrm","pminubPrm","pandPrm", 192"psubusbPrvm","psubuswPrvm","pminubPrvm","pandPrvm",
192"paddusbPrm","padduswPrm","pmaxubPrm","pandnPrm", 193"paddusbPrvm","padduswPrvm","pmaxubPrvm","pandnPrvm",
193--Ex 194--Ex
194"pavgbPrm","psrawPrm","psradPrm","pavgwPrm", 195"pavgbPrvm","psrawPrvm","psradPrvm","pavgwPrvm",
195"pmulhuwPrm","pmulhwPrm", 196"pmulhuwPrvm","pmulhwPrvm",
196"|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm","$movntqMmr||$movntdqXmr", 197"|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm","$movntqMmr||$movntdqXmr",
197"psubsbPrm","psubswPrm","pminswPrm","porPrm", 198"psubsbPrvm","psubswPrvm","pminswPrvm","porPrvm",
198"paddsbPrm","paddswPrm","pmaxswPrm","pxorPrm", 199"paddsbPrvm","paddswPrvm","pmaxswPrvm","pxorPrvm",
199--Fx 200--Fx
200"|||lddquXrm","psllwPrm","pslldPrm","psllqPrm", 201"|||lddquXrm","psllwPrvm","pslldPrvm","psllqPrvm",
201"pmuludqPrm","pmaddwdPrm","psadbwPrm","maskmovqMrm||maskmovdquXrm$", 202"pmuludqPrvm","pmaddwdPrvm","psadbwPrvm","maskmovqMrm||maskmovdquXrm$",
202"psubbPrm","psubwPrm","psubdPrm","psubqPrm", 203"psubbPrvm","psubwPrvm","psubdPrvm","psubqPrvm",
203"paddbPrm","paddwPrm","padddPrm","ud", 204"paddbPrvm","paddwPrvm","padddPrvm","ud",
204} 205}
205assert(map_opc2[255] == "ud") 206assert(map_opc2[255] == "ud")
206 207
@@ -208,49 +209,91 @@ assert(map_opc2[255] == "ud")
208local map_opc3 = { 209local map_opc3 = {
209["38"] = { -- [66] 0f 38 xx 210["38"] = { -- [66] 0f 38 xx
210--0x 211--0x
211[0]="pshufbPrm","phaddwPrm","phadddPrm","phaddswPrm", 212[0]="pshufbPrvm","phaddwPrvm","phadddPrvm","phaddswPrvm",
212"pmaddubswPrm","phsubwPrm","phsubdPrm","phsubswPrm", 213"pmaddubswPrvm","phsubwPrvm","phsubdPrvm","phsubswPrvm",
213"psignbPrm","psignwPrm","psigndPrm","pmulhrswPrm", 214"psignbPrvm","psignwPrvm","psigndPrvm","pmulhrswPrvm",
214nil,nil,nil,nil, 215"||permilpsXrvm","||permilpdXrvm",nil,nil,
215--1x 216--1x
216"||pblendvbXrma",nil,nil,nil, 217"||pblendvbXrma",nil,nil,nil,
217"||blendvpsXrma","||blendvpdXrma",nil,"||ptestXrm", 218"||blendvpsXrma","||blendvpdXrma","||permpsXrvm","||ptestXrm",
218nil,nil,nil,nil, 219"||broadcastssXrm","||broadcastsdXrm","||broadcastf128XrlXm",nil,
219"pabsbPrm","pabswPrm","pabsdPrm",nil, 220"pabsbPrm","pabswPrm","pabsdPrm",nil,
220--2x 221--2x
221"||pmovsxbwXrm","||pmovsxbdXrm","||pmovsxbqXrm","||pmovsxwdXrm", 222"||pmovsxbwXrm","||pmovsxbdXrm","||pmovsxbqXrm","||pmovsxwdXrm",
222"||pmovsxwqXrm","||pmovsxdqXrm",nil,nil, 223"||pmovsxwqXrm","||pmovsxdqXrm",nil,nil,
223"||pmuldqXrm","||pcmpeqqXrm","||$movntdqaXrm","||packusdwXrm", 224"||pmuldqXrvm","||pcmpeqqXrvm","||$movntdqaXrm","||packusdwXrvm",
224nil,nil,nil,nil, 225"||maskmovpsXrvm","||maskmovpdXrvm","||maskmovpsXmvr","||maskmovpdXmvr",
225--3x 226--3x
226"||pmovzxbwXrm","||pmovzxbdXrm","||pmovzxbqXrm","||pmovzxwdXrm", 227"||pmovzxbwXrm","||pmovzxbdXrm","||pmovzxbqXrm","||pmovzxwdXrm",
227"||pmovzxwqXrm","||pmovzxdqXrm",nil,"||pcmpgtqXrm", 228"||pmovzxwqXrm","||pmovzxdqXrm","||permdXrvm","||pcmpgtqXrvm",
228"||pminsbXrm","||pminsdXrm","||pminuwXrm","||pminudXrm", 229"||pminsbXrvm","||pminsdXrvm","||pminuwXrvm","||pminudXrvm",
229"||pmaxsbXrm","||pmaxsdXrm","||pmaxuwXrm","||pmaxudXrm", 230"||pmaxsbXrvm","||pmaxsdXrvm","||pmaxuwXrvm","||pmaxudXrvm",
230--4x 231--4x
231"||pmulddXrm","||phminposuwXrm", 232"||pmulddXrvm","||phminposuwXrm",nil,nil,
233nil,"||psrlvVSXrvm","||psravdXrvm","||psllvVSXrvm",
234--5x
235[0x58] = "||pbroadcastdXrlXm",[0x59] = "||pbroadcastqXrlXm",
236[0x5a] = "||broadcasti128XrlXm",
237--7x
238[0x78] = "||pbroadcastbXrlXm",[0x79] = "||pbroadcastwXrlXm",
239--8x
240[0x8c] = "||pmaskmovXrvVSm",
241[0x8e] = "||pmaskmovVSmXvr",
242--9x
243[0x96] = "||fmaddsub132pHXrvm",[0x97] = "||fmsubadd132pHXrvm",
244[0x98] = "||fmadd132pHXrvm",[0x99] = "||fmadd132sHXrvm",
245[0x9a] = "||fmsub132pHXrvm",[0x9b] = "||fmsub132sHXrvm",
246[0x9c] = "||fnmadd132pHXrvm",[0x9d] = "||fnmadd132sHXrvm",
247[0x9e] = "||fnmsub132pHXrvm",[0x9f] = "||fnmsub132sHXrvm",
248--Ax
249[0xa6] = "||fmaddsub213pHXrvm",[0xa7] = "||fmsubadd213pHXrvm",
250[0xa8] = "||fmadd213pHXrvm",[0xa9] = "||fmadd213sHXrvm",
251[0xaa] = "||fmsub213pHXrvm",[0xab] = "||fmsub213sHXrvm",
252[0xac] = "||fnmadd213pHXrvm",[0xad] = "||fnmadd213sHXrvm",
253[0xae] = "||fnmsub213pHXrvm",[0xaf] = "||fnmsub213sHXrvm",
254--Bx
255[0xb6] = "||fmaddsub231pHXrvm",[0xb7] = "||fmsubadd231pHXrvm",
256[0xb8] = "||fmadd231pHXrvm",[0xb9] = "||fmadd231sHXrvm",
257[0xba] = "||fmsub231pHXrvm",[0xbb] = "||fmsub231sHXrvm",
258[0xbc] = "||fnmadd231pHXrvm",[0xbd] = "||fnmadd231sHXrvm",
259[0xbe] = "||fnmsub231pHXrvm",[0xbf] = "||fnmsub231sHXrvm",
260--Dx
261[0xdc] = "||aesencXrvm", [0xdd] = "||aesenclastXrvm",
262[0xde] = "||aesdecXrvm", [0xdf] = "||aesdeclastXrvm",
232--Fx 263--Fx
233[0xf0] = "|||crc32TrBmt",[0xf1] = "|||crc32TrVmt", 264[0xf0] = "|||crc32TrBmt",[0xf1] = "|||crc32TrVmt",
265[0xf7] = "| sarxVrmv| shlxVrmv| shrxVrmv",
234}, 266},
235 267
236["3a"] = { -- [66] 0f 3a xx 268["3a"] = { -- [66] 0f 3a xx
237--0x 269--0x
238[0x00]=nil,nil,nil,nil,nil,nil,nil,nil, 270[0x00]="||permqXrmu","||permpdXrmu","||pblenddXrvmu",nil,
239"||roundpsXrmu","||roundpdXrmu","||roundssXrmu","||roundsdXrmu", 271"||permilpsXrmu","||permilpdXrmu","||perm2f128Xrvmu",nil,
240"||blendpsXrmu","||blendpdXrmu","||pblendwXrmu","palignrPrmu", 272"||roundpsXrmu","||roundpdXrmu","||roundssXrvmu","||roundsdXrvmu",
273"||blendpsXrvmu","||blendpdXrvmu","||pblendwXrvmu","palignrPrvmu",
241--1x 274--1x
242nil,nil,nil,nil, 275nil,nil,nil,nil,
243"||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru", 276"||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru",
244nil,nil,nil,nil,nil,nil,nil,nil, 277"||insertf128XrvlXmu","||extractf128XlXmYru",nil,nil,
278nil,nil,nil,nil,
245--2x 279--2x
246"||pinsrbXrVmu","||insertpsXrmu","||pinsrXrVmuS",nil, 280"||pinsrbXrvVmu","||insertpsXrvmu","||pinsrXrvVmuS",nil,
281--3x
282[0x38] = "||inserti128Xrvmu",[0x39] = "||extracti128XlXmYru",
247--4x 283--4x
248[0x40] = "||dppsXrmu", 284[0x40] = "||dppsXrvmu",
249[0x41] = "||dppdXrmu", 285[0x41] = "||dppdXrvmu",
250[0x42] = "||mpsadbwXrmu", 286[0x42] = "||mpsadbwXrvmu",
287[0x44] = "||pclmulqdqXrvmu",
288[0x46] = "||perm2i128Xrvmu",
289[0x4a] = "||blendvpsXrvmb",[0x4b] = "||blendvpdXrvmb",
290[0x4c] = "||pblendvbXrvmb",
251--6x 291--6x
252[0x60] = "||pcmpestrmXrmu",[0x61] = "||pcmpestriXrmu", 292[0x60] = "||pcmpestrmXrmu",[0x61] = "||pcmpestriXrmu",
253[0x62] = "||pcmpistrmXrmu",[0x63] = "||pcmpistriXrmu", 293[0x62] = "||pcmpistrmXrmu",[0x63] = "||pcmpistriXrmu",
294[0xdf] = "||aeskeygenassistXrmu",
295--Fx
296[0xf0] = "||| rorxVrmu",
254}, 297},
255} 298}
256 299
@@ -354,17 +397,19 @@ local map_regs = {
354 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }, -- No x64 ext! 397 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }, -- No x64 ext!
355 X = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", 398 X = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
356 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" }, 399 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" },
400 Y = { "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7",
401 "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15" },
357} 402}
358local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" } 403local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" }
359 404
360-- Maps for size names. 405-- Maps for size names.
361local map_sz2n = { 406local map_sz2n = {
362 B = 1, W = 2, D = 4, Q = 8, M = 8, X = 16, 407 B = 1, W = 2, D = 4, Q = 8, M = 8, X = 16, Y = 32,
363} 408}
364local map_sz2prefix = { 409local map_sz2prefix = {
365 B = "byte", W = "word", D = "dword", 410 B = "byte", W = "word", D = "dword",
366 Q = "qword", 411 Q = "qword",
367 M = "qword", X = "xword", 412 M = "qword", X = "xword", Y = "yword",
368 F = "dword", G = "qword", -- No need for sizes/register names for these two. 413 F = "dword", G = "qword", -- No need for sizes/register names for these two.
369} 414}
370 415
@@ -387,10 +432,13 @@ local function putop(ctx, text, operands)
387 if ctx.rep then text = ctx.rep.." "..text; ctx.rep = false end 432 if ctx.rep then text = ctx.rep.." "..text; ctx.rep = false end
388 if ctx.rex then 433 if ctx.rex then
389 local t = (ctx.rexw and "w" or "")..(ctx.rexr and "r" or "").. 434 local t = (ctx.rexw and "w" or "")..(ctx.rexr and "r" or "")..
390 (ctx.rexx and "x" or "")..(ctx.rexb and "b" or "") 435 (ctx.rexx and "x" or "")..(ctx.rexb and "b" or "")..
391 if t ~= "" then text = "rex."..t.." "..text end 436 (ctx.vexl and "l" or "")
437 if ctx.vexv and ctx.vexv ~= 0 then t = t.."v"..ctx.vexv end
438 if t ~= "" then text = ctx.rex.."."..t.." "..gsub(text, "^ ", "")
439 elseif ctx.rex == "vex" then text = gsub("v"..text, "^v ", "") end
392 ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false 440 ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
393 ctx.rex = false 441 ctx.rex = false; ctx.vexl = false; ctx.vexv = false
394 end 442 end
395 if ctx.seg then 443 if ctx.seg then
396 local text2, n = gsub(text, "%[", "["..ctx.seg..":") 444 local text2, n = gsub(text, "%[", "["..ctx.seg..":")
@@ -405,6 +453,7 @@ local function putop(ctx, text, operands)
405 end 453 end
406 ctx.out(format("%08x %s%s\n", ctx.addr+ctx.start, hex, text)) 454 ctx.out(format("%08x %s%s\n", ctx.addr+ctx.start, hex, text))
407 ctx.mrm = false 455 ctx.mrm = false
456 ctx.vexv = false
408 ctx.start = pos 457 ctx.start = pos
409 ctx.imm = nil 458 ctx.imm = nil
410end 459end
@@ -413,7 +462,7 @@ end
413local function clearprefixes(ctx) 462local function clearprefixes(ctx)
414 ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false 463 ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false
415 ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false 464 ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
416 ctx.rex = false; ctx.a32 = false 465 ctx.rex = false; ctx.a32 = false; ctx.vexl = false
417end 466end
418 467
419-- Fallback for incomplete opcodes at the end. 468-- Fallback for incomplete opcodes at the end.
@@ -450,9 +499,9 @@ end
450-- Process pattern string and generate the operands. 499-- Process pattern string and generate the operands.
451local function putpat(ctx, name, pat) 500local function putpat(ctx, name, pat)
452 local operands, regs, sz, mode, sp, rm, sc, rx, sdisp 501 local operands, regs, sz, mode, sp, rm, sc, rx, sdisp
453 local code, pos, stop = ctx.code, ctx.pos, ctx.stop 502 local code, pos, stop, vexl = ctx.code, ctx.pos, ctx.stop, ctx.vexl
454 503
455 -- Chars used: 1DFGIMPQRSTUVWXacdfgijmoprstuwxyz 504 -- Chars used: 1DFGHIMPQRSTUVWXYabcdfgijlmoprstuvwxyz
456 for p in gmatch(pat, ".") do 505 for p in gmatch(pat, ".") do
457 local x = nil 506 local x = nil
458 if p == "V" or p == "U" then 507 if p == "V" or p == "U" then
@@ -467,12 +516,17 @@ local function putpat(ctx, name, pat)
467 elseif p == "B" then 516 elseif p == "B" then
468 sz = "B" 517 sz = "B"
469 regs = ctx.rex and map_regs.B64 or map_regs.B 518 regs = ctx.rex and map_regs.B64 or map_regs.B
470 elseif match(p, "[WDQMXFG]") then 519 elseif match(p, "[WDQMXYFG]") then
471 sz = p 520 sz = p
521 if sz == "X" and vexl then sz = "Y"; ctx.vexl = false end
472 regs = map_regs[sz] 522 regs = map_regs[sz]
473 elseif p == "P" then 523 elseif p == "P" then
474 sz = ctx.o16 and "X" or "M"; ctx.o16 = false 524 sz = ctx.o16 and "X" or "M"; ctx.o16 = false
525 if sz == "X" and vexl then sz = "Y"; ctx.vexl = false end
475 regs = map_regs[sz] 526 regs = map_regs[sz]
527 elseif p == "H" then
528 name = name..(ctx.rexw and "d" or "s")
529 ctx.rexw = false
476 elseif p == "S" then 530 elseif p == "S" then
477 name = name..lower(sz) 531 name = name..lower(sz)
478 elseif p == "s" then 532 elseif p == "s" then
@@ -484,6 +538,10 @@ local function putpat(ctx, name, pat)
484 local imm = getimm(ctx, pos, 1); if not imm then return end 538 local imm = getimm(ctx, pos, 1); if not imm then return end
485 x = format("0x%02x", imm) 539 x = format("0x%02x", imm)
486 pos = pos+1 540 pos = pos+1
541 elseif p == "b" then
542 local imm = getimm(ctx, pos, 1); if not imm then return end
543 x = regs[imm/16+1]
544 pos = pos+1
487 elseif p == "w" then 545 elseif p == "w" then
488 local imm = getimm(ctx, pos, 2); if not imm then return end 546 local imm = getimm(ctx, pos, 2); if not imm then return end
489 x = format("0x%x", imm) 547 x = format("0x%x", imm)
@@ -532,7 +590,7 @@ local function putpat(ctx, name, pat)
532 local lo = imm % 0x1000000 590 local lo = imm % 0x1000000
533 x = format("0x%02x%06x", (imm-lo) / 0x1000000, lo) 591 x = format("0x%02x%06x", (imm-lo) / 0x1000000, lo)
534 else 592 else
535 x = format("0x%08x", imm) 593 x = "0x"..tohex(imm)
536 end 594 end
537 elseif p == "R" then 595 elseif p == "R" then
538 local r = byte(code, pos-1, pos-1)%8 596 local r = byte(code, pos-1, pos-1)%8
@@ -616,8 +674,13 @@ local function putpat(ctx, name, pat)
616 else 674 else
617 x = "CR"..sp 675 x = "CR"..sp
618 end 676 end
677 elseif p == "v" then
678 if ctx.vexv then
679 x = regs[ctx.vexv+1]; ctx.vexv = false
680 end
619 elseif p == "y" then x = "DR"..sp 681 elseif p == "y" then x = "DR"..sp
620 elseif p == "z" then x = "TR"..sp 682 elseif p == "z" then x = "TR"..sp
683 elseif p == "l" then vexl = false
621 elseif p == "t" then 684 elseif p == "t" then
622 else 685 else
623 error("bad pattern `"..pat.."'") 686 error("bad pattern `"..pat.."'")
@@ -692,7 +755,8 @@ map_act = {
692 B = putpat, W = putpat, D = putpat, Q = putpat, 755 B = putpat, W = putpat, D = putpat, Q = putpat,
693 V = putpat, U = putpat, T = putpat, 756 V = putpat, U = putpat, T = putpat,
694 M = putpat, X = putpat, P = putpat, 757 M = putpat, X = putpat, P = putpat,
695 F = putpat, G = putpat, 758 F = putpat, G = putpat, Y = putpat,
759 H = putpat,
696 760
697 -- Collect prefixes. 761 -- Collect prefixes.
698 [":"] = function(ctx, name, pat) 762 [":"] = function(ctx, name, pat)
@@ -753,15 +817,68 @@ map_act = {
753 817
754 -- REX prefix. 818 -- REX prefix.
755 rex = function(ctx, name, pat) 819 rex = function(ctx, name, pat)
756 if ctx.rex then return unknown(ctx) end -- Only 1 REX prefix allowed. 820 if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed.
757 for p in gmatch(pat, ".") do ctx["rex"..p] = true end 821 for p in gmatch(pat, ".") do ctx["rex"..p] = true end
758 ctx.rex = true 822 ctx.rex = "rex"
823 end,
824
825 -- VEX prefix.
826 vex = function(ctx, name, pat)
827 if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed.
828 ctx.rex = "vex"
829 local pos = ctx.pos
830 if ctx.mrm then
831 ctx.mrm = nil
832 pos = pos-1
833 end
834 local b = byte(ctx.code, pos, pos)
835 if not b then return incomplete(ctx) end
836 pos = pos+1
837 if b < 128 then ctx.rexr = true end
838 local m = 1
839 if pat == "3" then
840 m = b%32; b = (b-m)/32
841 local nb = b%2; b = (b-nb)/2
842 if nb == 0 then ctx.rexb = true end
843 local nx = b%2
844 if nx == 0 then ctx.rexx = true end
845 b = byte(ctx.code, pos, pos)
846 if not b then return incomplete(ctx) end
847 pos = pos+1
848 if b >= 128 then ctx.rexw = true end
849 end
850 ctx.pos = pos
851 local map
852 if m == 1 then map = map_opc2
853 elseif m == 2 then map = map_opc3["38"]
854 elseif m == 3 then map = map_opc3["3a"]
855 else return unknown(ctx) end
856 local p = b%4; b = (b-p)/4
857 if p == 1 then ctx.o16 = "o16"
858 elseif p == 2 then ctx.rep = "rep"
859 elseif p == 3 then ctx.rep = "repne" end
860 local l = b%2; b = (b-l)/2
861 if l ~= 0 then ctx.vexl = true end
862 ctx.vexv = (-1-b)%16
863 return dispatchmap(ctx, map)
759 end, 864 end,
760 865
761 -- Special case for nop with REX prefix. 866 -- Special case for nop with REX prefix.
762 nop = function(ctx, name, pat) 867 nop = function(ctx, name, pat)
763 return dispatch(ctx, ctx.rex and pat or "nop") 868 return dispatch(ctx, ctx.rex and pat or "nop")
764 end, 869 end,
870
871 -- Special case for 0F 77.
872 emms = function(ctx, name, pat)
873 if ctx.rex ~= "vex" then
874 return putop(ctx, "emms")
875 elseif ctx.vexl then
876 ctx.vexl = false
877 return putop(ctx, "zeroall")
878 else
879 return putop(ctx, "zeroupper")
880 end
881 end,
765} 882}
766 883
767------------------------------------------------------------------------------ 884------------------------------------------------------------------------------
@@ -782,7 +899,7 @@ local function disass_block(ctx, ofs, len)
782end 899end
783 900
784-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). 901-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
785local function create_(code, addr, out) 902local function create(code, addr, out)
786 local ctx = {} 903 local ctx = {}
787 ctx.code = code 904 ctx.code = code
788 ctx.addr = (addr or 0) - 1 905 ctx.addr = (addr or 0) - 1
@@ -796,8 +913,8 @@ local function create_(code, addr, out)
796 return ctx 913 return ctx
797end 914end
798 915
799local function create64_(code, addr, out) 916local function create64(code, addr, out)
800 local ctx = create_(code, addr, out) 917 local ctx = create(code, addr, out)
801 ctx.x64 = true 918 ctx.x64 = true
802 ctx.map1 = map_opc1_64 919 ctx.map1 = map_opc1_64
803 ctx.aregs = map_regs.Q 920 ctx.aregs = map_regs.Q
@@ -805,32 +922,32 @@ local function create64_(code, addr, out)
805end 922end
806 923
807-- Simple API: disassemble code (a string) at address and output via out. 924-- Simple API: disassemble code (a string) at address and output via out.
808local function disass_(code, addr, out) 925local function disass(code, addr, out)
809 create_(code, addr, out):disass() 926 create(code, addr, out):disass()
810end 927end
811 928
812local function disass64_(code, addr, out) 929local function disass64(code, addr, out)
813 create64_(code, addr, out):disass() 930 create64(code, addr, out):disass()
814end 931end
815 932
816-- Return register name for RID. 933-- Return register name for RID.
817local function regname_(r) 934local function regname(r)
818 if r < 8 then return map_regs.D[r+1] end 935 if r < 8 then return map_regs.D[r+1] end
819 return map_regs.X[r-7] 936 return map_regs.X[r-7]
820end 937end
821 938
822local function regname64_(r) 939local function regname64(r)
823 if r < 16 then return map_regs.Q[r+1] end 940 if r < 16 then return map_regs.Q[r+1] end
824 return map_regs.X[r-15] 941 return map_regs.X[r-15]
825end 942end
826 943
827-- Public module functions. 944-- Public module functions.
828module(...) 945return {
829 946 create = create,
830create = create_ 947 create64 = create64,
831create64 = create64_ 948 disass = disass,
832disass = disass_ 949 disass64 = disass64,
833disass64 = disass64_ 950 regname = regname,
834regname = regname_ 951 regname64 = regname64
835regname64 = regname64_ 952}
836 953
diff --git a/src/jit/dump.lua b/src/jit/dump.lua
index e7f694d6..4800a6b8 100644
--- a/src/jit/dump.lua
+++ b/src/jit/dump.lua
@@ -55,7 +55,7 @@
55 55
56-- Cache some library functions and objects. 56-- Cache some library functions and objects.
57local jit = require("jit") 57local jit = require("jit")
58assert(jit.version_num == 20005, "LuaJIT core/library version mismatch") 58assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
59local jutil = require("jit.util") 59local jutil = require("jit.util")
60local vmdef = require("jit.vmdef") 60local vmdef = require("jit.vmdef")
61local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc 61local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc
@@ -63,7 +63,7 @@ local traceinfo, traceir, tracek = jutil.traceinfo, jutil.traceir, jutil.tracek
63local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap 63local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap
64local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr 64local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr
65local bit = require("bit") 65local bit = require("bit")
66local band, shr = bit.band, bit.rshift 66local band, shr, tohex = bit.band, bit.rshift, bit.tohex
67local sub, gsub, format = string.sub, string.gsub, string.format 67local sub, gsub, format = string.sub, string.gsub, string.format
68local byte, rep = string.byte, string.rep 68local byte, rep = string.byte, string.rep
69local type, tostring = type, tostring 69local type, tostring = type, tostring
@@ -85,12 +85,13 @@ local nexitsym = 0
85local function fillsymtab_tr(tr, nexit) 85local function fillsymtab_tr(tr, nexit)
86 local t = {} 86 local t = {}
87 symtabmt.__index = t 87 symtabmt.__index = t
88 if jit.arch == "mips" or jit.arch == "mipsel" then 88 if jit.arch:sub(1, 4) == "mips" then
89 t[traceexitstub(tr, 0)] = "exit" 89 t[traceexitstub(tr, 0)] = "exit"
90 return 90 return
91 end 91 end
92 for i=0,nexit-1 do 92 for i=0,nexit-1 do
93 local addr = traceexitstub(tr, i) 93 local addr = traceexitstub(tr, i)
94 if addr < 0 then addr = addr + 2^32 end
94 t[addr] = tostring(i) 95 t[addr] = tostring(i)
95 end 96 end
96 local addr = traceexitstub(tr, nexit) 97 local addr = traceexitstub(tr, nexit)
@@ -104,7 +105,10 @@ local function fillsymtab(tr, nexit)
104 local ircall = vmdef.ircall 105 local ircall = vmdef.ircall
105 for i=0,#ircall do 106 for i=0,#ircall do
106 local addr = ircalladdr(i) 107 local addr = ircalladdr(i)
107 if addr ~= 0 then t[addr] = ircall[i] end 108 if addr ~= 0 then
109 if addr < 0 then addr = addr + 2^32 end
110 t[addr] = ircall[i]
111 end
108 end 112 end
109 end 113 end
110 if nexitsym == 1000000 then -- Per-trace exit stubs. 114 if nexitsym == 1000000 then -- Per-trace exit stubs.
@@ -118,6 +122,7 @@ local function fillsymtab(tr, nexit)
118 nexit = 1000000 122 nexit = 1000000
119 break 123 break
120 end 124 end
125 if addr < 0 then addr = addr + 2^32 end
121 t[addr] = tostring(i) 126 t[addr] = tostring(i)
122 end 127 end
123 nexitsym = nexit 128 nexitsym = nexit
@@ -136,6 +141,7 @@ local function dump_mcode(tr)
136 local mcode, addr, loop = tracemc(tr) 141 local mcode, addr, loop = tracemc(tr)
137 if not mcode then return end 142 if not mcode then return end
138 if not disass then disass = require("jit.dis_"..jit.arch) end 143 if not disass then disass = require("jit.dis_"..jit.arch) end
144 if addr < 0 then addr = addr + 2^32 end
139 out:write("---- TRACE ", tr, " mcode ", #mcode, "\n") 145 out:write("---- TRACE ", tr, " mcode ", #mcode, "\n")
140 local ctx = disass.create(mcode, addr, dumpwrite) 146 local ctx = disass.create(mcode, addr, dumpwrite)
141 ctx.hexdump = 0 147 ctx.hexdump = 0
@@ -270,8 +276,7 @@ local litname = {
270 ["CONV "] = setmetatable({}, { __index = function(t, mode) 276 ["CONV "] = setmetatable({}, { __index = function(t, mode)
271 local s = irtype[band(mode, 31)] 277 local s = irtype[band(mode, 31)]
272 s = irtype[band(shr(mode, 5), 31)].."."..s 278 s = irtype[band(shr(mode, 5), 31)].."."..s
273 if band(mode, 0x400) ~= 0 then s = s.." trunc" 279 if band(mode, 0x800) ~= 0 then s = s.." sext" end
274 elseif band(mode, 0x800) ~= 0 then s = s.." sext" end
275 local c = shr(mode, 14) 280 local c = shr(mode, 14)
276 if c == 2 then s = s.." index" elseif c == 3 then s = s.." check" end 281 if c == 2 then s = s.." index" elseif c == 3 then s = s.." check" end
277 t[mode] = s 282 t[mode] = s
@@ -280,6 +285,8 @@ local litname = {
280 ["FLOAD "] = vmdef.irfield, 285 ["FLOAD "] = vmdef.irfield,
281 ["FREF "] = vmdef.irfield, 286 ["FREF "] = vmdef.irfield,
282 ["FPMATH"] = vmdef.irfpm, 287 ["FPMATH"] = vmdef.irfpm,
288 ["BUFHDR"] = { [0] = "RESET", "APPEND" },
289 ["TOSTR "] = { [0] = "INT", "NUM", "CHAR" },
283} 290}
284 291
285local function ctlsub(c) 292local function ctlsub(c)
@@ -303,15 +310,19 @@ local function fmtfunc(func, pc)
303 end 310 end
304end 311end
305 312
306local function formatk(tr, idx) 313local function formatk(tr, idx, sn)
307 local k, t, slot = tracek(tr, idx) 314 local k, t, slot = tracek(tr, idx)
308 local tn = type(k) 315 local tn = type(k)
309 local s 316 local s
310 if tn == "number" then 317 if tn == "number" then
311 if k == 2^52+2^51 then 318 if t < 12 then
319 s = k == 0 and "NULL" or format("[0x%08x]", k)
320 elseif band(sn or 0, 0x30000) ~= 0 then
321 s = band(sn, 0x20000) ~= 0 and "contpc" or "ftsz"
322 elseif k == 2^52+2^51 then
312 s = "bias" 323 s = "bias"
313 else 324 else
314 s = format("%+.14g", k) 325 s = format(0 < k and k < 0x1p-1026 and "%+a" or "%+.14g", k)
315 end 326 end
316 elseif tn == "string" then 327 elseif tn == "string" then
317 s = format(#k > 20 and '"%.20s"~' or '"%s"', gsub(k, "%c", ctlsub)) 328 s = format(#k > 20 and '"%.20s"~' or '"%s"', gsub(k, "%c", ctlsub))
@@ -329,6 +340,8 @@ local function formatk(tr, idx)
329 elseif t == 21 then -- int64_t 340 elseif t == 21 then -- int64_t
330 s = sub(tostring(k), 1, -3) 341 s = sub(tostring(k), 1, -3)
331 if sub(s, 1, 1) ~= "-" then s = "+"..s end 342 if sub(s, 1, 1) ~= "-" then s = "+"..s end
343 elseif sn == 0x1057fff then -- SNAP(1, SNAP_FRAME | SNAP_NORESTORE, REF_NIL)
344 return "----" -- Special case for LJ_FR2 slot 1.
332 else 345 else
333 s = tostring(k) -- For primitives. 346 s = tostring(k) -- For primitives.
334 end 347 end
@@ -347,7 +360,7 @@ local function printsnap(tr, snap)
347 n = n + 1 360 n = n + 1
348 local ref = band(sn, 0xffff) - 0x8000 -- REF_BIAS 361 local ref = band(sn, 0xffff) - 0x8000 -- REF_BIAS
349 if ref < 0 then 362 if ref < 0 then
350 out:write(formatk(tr, ref)) 363 out:write(formatk(tr, ref, sn))
351 elseif band(sn, 0x80000) ~= 0 then -- SNAP_SOFTFPNUM 364 elseif band(sn, 0x80000) ~= 0 then -- SNAP_SOFTFPNUM
352 out:write(colorize(format("%04d/%04d", ref, ref+1), 14)) 365 out:write(colorize(format("%04d/%04d", ref, ref+1), 14))
353 else 366 else
@@ -545,7 +558,7 @@ local function dump_trace(what, tr, func, pc, otr, oex)
545 if what == "start" then 558 if what == "start" then
546 if dumpmode.H then out:write('<pre class="ljdump">\n') end 559 if dumpmode.H then out:write('<pre class="ljdump">\n') end
547 out:write("---- TRACE ", tr, " ", what) 560 out:write("---- TRACE ", tr, " ", what)
548 if otr then out:write(" ", otr, "/", oex) end 561 if otr then out:write(" ", otr, "/", oex == -1 and "stitch" or oex) end
549 out:write(" ", fmtfunc(func, pc), "\n") 562 out:write(" ", fmtfunc(func, pc), "\n")
550 elseif what == "stop" or what == "abort" then 563 elseif what == "stop" or what == "abort" then
551 out:write("---- TRACE ", tr, " ", what) 564 out:write("---- TRACE ", tr, " ", what)
@@ -595,23 +608,26 @@ end
595 608
596------------------------------------------------------------------------------ 609------------------------------------------------------------------------------
597 610
611local gpr64 = jit.arch:match("64")
612local fprmips32 = jit.arch == "mips" or jit.arch == "mipsel"
613
598-- Dump taken trace exits. 614-- Dump taken trace exits.
599local function dump_texit(tr, ex, ngpr, nfpr, ...) 615local function dump_texit(tr, ex, ngpr, nfpr, ...)
600 out:write("---- TRACE ", tr, " exit ", ex, "\n") 616 out:write("---- TRACE ", tr, " exit ", ex, "\n")
601 if dumpmode.X then 617 if dumpmode.X then
602 local regs = {...} 618 local regs = {...}
603 if jit.arch == "x64" then 619 if gpr64 then
604 for i=1,ngpr do 620 for i=1,ngpr do
605 out:write(format(" %016x", regs[i])) 621 out:write(format(" %016x", regs[i]))
606 if i % 4 == 0 then out:write("\n") end 622 if i % 4 == 0 then out:write("\n") end
607 end 623 end
608 else 624 else
609 for i=1,ngpr do 625 for i=1,ngpr do
610 out:write(format(" %08x", regs[i])) 626 out:write(" ", tohex(regs[i]))
611 if i % 8 == 0 then out:write("\n") end 627 if i % 8 == 0 then out:write("\n") end
612 end 628 end
613 end 629 end
614 if jit.arch == "mips" or jit.arch == "mipsel" then 630 if fprmips32 then
615 for i=1,nfpr,2 do 631 for i=1,nfpr,2 do
616 out:write(format(" %+17.14g", regs[ngpr+i])) 632 out:write(format(" %+17.14g", regs[ngpr+i]))
617 if i % 8 == 7 then out:write("\n") end 633 if i % 8 == 7 then out:write("\n") end
@@ -692,9 +708,9 @@ local function dumpon(opt, outfile)
692end 708end
693 709
694-- Public module functions. 710-- Public module functions.
695module(...) 711return {
696 712 on = dumpon,
697on = dumpon 713 off = dumpoff,
698off = dumpoff 714 start = dumpon -- For -j command line option.
699start = dumpon -- For -j command line option. 715}
700 716
diff --git a/src/jit/p.lua b/src/jit/p.lua
new file mode 100644
index 00000000..c0ad6c0e
--- /dev/null
+++ b/src/jit/p.lua
@@ -0,0 +1,311 @@
1----------------------------------------------------------------------------
2-- LuaJIT profiler.
3--
4-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
5-- Released under the MIT license. See Copyright Notice in luajit.h
6----------------------------------------------------------------------------
7--
8-- This module is a simple command line interface to the built-in
9-- low-overhead profiler of LuaJIT.
10--
11-- The lower-level API of the profiler is accessible via the "jit.profile"
12-- module or the luaJIT_profile_* C API.
13--
14-- Example usage:
15--
16-- luajit -jp myapp.lua
17-- luajit -jp=s myapp.lua
18-- luajit -jp=-s myapp.lua
19-- luajit -jp=vl myapp.lua
20-- luajit -jp=G,profile.txt myapp.lua
21--
22-- The following dump features are available:
23--
24-- f Stack dump: function name, otherwise module:line. Default mode.
25-- F Stack dump: ditto, but always prepend module.
26-- l Stack dump: module:line.
27-- <number> stack dump depth (callee < caller). Default: 1.
28-- -<number> Inverse stack dump depth (caller > callee).
29-- s Split stack dump after first stack level. Implies abs(depth) >= 2.
30-- p Show full path for module names.
31-- v Show VM states. Can be combined with stack dumps, e.g. vf or fv.
32-- z Show zones. Can be combined with stack dumps, e.g. zf or fz.
33-- r Show raw sample counts. Default: show percentages.
34-- a Annotate excerpts from source code files.
35-- A Annotate complete source code files.
36-- G Produce raw output suitable for graphical tools (e.g. flame graphs).
37-- m<number> Minimum sample percentage to be shown. Default: 3.
38-- i<number> Sampling interval in milliseconds. Default: 10.
39--
40----------------------------------------------------------------------------
41
42-- Cache some library functions and objects.
43local jit = require("jit")
44assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
45local profile = require("jit.profile")
46local vmdef = require("jit.vmdef")
47local math = math
48local pairs, ipairs, tonumber, floor = pairs, ipairs, tonumber, math.floor
49local sort, format = table.sort, string.format
50local stdout = io.stdout
51local zone -- Load jit.zone module on demand.
52
53-- Output file handle.
54local out
55
56------------------------------------------------------------------------------
57
58local prof_ud
59local prof_states, prof_split, prof_min, prof_raw, prof_fmt, prof_depth
60local prof_ann, prof_count1, prof_count2, prof_samples
61
62local map_vmmode = {
63 N = "Compiled",
64 I = "Interpreted",
65 C = "C code",
66 G = "Garbage Collector",
67 J = "JIT Compiler",
68}
69
70-- Profiler callback.
71local function prof_cb(th, samples, vmmode)
72 prof_samples = prof_samples + samples
73 local key_stack, key_stack2, key_state
74 -- Collect keys for sample.
75 if prof_states then
76 if prof_states == "v" then
77 key_state = map_vmmode[vmmode] or vmmode
78 else
79 key_state = zone:get() or "(none)"
80 end
81 end
82 if prof_fmt then
83 key_stack = profile.dumpstack(th, prof_fmt, prof_depth)
84 key_stack = key_stack:gsub("%[builtin#(%d+)%]", function(x)
85 return vmdef.ffnames[tonumber(x)]
86 end)
87 if prof_split == 2 then
88 local k1, k2 = key_stack:match("(.-) [<>] (.*)")
89 if k2 then key_stack, key_stack2 = k1, k2 end
90 elseif prof_split == 3 then
91 key_stack2 = profile.dumpstack(th, "l", 1)
92 end
93 end
94 -- Order keys.
95 local k1, k2
96 if prof_split == 1 then
97 if key_state then
98 k1 = key_state
99 if key_stack then k2 = key_stack end
100 end
101 elseif key_stack then
102 k1 = key_stack
103 if key_stack2 then k2 = key_stack2 elseif key_state then k2 = key_state end
104 end
105 -- Coalesce samples in one or two levels.
106 if k1 then
107 local t1 = prof_count1
108 t1[k1] = (t1[k1] or 0) + samples
109 if k2 then
110 local t2 = prof_count2
111 local t3 = t2[k1]
112 if not t3 then t3 = {}; t2[k1] = t3 end
113 t3[k2] = (t3[k2] or 0) + samples
114 end
115 end
116end
117
118------------------------------------------------------------------------------
119
120-- Show top N list.
121local function prof_top(count1, count2, samples, indent)
122 local t, n = {}, 0
123 for k in pairs(count1) do
124 n = n + 1
125 t[n] = k
126 end
127 sort(t, function(a, b) return count1[a] > count1[b] end)
128 for i=1,n do
129 local k = t[i]
130 local v = count1[k]
131 local pct = floor(v*100/samples + 0.5)
132 if pct < prof_min then break end
133 if not prof_raw then
134 out:write(format("%s%2d%% %s\n", indent, pct, k))
135 elseif prof_raw == "r" then
136 out:write(format("%s%5d %s\n", indent, v, k))
137 else
138 out:write(format("%s %d\n", k, v))
139 end
140 if count2 then
141 local r = count2[k]
142 if r then
143 prof_top(r, nil, v, (prof_split == 3 or prof_split == 1) and " -- " or
144 (prof_depth < 0 and " -> " or " <- "))
145 end
146 end
147 end
148end
149
150-- Annotate source code
151local function prof_annotate(count1, samples)
152 local files = {}
153 local ms = 0
154 for k, v in pairs(count1) do
155 local pct = floor(v*100/samples + 0.5)
156 ms = math.max(ms, v)
157 if pct >= prof_min then
158 local file, line = k:match("^(.*):(%d+)$")
159 if not file then file = k; line = 0 end
160 local fl = files[file]
161 if not fl then fl = {}; files[file] = fl; files[#files+1] = file end
162 line = tonumber(line)
163 fl[line] = prof_raw and v or pct
164 end
165 end
166 sort(files)
167 local fmtv, fmtn = " %3d%% | %s\n", " | %s\n"
168 if prof_raw then
169 local n = math.max(5, math.ceil(math.log10(ms)))
170 fmtv = "%"..n.."d | %s\n"
171 fmtn = (" "):rep(n).." | %s\n"
172 end
173 local ann = prof_ann
174 for _, file in ipairs(files) do
175 local f0 = file:byte()
176 if f0 == 40 or f0 == 91 then
177 out:write(format("\n====== %s ======\n[Cannot annotate non-file]\n", file))
178 break
179 end
180 local fp, err = io.open(file)
181 if not fp then
182 out:write(format("====== ERROR: %s: %s\n", file, err))
183 break
184 end
185 out:write(format("\n====== %s ======\n", file))
186 local fl = files[file]
187 local n, show = 1, false
188 if ann ~= 0 then
189 for i=1,ann do
190 if fl[i] then show = true; out:write("@@ 1 @@\n"); break end
191 end
192 end
193 for line in fp:lines() do
194 if line:byte() == 27 then
195 out:write("[Cannot annotate bytecode file]\n")
196 break
197 end
198 local v = fl[n]
199 if ann ~= 0 then
200 local v2 = fl[n+ann]
201 if show then
202 if v2 then show = n+ann elseif v then show = n
203 elseif show+ann < n then show = false end
204 elseif v2 then
205 show = n+ann
206 out:write(format("@@ %d @@\n", n))
207 end
208 if not show then goto next end
209 end
210 if v then
211 out:write(format(fmtv, v, line))
212 else
213 out:write(format(fmtn, line))
214 end
215 ::next::
216 n = n + 1
217 end
218 fp:close()
219 end
220end
221
222------------------------------------------------------------------------------
223
224-- Finish profiling and dump result.
225local function prof_finish()
226 if prof_ud then
227 profile.stop()
228 local samples = prof_samples
229 if samples == 0 then
230 if prof_raw ~= true then out:write("[No samples collected]\n") end
231 return
232 end
233 if prof_ann then
234 prof_annotate(prof_count1, samples)
235 else
236 prof_top(prof_count1, prof_count2, samples, "")
237 end
238 prof_count1 = nil
239 prof_count2 = nil
240 prof_ud = nil
241 end
242end
243
244-- Start profiling.
245local function prof_start(mode)
246 local interval = ""
247 mode = mode:gsub("i%d*", function(s) interval = s; return "" end)
248 prof_min = 3
249 mode = mode:gsub("m(%d+)", function(s) prof_min = tonumber(s); return "" end)
250 prof_depth = 1
251 mode = mode:gsub("%-?%d+", function(s) prof_depth = tonumber(s); return "" end)
252 local m = {}
253 for c in mode:gmatch(".") do m[c] = c end
254 prof_states = m.z or m.v
255 if prof_states == "z" then zone = require("jit.zone") end
256 local scope = m.l or m.f or m.F or (prof_states and "" or "f")
257 local flags = (m.p or "")
258 prof_raw = m.r
259 if m.s then
260 prof_split = 2
261 if prof_depth == -1 or m["-"] then prof_depth = -2
262 elseif prof_depth == 1 then prof_depth = 2 end
263 elseif mode:find("[fF].*l") then
264 scope = "l"
265 prof_split = 3
266 else
267 prof_split = (scope == "" or mode:find("[zv].*[lfF]")) and 1 or 0
268 end
269 prof_ann = m.A and 0 or (m.a and 3)
270 if prof_ann then
271 scope = "l"
272 prof_fmt = "pl"
273 prof_split = 0
274 prof_depth = 1
275 elseif m.G and scope ~= "" then
276 prof_fmt = flags..scope.."Z;"
277 prof_depth = -100
278 prof_raw = true
279 prof_min = 0
280 elseif scope == "" then
281 prof_fmt = false
282 else
283 local sc = prof_split == 3 and m.f or m.F or scope
284 prof_fmt = flags..sc..(prof_depth >= 0 and "Z < " or "Z > ")
285 end
286 prof_count1 = {}
287 prof_count2 = {}
288 prof_samples = 0
289 profile.start(scope:lower()..interval, prof_cb)
290 prof_ud = newproxy(true)
291 getmetatable(prof_ud).__gc = prof_finish
292end
293
294------------------------------------------------------------------------------
295
296local function start(mode, outfile)
297 if not outfile then outfile = os.getenv("LUAJIT_PROFILEFILE") end
298 if outfile then
299 out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
300 else
301 out = stdout
302 end
303 prof_start(mode or "f")
304end
305
306-- Public module functions.
307return {
308 start = start, -- For -j command line option.
309 stop = prof_finish
310}
311
diff --git a/src/jit/v.lua b/src/jit/v.lua
index a39bd203..83589143 100644
--- a/src/jit/v.lua
+++ b/src/jit/v.lua
@@ -59,7 +59,7 @@
59 59
60-- Cache some library functions and objects. 60-- Cache some library functions and objects.
61local jit = require("jit") 61local jit = require("jit")
62assert(jit.version_num == 20005, "LuaJIT core/library version mismatch") 62assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
63local jutil = require("jit.util") 63local jutil = require("jit.util")
64local vmdef = require("jit.vmdef") 64local vmdef = require("jit.vmdef")
65local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo 65local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo
@@ -99,7 +99,7 @@ end
99local function dump_trace(what, tr, func, pc, otr, oex) 99local function dump_trace(what, tr, func, pc, otr, oex)
100 if what == "start" then 100 if what == "start" then
101 startloc = fmtfunc(func, pc) 101 startloc = fmtfunc(func, pc)
102 startex = otr and "("..otr.."/"..oex..") " or "" 102 startex = otr and "("..otr.."/"..(oex == -1 and "stitch" or oex)..") " or ""
103 else 103 else
104 if what == "abort" then 104 if what == "abort" then
105 local loc = fmtfunc(func, pc) 105 local loc = fmtfunc(func, pc)
@@ -116,6 +116,9 @@ local function dump_trace(what, tr, func, pc, otr, oex)
116 if ltype == "interpreter" then 116 if ltype == "interpreter" then
117 out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n", 117 out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n",
118 tr, startex, startloc)) 118 tr, startex, startloc))
119 elseif ltype == "stitch" then
120 out:write(format("[TRACE %3s %s%s %s %s]\n",
121 tr, startex, startloc, ltype, fmtfunc(func, pc)))
119 elseif link == tr or link == 0 then 122 elseif link == tr or link == 0 then
120 out:write(format("[TRACE %3s %s%s %s]\n", 123 out:write(format("[TRACE %3s %s%s %s]\n",
121 tr, startex, startloc, ltype)) 124 tr, startex, startloc, ltype))
@@ -159,9 +162,9 @@ local function dumpon(outfile)
159end 162end
160 163
161-- Public module functions. 164-- Public module functions.
162module(...) 165return {
163 166 on = dumpon,
164on = dumpon 167 off = dumpoff,
165off = dumpoff 168 start = dumpon -- For -j command line option.
166start = dumpon -- For -j command line option. 169}
167 170
diff --git a/src/jit/zone.lua b/src/jit/zone.lua
new file mode 100644
index 00000000..94357854
--- /dev/null
+++ b/src/jit/zone.lua
@@ -0,0 +1,45 @@
1----------------------------------------------------------------------------
2-- LuaJIT profiler zones.
3--
4-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
5-- Released under the MIT license. See Copyright Notice in luajit.h
6----------------------------------------------------------------------------
7--
8-- This module implements a simple hierarchical zone model.
9--
10-- Example usage:
11--
12-- local zone = require("jit.zone")
13-- zone("AI")
14-- ...
15-- zone("A*")
16-- ...
17-- print(zone:get()) --> "A*"
18-- ...
19-- zone()
20-- ...
21-- print(zone:get()) --> "AI"
22-- ...
23-- zone()
24--
25----------------------------------------------------------------------------
26
27local remove = table.remove
28
29return setmetatable({
30 flush = function(t)
31 for i=#t,1,-1 do t[i] = nil end
32 end,
33 get = function(t)
34 return t[#t]
35 end
36}, {
37 __call = function(t, zone)
38 if zone then
39 t[#t+1] = zone
40 else
41 return (assert(remove(t), "empty zone stack"))
42 end
43 end
44})
45