diff options
Diffstat (limited to 'src/jit')
-rw-r--r-- | src/jit/bc.lua | 19 | ||||
-rw-r--r-- | src/jit/bcsave.lua | 106 | ||||
-rw-r--r-- | src/jit/dis_arm.lua | 18 | ||||
-rw-r--r-- | src/jit/dis_arm64.lua | 1216 | ||||
-rw-r--r-- | src/jit/dis_arm64be.lua | 12 | ||||
-rw-r--r-- | src/jit/dis_mips.lua | 372 | ||||
-rw-r--r-- | src/jit/dis_mips64.lua | 17 | ||||
-rw-r--r-- | src/jit/dis_mips64el.lua | 17 | ||||
-rw-r--r-- | src/jit/dis_mips64r6.lua | 17 | ||||
-rw-r--r-- | src/jit/dis_mips64r6el.lua | 17 | ||||
-rw-r--r-- | src/jit/dis_mipsel.lua | 15 | ||||
-rw-r--r-- | src/jit/dis_ppc.lua | 18 | ||||
-rw-r--r-- | src/jit/dis_x64.lua | 15 | ||||
-rw-r--r-- | src/jit/dis_x86.lua | 297 | ||||
-rw-r--r-- | src/jit/dump.lua | 54 | ||||
-rw-r--r-- | src/jit/p.lua | 311 | ||||
-rw-r--r-- | src/jit/v.lua | 17 | ||||
-rw-r--r-- | src/jit/zone.lua | 45 |
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. |
43 | local jit = require("jit") | 43 | local jit = require("jit") |
44 | assert(jit.version_num == 20005, "LuaJIT core/library version mismatch") | 44 | assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") |
45 | local jutil = require("jit.util") | 45 | local jutil = require("jit.util") |
46 | local vmdef = require("jit.vmdef") | 46 | local vmdef = require("jit.vmdef") |
47 | local bit = require("bit") | 47 | local bit = require("bit") |
@@ -179,13 +179,12 @@ local function bcliston(outfile) | |||
179 | end | 179 | end |
180 | 180 | ||
181 | -- Public module functions. | 181 | -- Public module functions. |
182 | module(...) | 182 | return { |
183 | 183 | line = bcline, | |
184 | line = bcline | 184 | dump = bcdump, |
185 | dump = bcdump | 185 | targets = bctargets, |
186 | targets = bctargets | 186 | on = bcliston, |
187 | 187 | off = bclistoff, | |
188 | on = bcliston | 188 | start = bcliston -- For -j command line option. |
189 | off = bclistoff | 189 | } |
190 | start = 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 | ||
13 | local jit = require("jit") | 13 | local jit = require("jit") |
14 | assert(jit.version_num == 20005, "LuaJIT core/library version mismatch") | 14 | assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") |
15 | local bit = require("bit") | 15 | local bit = require("bit") |
16 | 16 | ||
17 | -- Symbol name prefix for LuaJIT bytecode. | 17 | -- Symbol name prefix for LuaJIT bytecode. |
18 | local LJBC_PREFIX = "luaJIT_BC_" | 18 | local LJBC_PREFIX = "luaJIT_BC_" |
19 | 19 | ||
20 | local type, assert = type, assert | ||
21 | local format = string.format | ||
22 | local tremove, tconcat = table.remove, table.concat | ||
23 | |||
20 | ------------------------------------------------------------------------------ | 24 | ------------------------------------------------------------------------------ |
21 | 25 | ||
22 | local function usage() | 26 | local function usage() |
@@ -63,8 +67,18 @@ local map_type = { | |||
63 | } | 67 | } |
64 | 68 | ||
65 | local map_arch = { | 69 | local 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 | ||
70 | local map_os = { | 84 | local map_os = { |
@@ -73,33 +87,33 @@ local map_os = { | |||
73 | } | 87 | } |
74 | 88 | ||
75 | local function checkarg(str, map, err) | 89 | local 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 |
79 | end | 93 | end |
80 | 94 | ||
81 | local function detecttype(str) | 95 | local 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" |
84 | end | 98 | end |
85 | 99 | ||
86 | local function checkmodname(str) | 100 | local 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("[%.%-]", "_") |
89 | end | 103 | end |
90 | 104 | ||
91 | local function detectmodname(str) | 105 | local 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("[%.%-]", "_") |
103 | end | 117 | end |
104 | 118 | ||
105 | ------------------------------------------------------------------------------ | 119 | ------------------------------------------------------------------------------ |
@@ -118,19 +132,19 @@ end | |||
118 | local function bcsave_c(ctx, output, s) | 132 | local 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 |
123 | extern "C" | 137 | extern "C" |
124 | #endif | 138 | #endif |
125 | #ifdef _WIN32 | 139 | #ifdef _WIN32 |
126 | __declspec(dllexport) | 140 | __declspec(dllexport) |
127 | #endif | 141 | #endif |
128 | const char %s%s[] = { | 142 | const 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 |
133 | static const char %s%s[] = { | 147 | static 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") |
148 | end | 162 | end |
149 | 163 | ||
150 | local function bcsave_elfobj(ctx, output, s, ffi) | 164 | local 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; |
478 | typedef struct { | 482 | typedef 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. |
656 | module(...) | 662 | return { |
657 | 663 | start = docmd -- Process -b command line option. | |
658 | start = 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) | |||
658 | end | 658 | end |
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). |
661 | local function create_(code, addr, out) | 661 | local 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) | |||
670 | end | 670 | end |
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. |
673 | local function disass_(code, addr, out) | 673 | local function disass(code, addr, out) |
674 | create_(code, addr, out):disass() | 674 | create(code, addr, out):disass() |
675 | end | 675 | end |
676 | 676 | ||
677 | -- Return register name for RID. | 677 | -- Return register name for RID. |
678 | local function regname_(r) | 678 | local 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) |
681 | end | 681 | end |
682 | 682 | ||
683 | -- Public module functions. | 683 | -- Public module functions. |
684 | module(...) | 684 | return { |
685 | 685 | create = create, | |
686 | create = create_ | 686 | disass = disass, |
687 | disass = disass_ | 687 | regname = regname |
688 | regname = 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 | |||
16 | local type = type | ||
17 | local sub, byte, format = string.sub, string.byte, string.format | ||
18 | local match, gmatch, gsub = string.match, string.gmatch, string.gsub | ||
19 | local concat = table.concat | ||
20 | local bit = require("bit") | ||
21 | local band, bor, bxor, tohex = bit.band, bit.bor, bit.bxor, bit.tohex | ||
22 | local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift | ||
23 | local ror = bit.ror | ||
24 | |||
25 | ------------------------------------------------------------------------------ | ||
26 | -- Opcode maps | ||
27 | ------------------------------------------------------------------------------ | ||
28 | |||
29 | local map_adr = { -- PC-relative addressing. | ||
30 | shift = 31, mask = 1, | ||
31 | [0] = "adrDBx", "adrpDBx" | ||
32 | } | ||
33 | |||
34 | local map_addsubi = { -- Add/subtract immediate. | ||
35 | shift = 29, mask = 3, | ||
36 | [0] = "add|movDNIg", "adds|cmnD0NIg", "subDNIg", "subs|cmpD0NIg", | ||
37 | } | ||
38 | |||
39 | local 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 | |||
55 | local 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 | |||
70 | local 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 | |||
92 | local 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 | |||
103 | local 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 | |||
157 | local 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 | |||
207 | local map_addsubsh = { -- Add/subtract, shifted register. | ||
208 | shift = 22, mask = 3, | ||
209 | [0] = map_assh, map_assh, map_assh | ||
210 | } | ||
211 | |||
212 | local 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 | |||
220 | local 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 | |||
228 | local 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 | |||
243 | local 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 | |||
258 | local 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 | |||
273 | local 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 | |||
282 | local 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 | |||
306 | local 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 | |||
328 | local 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 | |||
340 | local 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 | |||
380 | local 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 | |||
445 | local 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 | |||
479 | local 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 | |||
525 | local 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 | |||
672 | local 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 | |||
712 | local 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 | |||
720 | local map_regs = { x = {}, w = {}, d = {}, s = {} } | ||
721 | |||
722 | for 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 | ||
727 | end | ||
728 | map_regs.x[31] = "sp" | ||
729 | map_regs.w[31] = "wsp" | ||
730 | map_regs.d[31] = "d31" | ||
731 | map_regs.s[31] = "s31" | ||
732 | |||
733 | local map_cond = { | ||
734 | [0] = "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", | ||
735 | "hi", "ls", "ge", "lt", "gt", "le", "al", | ||
736 | } | ||
737 | |||
738 | local map_shift = { [0] = "lsl", "lsr", "asr", } | ||
739 | |||
740 | local 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. | ||
747 | local 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 | ||
764 | end | ||
765 | |||
766 | -- Fallback for unknown opcodes. | ||
767 | local function unknown(ctx) | ||
768 | return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) | ||
769 | end | ||
770 | |||
771 | local function match_reg(p, pat, regnum) | ||
772 | return map_regs[match(pat, p.."%w-([xwds])")][regnum] | ||
773 | end | ||
774 | |||
775 | local function fmt_hex32(x) | ||
776 | if x < 0 then | ||
777 | return tohex(x) | ||
778 | else | ||
779 | return format("%x", x) | ||
780 | end | ||
781 | end | ||
782 | |||
783 | local imm13_rep = { 0x55555555, 0x11111111, 0x01010101, 0x00010001, 0x00000001 } | ||
784 | |||
785 | local 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 | ||
820 | end | ||
821 | |||
822 | local 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 | ||
834 | end | ||
835 | |||
836 | local 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 | ||
841 | end | ||
842 | |||
843 | local 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 | ||
856 | end | ||
857 | |||
858 | -- Disassemble a single instruction. | ||
859 | local 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) | ||
1174 | end | ||
1175 | |||
1176 | ------------------------------------------------------------------------------ | ||
1177 | |||
1178 | -- Disassemble a block of code. | ||
1179 | local 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 | ||
1185 | end | ||
1186 | |||
1187 | -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). | ||
1188 | local 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 | ||
1197 | end | ||
1198 | |||
1199 | -- Simple API: disassemble code (a string) at address and output via out. | ||
1200 | local function disass(code, addr, out) | ||
1201 | create(code, addr, out):disass() | ||
1202 | end | ||
1203 | |||
1204 | -- Return register name for RID. | ||
1205 | local function regname(r) | ||
1206 | if r < 32 then return map_regs.x[r] end | ||
1207 | return map_regs.d[r-32] | ||
1208 | end | ||
1209 | |||
1210 | -- Public module functions. | ||
1211 | return { | ||
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 | |||
11 | return 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 | |||
19 | local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift | 19 | local 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 | ||
25 | local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", } | ||
26 | local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", } | 25 | local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", } |
27 | local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", } | 26 | local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", } |
28 | 27 | ||
28 | local 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 | |||
48 | local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", } | ||
49 | |||
29 | local map_special = { | 50 | local 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 | ||
48 | local map_special2 = { | 71 | local map_special2 = { |
@@ -60,11 +83,17 @@ local map_bshfl = { | |||
60 | [24] = "sehDT", | 83 | [24] = "sehDT", |
61 | } | 84 | } |
62 | 85 | ||
86 | local map_dbshfl = { | ||
87 | shift = 6, mask = 31, | ||
88 | [2] = "dsbhDT", | ||
89 | [5] = "dshdDT", | ||
90 | } | ||
91 | |||
63 | local map_special3 = { | 92 | local 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 | ||
70 | local map_regimm = { | 99 | local map_regimm = { |
@@ -79,22 +108,6 @@ local map_regimm = { | |||
79 | false, false, false, "synciSO", | 108 | false, false, false, "synciSO", |
80 | } | 109 | } |
81 | 110 | ||
82 | local 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 | |||
98 | local map_cop1s = { | 111 | local 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 | ||
179 | local map_cop1 = { | 192 | local 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 | |||
245 | local map_mul_r6 = { shift = 6, mask = 3, [2] = "mulDST", [3] = "muhDST" } | ||
246 | local map_mulu_r6 = { shift = 6, mask = 3, [2] = "muluDST", [3] = "muhuDST" } | ||
247 | local map_div_r6 = { shift = 6, mask = 3, [2] = "divDST", [3] = "modDST" } | ||
248 | local map_divu_r6 = { shift = 6, mask = 3, [2] = "divuDST", [3] = "moduDST" } | ||
249 | local map_dmul_r6 = { shift = 6, mask = 3, [2] = "dmulDST", [3] = "dmuhDST" } | ||
250 | local map_dmulu_r6 = { shift = 6, mask = 3, [2] = "dmuluDST", [3] = "dmuhuDST" } | ||
251 | local map_ddiv_r6 = { shift = 6, mask = 3, [2] = "ddivDST", [3] = "dmodDST" } | ||
252 | local map_ddivu_r6 = { shift = 6, mask = 3, [2] = "ddivuDST", [3] = "dmoduDST" } | ||
253 | |||
254 | local 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 | |||
275 | local 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 | |||
287 | local 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 | |||
298 | local 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 | |||
305 | local 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 | |||
312 | local 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 | |||
320 | local 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 | |||
334 | local 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 | |||
348 | local 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 | |||
361 | local 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 | |||
374 | local 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 | |||
384 | local 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 | ||
387 | end | ||
388 | |||
389 | local map_pop06_r6 = { | ||
390 | maprs = maprs_popTS, [0] = "blezSB", "blezalcTB", "bgezalcTB", "bgeucSTB" | ||
391 | } | ||
392 | local map_pop07_r6 = { | ||
393 | maprs = maprs_popTS, [0] = "bgtzSB", "bgtzalcTB", "bltzalcTB", "bltucSTB" | ||
394 | } | ||
395 | local map_pop26_r6 = { | ||
396 | maprs = maprs_popTS, "blezcTB", "bgezcTB", "bgecSTB" | ||
397 | } | ||
398 | local map_pop27_r6 = { | ||
399 | maprs = maprs_popTS, "bgtzcTB", "bltzcTB", "bltcSTB" | ||
400 | } | ||
401 | |||
402 | local function maprs_popS(rs, rt) | ||
403 | if rs == 0 then return 0 else return 1 end | ||
404 | end | ||
405 | |||
406 | local map_pop66_r6 = { | ||
407 | maprs = maprs_popS, [0] = "jicTI", "beqzcSb" | ||
408 | } | ||
409 | local map_pop76_r6 = { | ||
410 | maprs = maprs_popS, [0] = "jialcTI", "bnezcSb" | ||
411 | } | ||
412 | |||
413 | local function maprs_popST(rs, rt) | ||
414 | if rs >= rt then return 0 elseif rs == 0 then return 1 else return 2 end | ||
415 | end | ||
416 | |||
417 | local map_pop10_r6 = { | ||
418 | maprs = maprs_popST, [0] = "bovcSTB", "beqzalcTB", "beqcSTB" | ||
419 | } | ||
420 | local map_pop30_r6 = { | ||
421 | maprs = maprs_popST, [0] = "bnvcSTB", "bnezalcTB", "bnecSTB" | ||
422 | } | ||
423 | |||
424 | local 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) | |||
384 | end | 624 | end |
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). |
387 | local function create_(code, addr, out) | 627 | local 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 | ||
638 | end | ||
639 | |||
640 | local function create_el(code, addr, out) | ||
641 | local ctx = create(code, addr, out) | ||
642 | ctx.get = get_le | ||
643 | return ctx | ||
644 | end | ||
645 | |||
646 | local 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 |
397 | end | 650 | end |
398 | 651 | ||
399 | local function create_el_(code, addr, out) | 652 | local 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 |
403 | end | 657 | end |
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. |
406 | local function disass_(code, addr, out) | 660 | local function disass(code, addr, out) |
407 | create_(code, addr, out):disass() | 661 | create(code, addr, out):disass() |
662 | end | ||
663 | |||
664 | local function disass_el(code, addr, out) | ||
665 | create_el(code, addr, out):disass() | ||
408 | end | 666 | end |
409 | 667 | ||
410 | local function disass_el_(code, addr, out) | 668 | local function disass_r6(code, addr, out) |
411 | create_el_(code, addr, out):disass() | 669 | create_r6(code, addr, out):disass() |
670 | end | ||
671 | |||
672 | local function disass_r6_el(code, addr, out) | ||
673 | create_r6_el(code, addr, out):disass() | ||
412 | end | 674 | end |
413 | 675 | ||
414 | -- Return register name for RID. | 676 | -- Return register name for RID. |
415 | local function regname_(r) | 677 | local 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) |
418 | end | 680 | end |
419 | 681 | ||
420 | -- Public module functions. | 682 | -- Public module functions. |
421 | module(...) | 683 | return { |
422 | 684 | create = create, | |
423 | create = create_ | 685 | create_el = create_el, |
424 | create_el = create_el_ | 686 | create_r6 = create_r6, |
425 | disass = disass_ | 687 | create_r6_el = create_r6_el, |
426 | disass_el = disass_el_ | 688 | disass = disass, |
427 | regname = 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 | |||
11 | local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips") | ||
12 | return { | ||
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 | |||
11 | local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips") | ||
12 | return { | ||
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 | |||
11 | local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips") | ||
12 | return { | ||
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 | |||
11 | local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips") | ||
12 | return { | ||
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 | ||
11 | local require = require | 11 | local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips") |
12 | 12 | return { | |
13 | module(...) | 13 | create = dis_mips.create_el, |
14 | 14 | disass = dis_mips.disass_el, | |
15 | local dis_mips = require(_PACKAGE.."dis_mips") | 15 | regname = dis_mips.regname |
16 | 16 | } | |
17 | create = dis_mips.create_el | ||
18 | disass = dis_mips.disass_el | ||
19 | regname = 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) | |||
560 | end | 560 | end |
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). |
563 | local function create_(code, addr, out) | 563 | local 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) | |||
572 | end | 572 | end |
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. |
575 | local function disass_(code, addr, out) | 575 | local function disass(code, addr, out) |
576 | create_(code, addr, out):disass() | 576 | create(code, addr, out):disass() |
577 | end | 577 | end |
578 | 578 | ||
579 | -- Return register name for RID. | 579 | -- Return register name for RID. |
580 | local function regname_(r) | 580 | local 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) |
583 | end | 583 | end |
584 | 584 | ||
585 | -- Public module functions. | 585 | -- Public module functions. |
586 | module(...) | 586 | return { |
587 | 587 | create = create, | |
588 | create = create_ | 588 | disass = disass, |
589 | disass = disass_ | 589 | regname = regname |
590 | regname = 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 | ||
11 | local require = require | 11 | local dis_x86 = require((string.match(..., ".*%.") or "").."dis_x86") |
12 | 12 | return { | |
13 | module(...) | 13 | create = dis_x86.create64, |
14 | 14 | disass = dis_x86.disass64, | |
15 | local dis_x86 = require(_PACKAGE.."dis_x86") | 15 | regname = dis_x86.regname64 |
16 | 16 | } | |
17 | create = dis_x86.create64 | ||
18 | disass = dis_x86.disass64 | ||
19 | regname = 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 | ||
27 | local type = type | 26 | local type = type |
28 | local sub, byte, format = string.sub, string.byte, string.format | 27 | local sub, byte, format = string.sub, string.byte, string.format |
29 | local match, gmatch, gsub = string.match, string.gmatch, string.gsub | 28 | local match, gmatch, gsub = string.match, string.gmatch, string.gsub |
30 | local lower, rep = string.lower, string.rep | 29 | local lower, rep = string.lower, string.rep |
30 | local bit = require("bit") | ||
31 | local 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. |
33 | local map_opc1_32 = { | 34 | local 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$", |
164 | nil,nil, | 165 | nil,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 | } |
205 | assert(map_opc2[255] == "ud") | 206 | assert(map_opc2[255] == "ud") |
206 | 207 | ||
@@ -208,49 +209,91 @@ assert(map_opc2[255] == "ud") | |||
208 | local map_opc3 = { | 209 | local 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", |
214 | nil,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", |
218 | nil,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", |
224 | nil,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, |
233 | nil,"||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 |
242 | nil,nil,nil,nil, | 275 | nil,nil,nil,nil, |
243 | "||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru", | 276 | "||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru", |
244 | nil,nil,nil,nil,nil,nil,nil,nil, | 277 | "||insertf128XrvlXmu","||extractf128XlXmYru",nil,nil, |
278 | nil,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 | } |
358 | local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" } | 403 | local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" } |
359 | 404 | ||
360 | -- Maps for size names. | 405 | -- Maps for size names. |
361 | local map_sz2n = { | 406 | local 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 | } |
364 | local map_sz2prefix = { | 409 | local 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 |
410 | end | 459 | end |
@@ -413,7 +462,7 @@ end | |||
413 | local function clearprefixes(ctx) | 462 | local 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 |
417 | end | 466 | end |
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. |
451 | local function putpat(ctx, name, pat) | 500 | local 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) | |||
782 | end | 899 | end |
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). |
785 | local function create_(code, addr, out) | 902 | local 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 |
797 | end | 914 | end |
798 | 915 | ||
799 | local function create64_(code, addr, out) | 916 | local 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) | |||
805 | end | 922 | end |
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. |
808 | local function disass_(code, addr, out) | 925 | local function disass(code, addr, out) |
809 | create_(code, addr, out):disass() | 926 | create(code, addr, out):disass() |
810 | end | 927 | end |
811 | 928 | ||
812 | local function disass64_(code, addr, out) | 929 | local function disass64(code, addr, out) |
813 | create64_(code, addr, out):disass() | 930 | create64(code, addr, out):disass() |
814 | end | 931 | end |
815 | 932 | ||
816 | -- Return register name for RID. | 933 | -- Return register name for RID. |
817 | local function regname_(r) | 934 | local 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] |
820 | end | 937 | end |
821 | 938 | ||
822 | local function regname64_(r) | 939 | local 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] |
825 | end | 942 | end |
826 | 943 | ||
827 | -- Public module functions. | 944 | -- Public module functions. |
828 | module(...) | 945 | return { |
829 | 946 | create = create, | |
830 | create = create_ | 947 | create64 = create64, |
831 | create64 = create64_ | 948 | disass = disass, |
832 | disass = disass_ | 949 | disass64 = disass64, |
833 | disass64 = disass64_ | 950 | regname = regname, |
834 | regname = regname_ | 951 | regname64 = regname64 |
835 | regname64 = 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. |
57 | local jit = require("jit") | 57 | local jit = require("jit") |
58 | assert(jit.version_num == 20005, "LuaJIT core/library version mismatch") | 58 | assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") |
59 | local jutil = require("jit.util") | 59 | local jutil = require("jit.util") |
60 | local vmdef = require("jit.vmdef") | 60 | local vmdef = require("jit.vmdef") |
61 | local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc | 61 | local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc |
@@ -63,7 +63,7 @@ local traceinfo, traceir, tracek = jutil.traceinfo, jutil.traceir, jutil.tracek | |||
63 | local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap | 63 | local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap |
64 | local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr | 64 | local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr |
65 | local bit = require("bit") | 65 | local bit = require("bit") |
66 | local band, shr = bit.band, bit.rshift | 66 | local band, shr, tohex = bit.band, bit.rshift, bit.tohex |
67 | local sub, gsub, format = string.sub, string.gsub, string.format | 67 | local sub, gsub, format = string.sub, string.gsub, string.format |
68 | local byte, rep = string.byte, string.rep | 68 | local byte, rep = string.byte, string.rep |
69 | local type, tostring = type, tostring | 69 | local type, tostring = type, tostring |
@@ -85,12 +85,13 @@ local nexitsym = 0 | |||
85 | local function fillsymtab_tr(tr, nexit) | 85 | local 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 | ||
285 | local function ctlsub(c) | 292 | local function ctlsub(c) |
@@ -303,15 +310,19 @@ local function fmtfunc(func, pc) | |||
303 | end | 310 | end |
304 | end | 311 | end |
305 | 312 | ||
306 | local function formatk(tr, idx) | 313 | local 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 | ||
611 | local gpr64 = jit.arch:match("64") | ||
612 | local fprmips32 = jit.arch == "mips" or jit.arch == "mipsel" | ||
613 | |||
598 | -- Dump taken trace exits. | 614 | -- Dump taken trace exits. |
599 | local function dump_texit(tr, ex, ngpr, nfpr, ...) | 615 | local 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) | |||
692 | end | 708 | end |
693 | 709 | ||
694 | -- Public module functions. | 710 | -- Public module functions. |
695 | module(...) | 711 | return { |
696 | 712 | on = dumpon, | |
697 | on = dumpon | 713 | off = dumpoff, |
698 | off = dumpoff | 714 | start = dumpon -- For -j command line option. |
699 | start = 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. | ||
43 | local jit = require("jit") | ||
44 | assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") | ||
45 | local profile = require("jit.profile") | ||
46 | local vmdef = require("jit.vmdef") | ||
47 | local math = math | ||
48 | local pairs, ipairs, tonumber, floor = pairs, ipairs, tonumber, math.floor | ||
49 | local sort, format = table.sort, string.format | ||
50 | local stdout = io.stdout | ||
51 | local zone -- Load jit.zone module on demand. | ||
52 | |||
53 | -- Output file handle. | ||
54 | local out | ||
55 | |||
56 | ------------------------------------------------------------------------------ | ||
57 | |||
58 | local prof_ud | ||
59 | local prof_states, prof_split, prof_min, prof_raw, prof_fmt, prof_depth | ||
60 | local prof_ann, prof_count1, prof_count2, prof_samples | ||
61 | |||
62 | local 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. | ||
71 | local 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 | ||
116 | end | ||
117 | |||
118 | ------------------------------------------------------------------------------ | ||
119 | |||
120 | -- Show top N list. | ||
121 | local 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 | ||
148 | end | ||
149 | |||
150 | -- Annotate source code | ||
151 | local 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 | ||
220 | end | ||
221 | |||
222 | ------------------------------------------------------------------------------ | ||
223 | |||
224 | -- Finish profiling and dump result. | ||
225 | local 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 | ||
242 | end | ||
243 | |||
244 | -- Start profiling. | ||
245 | local 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 | ||
292 | end | ||
293 | |||
294 | ------------------------------------------------------------------------------ | ||
295 | |||
296 | local 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") | ||
304 | end | ||
305 | |||
306 | -- Public module functions. | ||
307 | return { | ||
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. |
61 | local jit = require("jit") | 61 | local jit = require("jit") |
62 | assert(jit.version_num == 20005, "LuaJIT core/library version mismatch") | 62 | assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") |
63 | local jutil = require("jit.util") | 63 | local jutil = require("jit.util") |
64 | local vmdef = require("jit.vmdef") | 64 | local vmdef = require("jit.vmdef") |
65 | local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo | 65 | local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo |
@@ -99,7 +99,7 @@ end | |||
99 | local function dump_trace(what, tr, func, pc, otr, oex) | 99 | local 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) | |||
159 | end | 162 | end |
160 | 163 | ||
161 | -- Public module functions. | 164 | -- Public module functions. |
162 | module(...) | 165 | return { |
163 | 166 | on = dumpon, | |
164 | on = dumpon | 167 | off = dumpoff, |
165 | off = dumpoff | 168 | start = dumpon -- For -j command line option. |
166 | start = 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 | |||
27 | local remove = table.remove | ||
28 | |||
29 | return 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 | |||