1 local _type
, _ipairs
, _pairs
, _tonum
, _tostr
, _assert
, _error
= type, ipairs
, pairs
, tonumber, tostring, assert, error
2 local _loadstr
= loadstring
3 local _match
, _gmatch
, _sub
, _lower
, _upper
= string.match
, string.gmatch
, string.sub
, string.lower
, string.upper
4 local _fmt
, _gsub
= string.format, string.gsub
5 local _sort
= table.sort
7 local _ceil
, _pow
= math
.ceil, math
.pow
11 local _trim
= function(s
) return _match(s
, "^%s*(.-)%s*$") or s
end
12 function _dump(x
, unquote
)
13 if not unquote
and _type(x
) == "string" then
15 elseif _type(x
) ~= "table" then
20 for i
= 1,n
do r
= r
.. (i
> 1 and ", " or "") .. _dump(x
[i
], unquote
) end
21 local pending
= n
> 0 and ";"
22 for k
,v
in _pairs(x
) do
23 if _type(k
) == "number" and k
== _ceil(k
) and k
>= 1 and k
<=n
then
25 elseif _type(k
) == "string" and _match(k
,"^%a[%w_]*$") then
26 if pending
then r
= r
.. pending
; pending
= nil end
27 r
= r
.. k
.. " = " .. _dump(v
, unquote
)
30 if pending
then r
= r
.. pending
; pending
= nil end
31 r
= r
.. "[" .. _dump(k
, unquote
) .. "] = " .. _dump(v
, unquote
)
40 local function readfile(n
)
41 local f
= _open(n
) or _open("tools/"..n
)
42 local ctnt
= f
:read("*a")
49 local testname
, outname
= ...
50 if (testname
== nil or testname
== "") then
51 testname
= "..\\src-lib\\x86\\src\\_x86_inslist.ltxt"
53 if outname
== nil or outname
== "" then
54 outname
= _match(testname
, "^(.-)%.[^.\\/]*$") .. ".dat"
57 local emblua
= _loadstr(readfile("emblua.lua"))
58 local inslist
= emblua(testname
,{type="string"})
59 --local inslist = readfile("..\\evm\\x86\\src\\_x86_inslist.txt")
60 -----------------------------------------------------------------
62 -----------------------------------------------------------------
64 local _cacheMatchWords
= {}
65 local function matchWords(w
, n
)
66 local v
= _cacheMatchWords
[n
]
69 for i
= 1, n
do v
= v
.. "(%w+)%s*" end
71 _cacheMatchWords
[n
] = v
75 local _cacheMatchID
= {}
76 local function matchID(w
, n
)
77 local v
= _cacheMatchID
[n
]
79 v
= _gsub(n
, "$ID", "%%a[%%w_]*")
80 v
= _gsub(v
, "$NUM", "%%d+")
81 v
= _gsub(v
, "$OP", "[^,]-")
82 v
= _gsub(v
, " ", "%%s*")
83 v
= "^%s*" .. v
.. "%s*$"
90 -----------------------------------------------------------------
92 -----------------------------------------------------------------
95 -----------------------------------------------------------------
97 -----------------------------------------------------------------
99 local cache
, cachecount
= {}, {}
100 local function unify(section
, t
, pred
)
101 local subcache
= cache
[section
]
102 if not subcache
then subcache
= {}; cache
[section
] = subcache
end
103 local sig
= (pred
or _dump
)(t
, true)
104 local data
= subcache
[sig
]
106 local id
= (cachecount
[section
] or 0) + 1
107 data
= t
; data
.id
= id
; data
.sig
= sig
; subcache
[sig
] = data
; cachecount
[section
] = id
end
110 local function _opassert(cond
, op
, msg
, ...)
111 if cond
then return end
112 assert(false, _fmt("op %s: "..msg
, op
.name
, ...))
114 --------------------------------------
121 sse2
= {"sse", "mmxext"},
144 x64
= {"sse2","cmov"},
146 avx512f
= {"avx2","f16c","fma3"}}
147 local function _simplifyISA(t
, v
)
148 --if not _isetset[v] then return end
149 for k
,vv
in _ipairs(_isetset
[v
]) do
155 local function _parseISA(op
, data
)
156 _opassert(not op
.isa
, op
, "double ISA declaration")
158 for i
in _gmatch(data
,"[%w_]+") do
159 _opassert(_isetset
[i
], op
, "invalid isa %s", i
)
160 if i
== "x64only" then i
= "x64" end
162 _simplifyISA(iset
, i
)
165 for k
,v
in _pairs(iset
) do
169 for k
,v
in _pairs(iset
) do if not dep
[k
] then iset2
[#iset2
+ 1] = k
end end
171 op
.isa
= unify("isa", iset2
)
172 if iset
.x64
then op
.isa
.x64
= true end
173 if iset
.x32only
then op
.isa
.x32only
= true end
175 --------------------------------------
176 local function list2set( list
)
178 for k
,v
in _ipairs(list
) do set
[v
]= k
end
181 local _typeset
= list2set
{"GR8","GR16","GR32","GR64","VR128","VR256","VR512","KR",
182 "i8","i16","i32","i64",
183 "i8*","i16*","i32*","i64*","i128*","i256*","i512*",
186 al
= "rax", ah
= "rax", ax
= "rax", eax
= "rax", rax
= "rax",
187 cl
= "rcx", ecx
= "rcx", rcx
= "rcx",
188 dx
= "rdx", edx
= "rdx", rdx
= "rdx",
189 ebx
= "rbx", rbx
= "rbx",
190 edi
= "rdi", rdi
= "rdi",
194 local function _parseOps(op
, data
)
195 _opassert(not op
.ops
, op
, "double operands declaration")
196 local varlist
, varset
= {}, {}
197 for p
in _gmatch(data
, "[^,]+") do
200 local tp
, fixedreg
, vname
, mode
= matchID(p
, "($ID%*?) { ($ID) } ($ID)/($ID)" )
202 tp
,vname
,mode
= matchID(p
, "($ID%*?) ($ID)/($ID)")
205 fixedreg
= fixedreg
and _lower(fixedreg
)
206 _opassert(tp
and vname
, op
, "invalid operand \"%s\"", p
)
207 _opassert(_typeset
[tp
], op
, "invalid type %s", tp
)
208 _opassert(not varset
[vname
], op
, "double declaration of operand %s", vname
)
209 _opassert(mode
== "i" or mode
== "o" or mode
== "io",
210 op
, "operand %s uses invalid mode %s", vname
, mode
)
212 if (tp
== "GR8" or tp
== "GR16") and mode
== "o" then mode
= "io" end
215 _opassert(_fixedregs
[fixedreg
], op
, "unsupported fixed reg %s", fixedreg
)
216 fixedreg
= _fixedregs
[fixedreg
]
217 for i
,v
in _ipairs(varlist
) do
218 if v
.fixed
== fixedreg
then
219 local mi
= _match(v
.mode
, "i") or _match(mode
, "i")
220 local mo
= _match(v
.mode
, "o") or _match(mode
, "o")
221 v
.mode
= (mi
and "i" or "")..(mo
and "o" or "")
228 varlist
[ #varlist
+1 ]= {name
=vname
,type=tp
,fixed
=fixedreg
,mode
=mode
}
232 op
.operands
= varlist
234 --------------------------------------
236 rflags
= {flagin
= true}, rflag_c
= {flagin
= true}, rflag_o
= {flagin
= true},
237 rflag_s
= {flagin
= true}, rflag_z
= {flagin
= true}, rflag_p
= {flagin
= true},
238 wflags
= {flagout
= true},
239 wflag_c
= {flagin
= true, flagout
= true}, wflag_o
= {flagin
= true, flagout
= true},
240 subflags
= {flagin
= true},
241 wmem
= {}, rmem
= {}, rwmem
= {}, usemem
= {}, amem
= {}, umem
= {},
242 cf_jmp
= {}, cf_call
= {}, cf_ret
= {}, cf_fallthru
= {},
246 local function _parseFlags(op
, data
)
247 _opassert(not op
.flags
, op
, "double flags declaration")
249 for i
in _gmatch(data
,"[%w_]+") do
250 _opassert(_flagset
[i
], op
, "invalid flag %s", i
)
253 if fset
.rwmem
then fset
.wmem
= true; fset
.rmem
= true; fset
.rwmem
= false end
255 for k
,v
in _pairs(fset
) do fset2
[#fset2
+ 1] = k
end
257 op
.flags
= unify("flags", fset2
)
259 --------------------------------------
264 ["66f2"] = {}, -- only for crc32_16
266 local function _parsePref(op
, data
)
267 _opassert(not op
.pref
, op
, "double prefix declaration")
268 if data
== "" then op
.pref
= ""; return end
269 local p
= _match(data
, "^([%w_]+)$")
270 _opassert(p
and _prefset
[p
], op
, "invalid prefix %s", _tostr(p
))
273 --------------------------------------
274 local _extopcodeset
= {
279 local function _parseExtOpcode(op
, data
)
280 _opassert(not op
.extopcode
, op
, "double extended opcode declaration")
281 if data
== "" then op
.extopcode
= ""; return end
282 local p
= _match(data
, "^([%w_]+)$")
283 _opassert(p
and _extopcodeset
[p
], op
, "invalid extended opcode %s", _tostr(p
))
286 --------------------------------------
287 local function _parseCoding(op
, data
)
288 _opassert(not op
.code
, op
, "double coding declaration")
290 for c
in _gmatch(data
, "%S+") do
292 _gsub(c
, "[%(%)]", function (m
) cnt
[m
] = (cnt
[m
] or 0) + 1 end)
293 _opassert(cnt
["("] == cnt
[")"], op
, "unbalanced parenthesis in coding")
295 c
= _gsub(c
, "!par%((%w+)%)", function (p
)
296 _opassert(not op
.parm
, op
, "double !par declaration")
297 _opassert(_tonum(p
), op
, "invalid !par value")
301 c
= _gsub(c
, "!sub%((%w+)%)", function (p
)
302 _opassert(not op
.sub
, op
, "double !sub declaration")
303 _opassert(_tonum(p
), op
, "invalid !sub value")
307 c
= _gsub(c
, "!parsub%((%w+)%)", function (p
)
308 _opassert(not op
.par
, op
, "double !par declaration")
309 _opassert(not op
.sub
, op
, "double !sub declaration")
310 _opassert(_tonum(p
), op
, "invalid !parsub value")
312 op
.sub
= op
.parm
% 32
313 op
.parm
= op
.parm
- op
.sub
316 result
[ #result
+1 ]= c
320 --------------------------------------
321 local function _parseLEAREX(op
, data
)
322 _opassert(not op
.rex
, op
, "double rex/vex declaration in op "..op
.name
)
323 local w
, reg
, base
, index
= matchWords(data
,4)
324 _opassert(reg
, op
, "invalid rexlea parameters")
325 _opassert(w
== "0" or w
== "1", op
, "invalid rex w field")
326 op
.rex
= {mode
= "lea", reg
= reg
, rmb
= base
, rmi
= index
, r64
= w
}
328 local function _parseREX(op
, data
)
329 _opassert(not op
.rex
, op
, "double rex/vex declaration in op "..op
.name
)
330 local rm
, w
, rmr
, rmm
= matchWords(data
,4)
331 _opassert(rm
, op
, "invalid rex parameters")
332 _opassert(rm
== "rr" or rm
== "rm", op
, "invalid rex rm field")
333 _opassert(w
== "0" or w
== "1", op
, "invalid rex w field")
334 op
.rex
= {mode
= rm
, reg
= rmr
, rm
= rmm
, r64
= w
}
336 local function _parseVEX(op
, data
)
337 _opassert(not op
.rex
, op
, "double rex/vex declaration")
338 local rm
, w
, src1
, rmr
, rmm
, l
= matchWords(data
,6)
339 _opassert(rm
, op
, "invalid rex parameters")
340 _opassert(rm
== "rr" or rm
== "rm", op
, "invalid vex rm field")
341 _opassert(w
== "0" or w
== "1", op
, "invalid vex w field")
342 _opassert(l
== "0" or l
== "1", op
, "invalid vex l field")
343 op
.rex
= {vex
= true, mode
= rm
, reg
= rmr
, rm
= rmm
, r64
= w
, l
= l
, src1
= src1
}
345 local function _parseEVEX(op
, data
)
346 _opassert(not op
.rex
, op
, "double rex/vex declaration in op "..op
.name
)
347 local rm
, w
, src1
, rmr
, rmm
, l
, k
, z
, b
= matchWords(data
,9)
348 _opassert(rm
, op
, "invalid rex parameters")
349 _opassert(rm
== "rr" or rm
== "rm", op
, "invalid evex rm field")
350 _opassert(w
== "0" or w
== "1", op
, "invalid evex w field")
351 _opassert(l
== "0" or l
== "1" or l
== "2" or l
== "3", op
, "invalid evex l field")
352 _opassert(z
== "0" or z
== "1", op
, "invalid evex z field")
353 _opassert(b
== "0" or b
== "1", op
, "invalid evex b field")
354 op
.rex
= {evex
= true, mode
= rm
, reg
= rmr
, rm
= rmm
, r64
= w
, l
= l
, src1
= src1
,
357 local function _parseFold(op
, data
)
359 local function _parseCommute(op
, data
)
362 --------------------------------------
364 local function _getValidVarSet( op
)
366 local vars
={ parm
="i8", sub
="i8" }
367 for _
,v
in _ipairs(op
.operands
) do vars
[v
.name
]= v
.type end
371 local function _ptrtype(s
)
372 return s
and _sub(s
,-1,-1)=="*"
374 local function _immtype(s
)
375 return s
and _sub(s
,1,1)=="i" and not _ptrtype(s
)
377 local function _regtype(s
)
378 return s
and not _ptrtype(s
) and not _immtype(s
)
381 local function _checkOp( op
)
382 local vars
= _getValidVarSet(op
)
385 for _
,v
in _ipairs(op
.operands
) do
386 if _ptrtype(v
.type) then
387 _opassert(v
.mode
== "i", op
, "memory operands are input only")
388 _opassert(memops
== 0, op
, "only one memory operand allowed")
393 for _
,v
in _ipairs(op
.code
) do
394 for vv
in _gmatch(v
, "%$(%a%w*)") do
395 _opassert(vars
[vv
], op
, "invalid variable %s", vv
)
398 local p1
,p2
,p3
,p4
,p5
= matchID(v
,"!RRMLEA%( ($OP) , ($OP) , ($OP) , ($OP) , ($OP) %)")
400 _opassert(op
.rex
.mode
=="lea", op
, "RRM?-rex mode mismatch" )
401 _opassert(not op
.rex
.vex
and not op
.rex
.evex
, op
, "RRMLEA and vex don't mix" )
402 _opassert(_sub(p1
,1,1)=="$" and vars
[_sub(p1
,2)], op
, ": RRMLEA-reg error" )
403 _opassert(_sub(p1
,2)==op
.rex
.reg
, op
, "RRMLEA-rex reg mismatch" )
404 _opassert(_sub(p2
,1,1)=="$" and vars
[_sub(p2
,2)], op
, "RRMLEA-rm base error" )
405 _opassert(_sub(p2
,2)==op
.rex
.rmb
, op
, "RRMLEA-rex rm base mismatch" )
406 _opassert(_sub(p3
,1,1)=="$" and vars
[_sub(p3
,2)], op
, "RRMLEA-rm index error" )
407 _opassert(_sub(p3
,2)==op
.rex
.rmi
, op
, "RRMLEA-rex rm index mismatch" )
410 p1
,p2
,p3
= matchID(v
, "!RRMMVSIB([RM])%( ($OP) , ($OP) , ($OP) %)")
412 _opassert(op
.rex
.mode
=="rm", op
, "RRMMVSIB-rex mode mismatch" )
413 _opassert(op
.rex
.vex
or op
.rex
.evex
, op
, "RRMMVSIB requires vex" )
414 _opassert(_sub(p1
,1,1)=="$" and vars
[_sub(p1
,2)], op
, ": RRMMVSIB-reg error" )
415 _opassert(_sub(p1
,2)==op
.rex
.reg
, op
, "RRMMVSIB-rex reg mismatch" )
416 _opassert(_sub(p2
,1,1)=="$" and vars
[_sub(p2
,2)], op
, "RRMMVSIB-rm base error" )
417 _opassert(_sub(p2
,2)==op
.rex
.rm
, op
, "RRMMVSIB-rex rm base mismatch" )
418 _opassert(_sub(p3
,1,1)=="$" and vars
[_sub(p3
,2)], op
, "RRMMVSIB-vsib index error" )
421 x
,p1
,p2
= matchID(v
, "!RRM([RM])%( ($OP) , ($OP) %)")
423 local rm
= "r".._lower(x
)
424 _opassert(op
.rex
.mode
== rm
, op
, "RRM%s-rex mode mismatch", x
)
426 _opassert( op
.rex
.reg
==p1
, op
, "RRM%s-rex reg(#) mismatch", x
)
427 elseif p1
=="$parm" then
428 _opassert( op
.parm
>=0 and op
.parm
<8 and op
.rex
.reg
=="0", op
, "RRM%s-rex reg(parm) mismatch", x
)
429 elseif p1
=="$sub" then
430 local sub
= op
.sub
or 0
431 _opassert( sub
>=0 and sub
<8 and op
.rex
.reg
=="0", op
, "RRM%s-rex reg(parm) mismatch", x
)
433 _opassert(_sub(p1
,1,1)=="$" and vars
[_sub(p1
,2)], op
, "RRM%s-reg error", x
)
434 _opassert(_sub(p1
,2)==op
.rex
.reg
, op
, "RRM%s-rex reg mismatch", x
)
437 _opassert((op
.rex
.rm
or "0") == "0", op
, "RRM%s-rex rm mismatch", x
)
439 _opassert(_sub(p2
,1,1)=="$" and vars
[_sub(p2
,2)], op
, "RRM%s-rm error", x
)
440 _opassert(_sub(p2
,2)==op
.rex
.rm
, op
, "RRM%s-rex rm mismatch", x
)
444 _opassert( op
.rex
.reg
=="0" or _regtype(vars
[op
.rex
.reg
]), op
, "rex-reg error" )
445 if op
.rex
.mode
=="rr" then
446 _opassert( op
.rex
.rm
=="0" or _regtype(vars
[op
.rex
.rm
]), op
, "rex-rmr error" )
447 elseif op
.rex
.mode
=="rm" then
448 _opassert( op
.rex
.mode
=="rm" and _ptrtype(vars
[op
.rex
.rm
]), op
, "rex-rmm error" )
452 local function _createLayout(op
)
453 local layout
, renametab
, pnum
= {}, {}, nil
455 --print(op.name, dump(op.rex))
456 local function renameVar(v
)
457 local res
= renametab
[v
]
459 pnum
= (pnum
or 0) + 1
460 res
= {"p".._tostr(pnum
), pnum
}
465 local function add2layout(v
, defuse
)
466 if v
.fixed
then return end
467 local n
= renameVar(v
.name
)
468 if indices
[v
.name
] then return end
470 if _ptrtype(v
.type) then
472 elseif _immtype(v
.type) then
474 elseif v
.type == "BB" then
477 mode
, lp3
= "RegId", nil
478 if v
.type == "GR8" then lp3
= "GR8" end
479 --if v.type == "GR16" or v.type == "GR32" or v.type == "GR64" or v.type == "GR" then lp3 = "GR" end
480 --if v.type == "VR128" or v.type == "VR256" or v.type == "VR512" then lp3 = "VR" end
482 layout
[#layout
+ 1] = {mode
, defuse
, n
, lp3
};
483 indices
[v
.name
] = #layout
484 if v
.type == "i64" then
485 layout
[#layout
+ 1] = {"Imm", "use", n
, 32}
489 -- make sure, memory operands are the first parameter
490 -- this preferred order should simplify the code generator a bit
491 for _
,v
in _ipairs(op
.operands
) do
492 if _ptrtype(v
.type) then add2layout(v
, "use") end
494 local orderedlayout
= {}
495 if op
.rex
.rm
and not _tonum(op
.rex
.rm
) then orderedlayout
[#orderedlayout
+1] = op
.rex
.rm
end
496 if op
.rex
.reg
and not _tonum(op
.rex
.reg
) then orderedlayout
[#orderedlayout
+1] = op
.rex
.reg
end
497 if op
.rex
.src1
and not _tonum(op
.rex
.src1
) then orderedlayout
[#orderedlayout
+1] = op
.rex
.src1
end
498 if op
.rex
.msk
and not _tonum(op
.rex
.msk
) then orderedlayout
[#orderedlayout
+1] = op
.rex
.msk
end
499 local t
= {i
= "use", o
= "def", io
= "use/def"}
500 for _1
,v1
in _ipairs(orderedlayout
) do
501 for _
,v
in _ipairs(op
.operands
) do
503 add2layout(v
, t
[v
.mode
])
508 for _
,v
in _ipairs(op
.operands
) do
509 add2layout(v
, t
[v
.mode
])
511 for _
,v
in _ipairs(op
.operands
) do
513 local n
= renameVar(v
.name
)
516 op
.layout
= unify("layout", layout
)
517 op
.rename2layout
= renametab
520 local function _renameFromLayout(op
)
522 for i
,v
in _ipairs(op
.operands
) do
523 op
.orgnames
[i
] = v
.name
524 v
.name
= op
.rename2layout
[v
.name
][1]
526 for _
,v
in _ipairs
{"reg", "rm", "src1", "msk", "rmb", "rmi"} do
527 if op
.rex
[v
] and op
.rename2layout
[op
.rex
[v]]
then
528 op
.rex
[v
] = op
.rename2layout
[op
.rex
[v]]
[1]
531 for i
,v
in _ipairs(op
.code
) do
532 op
.code
[i
] = _gsub(v
, "%$(%a%w*)", function (vv
)
533 if op
.rename2layout
[vv
] then return "$"..op
.rename2layout
[vv
][1] end
537 op
.operands
= unify("operands", op
.operands
)
538 op
.orgnames
= unify("orgnames", op
.orgnames
)
539 op
.rex
= unify("rex", op
.rex
)
540 op
.code
= unify("code", op
.code
)
541 op
.rename2layout
= nil
543 local function _createImpRegs(op
)
545 local t
= {i
= "use", o
= "def", io
= "use/def"}
546 for _
,v
in _ipairs(op
.operands
) do
547 if not _ptrtype(v
.type) and not _immtype(v
.type) and not (v
.type == "BB") then
549 regs
[#regs
+ 1] = {v
.fixed
, t
[v
.mode
]}
554 local flagin
, flagout
= false, false
555 for _
,v
in _ipairs(op
.flags
) do
556 flagin
= flagin
or _flagset
[v
].flagin
557 flagout
= flagout
or _flagset
[v
].flagout
559 if flagin
or flagout
then
560 regs
[#regs
+ 1] = {"FLAGS", flagout
and (flagin
and "use/def" or "def") or "use"}
562 op
.impregs
= unify("impregs", regs
)
564 function _getPrefixSig(op
)
565 local r
, pending
= ""
568 if op
.pref
~= "" then r
= r
.. "-" .. op
.pref
end
569 if op
.extopcode
~= "" then r
= r
.. "-" .. op
.extopcode
end
571 if tonumber(op
.rex
.l
) > 0 then r
= r
.. (128 * _pow(2,tonumber(op
.rex
.l
))) .. "." end
572 if tonumber(op
.rex
.r64
) > 0 then r
= r
.. "W" end
573 if not tonumber(op
.rex
.reg
) then r
= r
.. "R".._gsub(op
.rex
.reg
,"p","") end
574 if not tonumber(op
.rex
.rm
) then
575 r
= r
.. (op
.rex
.mode
== "rr" and "B" or "M").._gsub(op
.rex
.rm
,"p","")
577 if not tonumber(op
.rex
.src1
) then r
= r
.. "S".._gsub(op
.rex
.src1
,"p","") end
579 if op
.pref
~= "" then r
= r
.. op
.pref
; pending
= "-" end
580 if op
.rex
.mode
== "lea" then
581 if pending
then r
= r
.. pending
; pending
= nil end;
583 if tonumber(op
.rex
.r64
) > 0 then r
= r
.. "W" end
584 if not tonumber(op
.rex
.reg
) then r
= r
.. "R".._gsub(op
.rex
.reg
,"p","") end
585 if not tonumber(op
.rex
.rmb
) then r
= r
.. "B".._gsub(op
.rex
.rmb
,"p","") end
586 if not tonumber(op
.rex
.rmi
) then r
= r
.. "I".._gsub(op
.rex
.rmi
,"p","") end
588 elseif tonumber(op
.rex
.r64
) or not tonumber(op
.rex
.reg
) or not tonumber(op
.rex
.rm
) then
589 if pending
then r
= r
.. pending
; pending
= nil end;
591 if tonumber(op
.rex
.r64
) > 0 then r
= r
.. "W" end
592 if not tonumber(op
.rex
.reg
) then r
= r
.. "R".._gsub(op
.rex
.reg
,"p","") end
593 if not tonumber(op
.rex
.rm
) then
594 r
= r
.. (op
.rex
.mode
== "rr" and "B" or "M").._gsub(op
.rex
.rm
,"p","")
598 if op
.extopcode
~= "" then
599 if pending
then r
= r
.. pending
; pending
= nil end;
600 r
= r
.. op
.extopcode
602 if r
== "" then r
= "none" end
606 function _getPrefixClass(op
)
607 local pcl
= {pref
= op
.pref
, rex
= op
.rex
, extopcode
= op
.extopcode
}
608 pcl
= unify("prefixclass", pcl
, _getPrefixSig
)
616 function _getOpClassSig(op
)
617 return op
.isa
.sig
.. "|" .. op
.layout
.sig
.. "|" .. op
.impregs
.sig
618 .. "|" .. op
.prefixclass
.sig
.. "|" .. op
.code
.sig
619 .. "|" .. _fmt("PAR%2X",op
.parm
or 0)
620 .. "|" .. op
.flags
.sig
622 function _getOpClass(op
)
623 local cl
= {isa
= op
.isa
, layout
= op
.layout
, impregs
= op
.impregs
,
624 prefixclass
= op
.prefixclass
, code
= op
.code
, parm
= op
.parm
, flags
= op
.flags
}
625 cl
= unify("opclass", cl
, _getOpClassSig
)
637 --------------------------------------
639 -- {isa avx512f; ops KR dst/o, KR src1/i, KR src/i;
640 -- pref ; %(VEXDS({"avx",256,"rr"},"S")); extopcode 0f; coding !parsub(0x45) !RRMR($dst,$src)}
641 --------------------------------------
648 extopcode
= _parseExtOpcode
,
649 coding
= _parseCoding
,
651 learex
= _parseLEAREX
,
652 rexlea
= _parseLEAREX
,
656 commute
= _parseCommute
,
659 local function parseLine(name
, defs
)
660 local op
= { name
= name
}
661 for part
,info
in _gmatch(defs
,"%s*(%w+)%s+([^;]*);?") do
662 info
= _match(info
, "^%s*(.-)%s*$")
663 _assert(_parsePart
[part
], "invalid option "..part
.." in opcode "..name
)
664 _parsePart
[part
](op
, info
)
666 if not op
.isa
then op
.isa
= unify("isa", {}) end
667 if not op
.operands
then op
.operands
= {} end
668 if not op
.flags
then op
.flags
= unify("flags", {}) end
669 if not op
.pref
then op
.pref
= "" end
670 if not op
.rex
then op
.rex
= {mode
= "rr", reg
= "0", rm
= "0", r64
= "0"} end
671 if not op
.extopcode
then op
.extopcode
= "" end
672 if not op
.code
then op
.code
= {} end
673 if op
.pref
== "66f2" then _assert(not op
.rex
.vex
and not op
.rex
.evex
) end
677 _renameFromLayout(op
)
684 -----------------------------------------------------------------
686 -----------------------------------------------------------------
687 --local mode,file= ...
689 local ops
,opset
= {},{}
692 -----------------------------------------------------------------
694 -----------------------------------------------------------------
695 inslist
= _gsub(inslist
, "(//[^\r\n]*)([\r\n])","%2")
696 inslist
= _gsub(inslist
, "(/%*.-%*/)","" )
699 for opname
, def
in _gmatch(inslist
, "%s*([%w_]+)%s*(%b{})") do
700 def
= _sub(_gsub(def
,"[\r\n]"," "),2,-2)
701 _assert( not opset
[opname
],"double definition of "..opname
)
702 local ok
, op
= pcall(parseLine
,opname
, def
)
705 if not op
then print("error in parseLine: ", opname
, prevopname
) end
713 for k
,v
in _pairs(cache
.opclass
) do
714 opclasses
[#opclasses
+ 1] = v
716 -- before avx2: 120 prefix (prefix + rex + extopcode/vex) classes, 60 coding classes
717 -- total: isa 39, rex 37, code 73, defuse 42, flags 61, layout 96, operands 321, orgnames 40
718 -- bits: isa 6, rex 6, code 7, defuse 6, flags 7, layout 7 -> sum 39 bits
719 -- class: to check if op is available): isa + 1 bit per opcodesubmask checking
720 -- prefix encoding: pref + rex + extopcode
721 -- main encoding: code
722 -- data flow: defuse + ???
723 -- register class is setup at construction time (of the vregs), and as such, not
724 -- relevant for def use. instruction constructors do the type checking for us.
725 -- allocation and data flow is done for virtual and fixed regs.so we have fixed registers to worry about,
729 local function opclassid(op
)
730 if op
.flags
.rmem
then r
= r
.. "R" end
731 if op
.flags
.wmem
then r
= r
.. "W" end
732 if op
.flags
.usemem
then r
= r
.. "U" end
734 -- if cl.subs[op.sub or 0] then
735 -- print("class "..(op.class or op.name).." contains the sub "..(op.sub or 0).." multiple times")
738 local function _compareISA(a
, b
)
739 if a
== b
then return false end
740 if (a
.x64
or false) ~= (b
.x64
or false) then return b
.x64
end
741 if (a
.x32only
or false) ~= (b
.x32only
or false) then return b
.x32only
end
742 if a
.sig
~= b
.sig
then return a
.sig
< b
.sig
end
743 _assert("comparing ISA failed")
745 _sort(opclasses
,function(a
,b
)
746 if a
.isa
~= b
.isa
then return _compareISA(a
.isa
, b
.isa
) end
749 for i
,v
in _ipairs(opclasses
) do v
.id
= i
end
751 _sort(ops
,function(a
,b
)
752 if a
.opclass
.isa
~= b
.opclass
.isa
then return _compareISA(a
.opclass
.isa
, b
.opclass
.isa
) end
753 return a
.name
< b
.name
756 -----------------------------------------
758 -----------------------------------------
760 GR8
="T_I8", GR16
= "T_I16", GR32
= "T_I32", GR64
= "T_I64",
761 VRI64
="T_V1I64", VRI128
="T_V2I64", VRI256
="T_V4I64", VRI128Z
="T_V2I64", VRI512
="T_V8I64",
762 VR4F32
="T_V4F32", VR2F64
= "T_V2F64", VR8F32
="T_V8F32", VR4F64
= "T_V4F64",
763 VR4F32Z
="T_V4F32", VR2F64Z
= "T_V2F64", VR16F32
="T_V16F32", VR8F64
= "T_V8F64",
765 i8
="T_I8", i16
= "T_I16", i32
= "T_I32", i64
= "T_I64",
768 ["i8*"]= "T_I8", ["i16*"]= "T_I16", ["i32*"]= "T_I32", ["i64*"]= "T_I64",
769 ["VI16*"]= "T_I16", ["VI32*"]= "T_I32", ["VI64*"]= "T_V1I64",
770 ["VI128*"]= "T_V2I64", ["VI256*"]= "T_V4I64", ["VI512*"]= "T_V8I64",
771 ["V2F32*"]= "T_V2F32", ["V4F32*"]= "T_V4F32", ["V2F64*"]= "T_V2F64",
772 ["V8F32*"]= "T_V8F32", ["V4F64*"]= "T_V4F64",
773 ["V16F32*"]= "T_V16F32", ["V8F64*"]= "T_V8F64",
774 ["f32*"]= "T_F32", ["f64*"]= "T_F64", ["V1F64*"]= "T_F64",
776 --local data = {ops=ops,type2type=type2type,ptr2type=ptr2type,opclasses=opclasses}
777 local data
= {ops
=ops
,opclasses
=opclasses
}
778 -- lib for creating/loading/storing/changing memory blocks
780 ---------------------------------------------
781 local function _scandump(x
, m
)
782 if _type(x
) == "table" then
783 if not m
[x
] then m
[#m
+ 1] = x
; m
[x
] = {0, "l["..#m
.."]"}; end
784 m
[x
][1] = m
[x
][1] + 1
785 if (m
[x
][1] > 1) then return m
end
786 for k
,v
in _pairs(x
) do
793 local function _write_value(f
,x
,m
)
794 if _type(x
)=="string" then
795 f
:write(_fmt("%q",x
))
798 if _type(x
)=="table" then
799 f
:write(m
[x
] and m
[x
][2] or "$ERROR")
804 local function _write_index(f
,x
,m
)
805 if type(x
)=="string" and _match(x
, "^[%a_][%w_]*$") then
814 local function writedump(f
,x
)
815 if _type(x
) ~= "table" then
821 local m
= _scandump(x
, {})
823 -- create refs for all tables
824 f
:write("local l = {}; for i = 1, "..#m
.." do l[i] = {} end\n")
826 for k
,v
in _ipairs(m
) do
827 f
:write("do local k = "..m
[v
][2].."\n")
828 for kk
,vv
in _pairs(v
) do
838 f
:write("return "..m
[x
][2].."\n")
841 local f
= io
.open(outname
, "w")