tablegen-x86.js 77 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413
  1. // [AsmJit]
  2. // Machine Code Generation for C++.
  3. //
  4. // [License]
  5. // Zlib - See LICENSE.md file in the package.
  6. // ============================================================================
  7. // tablegen-x86.js
  8. //
  9. // The purpose of this script is to fetch all instructions' names into a single
  10. // string and to optimize common patterns that appear in instruction data. It
  11. // prevents relocation of small strings (instruction names) that has to be done
  12. // by a linker to make all pointers the binary application/library uses valid.
  13. // This approach decreases the final size of AsmJit binary and relocation data.
  14. //
  15. // NOTE: This script relies on 'asmdb' package. Either install it by using
  16. // node.js package manager (npm) or by copying/symlinking the whole asmdb
  17. // directory as [asmjit]/tools/asmdb.
  18. // ============================================================================
  19. "use strict";
  20. const core = require("./tablegen.js");
  21. const asmdb = core.asmdb;
  22. const kIndent = core.kIndent;
  23. const Lang = core.Lang;
  24. const CxxUtils = core.CxxUtils;
  25. const MapUtils = core.MapUtils;
  26. const ArrayUtils = core.ArrayUtils;
  27. const StringUtils = core.StringUtils;
  28. const IndexedArray = core.IndexedArray;
  29. const hasOwn = Object.prototype.hasOwnProperty;
  30. const disclaimer = StringUtils.disclaimer;
  31. const FAIL = core.FAIL;
  32. const DEBUG = core.DEBUG;
  33. const decToHex = StringUtils.decToHex;
  34. // ============================================================================
  35. // [tablegen.x86.x86isa]
  36. // ============================================================================
  37. // Create the X86 database and add some special cases recognized by AsmJit.
  38. const x86isa = new asmdb.x86.ISA({
  39. instructions: [
  40. // Imul in [reg, imm] form is encoded as [reg, reg, imm].
  41. ["imul", "r16, ib" , "RMI" , "66 6B /r ib" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"],
  42. ["imul", "r32, ib" , "RMI" , "6B /r ib" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"],
  43. ["imul", "r64, ib" , "RMI" , "REX.W 6B /r ib", "X64 OF=W SF=W ZF=U AF=U PF=U CF=W"],
  44. ["imul", "r16, iw" , "RMI" , "66 69 /r iw" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"],
  45. ["imul", "r32, id" , "RMI" , "69 /r id" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"],
  46. ["imul", "r64, id" , "RMI" , "REX.W 69 /r id", "X64 OF=W SF=W ZF=U AF=U PF=U CF=W"]
  47. ]
  48. });
  49. // Remapped instructions contain mapping between instructions that AsmJit expects
  50. // and instructions provided by asmdb. In general, AsmJit uses string instructions
  51. // (like cmps, movs, etc...) without the suffix, so we just remap these and keep
  52. // all others.
  53. const RemappedInsts = {
  54. __proto__: null,
  55. "cmpsd": { names: ["cmpsd"] , rep: false },
  56. "movsd": { names: ["movsd"] , rep: false },
  57. "cmps" : { names: ["cmpsb", "cmpsw", "cmpsd", "cmpsq"], rep: true },
  58. "movs" : { names: ["movsb", "movsw", "movsd", "movsq"], rep: true },
  59. "lods" : { names: ["lodsb", "lodsw", "lodsd", "lodsq"], rep: null },
  60. "scas" : { names: ["scasb", "scasw", "scasd", "scasq"], rep: null },
  61. "stos" : { names: ["stosb", "stosw", "stosd", "stosq"], rep: null },
  62. "ins" : { names: ["insb" , "insw" , "insd" ] , rep: null },
  63. "outs" : { names: ["outsb", "outsw", "outsd"] , rep: null }
  64. };
  65. // ============================================================================
  66. // [tablegen.x86.Filter]
  67. // ============================================================================
  68. class Filter {
  69. static unique(instArray) {
  70. const result = [];
  71. const known = {};
  72. for (var i = 0; i < instArray.length; i++) {
  73. const inst = instArray[i];
  74. if (inst.attributes.AltForm)
  75. continue;
  76. const s = inst.operands.map((op) => { return op.isImm() ? "imm" : op.toString(); }).join(", ");
  77. if (known[s] === true)
  78. continue;
  79. known[s] = true;
  80. result.push(inst);
  81. }
  82. return result;
  83. }
  84. static noAltForm(instArray) {
  85. const result = [];
  86. for (var i = 0; i < instArray.length; i++) {
  87. const inst = instArray[i];
  88. if (inst.attributes.AltForm)
  89. continue;
  90. result.push(inst);
  91. }
  92. return result;
  93. }
  94. static byArch(instArray, arch) {
  95. return instArray.filter(function(inst) {
  96. return inst.arch === "ANY" || inst.arch === arch;
  97. });
  98. }
  99. }
  100. // ============================================================================
  101. // [tablegen.x86.GenUtils]
  102. // ============================================================================
  103. class GenUtils {
  104. static cpuArchOf(dbInsts) {
  105. var anyArch = false;
  106. var x86Arch = false;
  107. var x64Arch = false;
  108. for (var i = 0; i < dbInsts.length; i++) {
  109. const dbInst = dbInsts[i];
  110. if (dbInst.arch === "ANY") anyArch = true;
  111. if (dbInst.arch === "X86") x86Arch = true;
  112. if (dbInst.arch === "X64") x64Arch = true;
  113. }
  114. return anyArch || (x86Arch && x64Arch) ? "" : x86Arch ? "(X86)" : "(X64)";
  115. }
  116. static cpuFeaturesOf(dbInsts) {
  117. return ArrayUtils.sorted(dbInsts.unionCpuFeatures());
  118. }
  119. static flagsOf(dbInsts) {
  120. function replace(map, a, b, c) {
  121. if (map[a] && map[b]) {
  122. delete map[a];
  123. delete map[b];
  124. map[c] = true;
  125. }
  126. }
  127. const f = Object.create(null);
  128. var i, j;
  129. var mib = dbInsts.length > 0 && /^(?:bndldx|bndstx)$/.test(dbInsts[0].name);
  130. if (mib) f.Mib = true;
  131. var mmx = false;
  132. var vec = false;
  133. for (i = 0; i < dbInsts.length; i++) {
  134. const dbInst = dbInsts[i];
  135. const operands = dbInst.operands;
  136. if (dbInst.name === "emms")
  137. mmx = true;
  138. if (dbInst.name === "vzeroall" || dbInst.name === "vzeroupper")
  139. vec = true;
  140. for (j = 0; j < operands.length; j++) {
  141. const op = operands[j];
  142. if (op.reg === "mm")
  143. mmx = true;
  144. else if (/^(k|xmm|ymm|zmm)$/.test(op.reg)) {
  145. vec = true;
  146. }
  147. }
  148. }
  149. if (mmx) f.Mmx = true;
  150. if (vec) f.Vec = true;
  151. for (i = 0; i < dbInsts.length; i++) {
  152. const dbInst = dbInsts[i];
  153. const operands = dbInst.operands;
  154. if (dbInst.attributes.Lock ) f.Lock = true;
  155. if (dbInst.attributes.XAcquire ) f.XAcquire = true;
  156. if (dbInst.attributes.XRelease ) f.XRelease = true;
  157. if (dbInst.attributes.BND ) f.Rep = true;
  158. if (dbInst.attributes.REP ) f.Rep = true;
  159. if (dbInst.attributes.REPNE ) f.Rep = true;
  160. if (dbInst.attributes.RepIgnored) f.RepIgnored = true;
  161. if (dbInst.fpu) {
  162. for (var j = 0; j < operands.length; j++) {
  163. const op = operands[j];
  164. if (op.memSize === 16) f.FpuM16 = true;
  165. if (op.memSize === 32) f.FpuM32 = true;
  166. if (op.memSize === 64) f.FpuM64 = true;
  167. if (op.memSize === 80) f.FpuM80 = true;
  168. }
  169. }
  170. if (dbInst.vsibReg)
  171. f.Vsib = true;
  172. if (dbInst.prefix === "VEX" || dbInst.prefix === "XOP")
  173. f.Vex = true;
  174. if (dbInst.prefix === "EVEX") {
  175. f.Evex = true;
  176. if (dbInst.kmask) f.Avx512K = true;
  177. if (dbInst.zmask) f.Avx512Z = true;
  178. if (dbInst.er) f.Avx512ER = true;
  179. if (dbInst.sae) f.Avx512SAE = true;
  180. if (dbInst.broadcast) f["Avx512B" + String(dbInst.elementSize)] = true;
  181. if (dbInst.tupleType === "T1_4X") f.Avx512T4X = true;
  182. }
  183. }
  184. replace(f, "Avx512K" , "Avx512Z" , "Avx512KZ");
  185. replace(f, "Avx512ER" , "Avx512SAE" , "Avx512ER_SAE");
  186. replace(f, "Avx512KZ" , "Avx512SAE" , "Avx512KZ_SAE");
  187. replace(f, "Avx512KZ" , "Avx512ER_SAE", "Avx512KZ_ER_SAE");
  188. replace(f, "Avx512K" , "Avx512B32" , "Avx512K_B32");
  189. replace(f, "Avx512K" , "Avx512B64" , "Avx512K_B64");
  190. replace(f, "Avx512KZ" , "Avx512B32" , "Avx512KZ_B32");
  191. replace(f, "Avx512KZ" , "Avx512B64" , "Avx512KZ_B64");
  192. replace(f, "Avx512KZ_SAE" , "Avx512B32" , "Avx512KZ_SAE_B32");
  193. replace(f, "Avx512KZ_SAE" , "Avx512B64" , "Avx512KZ_SAE_B64");
  194. replace(f, "Avx512KZ_ER_SAE", "Avx512B32" , "Avx512KZ_ER_SAE_B32");
  195. replace(f, "Avx512KZ_ER_SAE", "Avx512B64" , "Avx512KZ_ER_SAE_B64");
  196. return Object.getOwnPropertyNames(f);
  197. }
  198. static eqOps(aOps, aFrom, bOps, bFrom) {
  199. var x = 0;
  200. for (;;) {
  201. const aIndex = x + aFrom;
  202. const bIndex = x + bFrom;
  203. const aOut = aIndex >= aOps.length;
  204. const bOut = bIndex >= bOps.length;
  205. if (aOut || bOut)
  206. return !!(aOut && bOut);
  207. const aOp = aOps[aIndex];
  208. const bOp = bOps[bIndex];
  209. if (aOp.data !== bOp.data)
  210. return false;
  211. x++;
  212. }
  213. }
  214. static singleRegCase(name) {
  215. switch (name) {
  216. case "xchg" :
  217. case "and" :
  218. case "pand" : case "vpand" : case "vpandd" : case "vpandq" :
  219. case "andpd" : case "vandpd" :
  220. case "andps" : case "vandps" :
  221. case "or" :
  222. case "por" : case "vpor" : case "vpord" : case "vporq" :
  223. case "orpd" : case "vorpd" :
  224. case "orps" : case "vorps" :
  225. case "pminsb" : case "vpminsb": case "pmaxsb" : case "vpmaxsb" :
  226. case "pminsw" : case "vpminsw": case "pmaxsw" : case "vpmaxsw" :
  227. case "pminsd" : case "vpminsd": case "pmaxsd" : case "vpmaxsd" :
  228. case "pminub" : case "vpminub": case "pmaxub" : case "vpmaxub" :
  229. case "pminuw" : case "vpminuw": case "pmaxuw" : case "vpmaxuw" :
  230. case "pminud" : case "vpminud": case "pmaxud" : case "vpmaxud" :
  231. return "RO";
  232. case "pandn" : case "vpandn" : case "vpandnd" : case "vpandnq" :
  233. case "xor" :
  234. case "pxor" : case "vpxor" : case "vpxord" : case "vpxorq" :
  235. case "xorpd" : case "vxorpd" :
  236. case "xorps" : case "vxorps" :
  237. case "sub" :
  238. case "sbb" :
  239. case "psubb" : case "vpsubb" :
  240. case "psubw" : case "vpsubw" :
  241. case "psubd" : case "vpsubd" :
  242. case "psubq" : case "vpsubq" :
  243. case "psubsb" : case "vpsubsb": case "psubusb" : case "vpsubusb" :
  244. case "psubsw" : case "vpsubsw": case "psubusw" : case "vpsubusw" :
  245. case "vpcmpeqb": case "pcmpeqb": case "vpcmpgtb": case "pcmpgtb" :
  246. case "vpcmpeqw": case "pcmpeqw": case "vpcmpgtw": case "pcmpgtw" :
  247. case "vpcmpeqd": case "pcmpeqd": case "vpcmpgtd": case "pcmpgtd" :
  248. case "vpcmpeqq": case "pcmpeqq": case "vpcmpgtq": case "pcmpgtq" :
  249. case "vpcmpb" : case "vpcmpub":
  250. case "vpcmpd" : case "vpcmpud":
  251. case "vpcmpw" : case "vpcmpuw":
  252. case "vpcmpq" : case "vpcmpuq":
  253. return "WO";
  254. default:
  255. return "None";
  256. }
  257. }
  258. static fixedRegOf(reg) {
  259. switch (reg) {
  260. case "es" : return 1;
  261. case "cs" : return 2;
  262. case "ss" : return 3;
  263. case "ds" : return 4;
  264. case "fs" : return 5;
  265. case "gs" : return 6;
  266. case "ah" : return 0;
  267. case "ch" : return 1;
  268. case "dh" : return 2;
  269. case "bh" : return 3;
  270. case "al" : case "ax": case "eax": case "rax": case "zax": return 0;
  271. case "cl" : case "cx": case "ecx": case "rcx": case "zcx": return 1;
  272. case "dl" : case "dx": case "edx": case "rdx": case "zdx": return 2;
  273. case "bl" : case "bx": case "ebx": case "rbx": case "zbx": return 3;
  274. case "spl" : case "sp": case "esp": case "rsp": case "zsp": return 4;
  275. case "bpl" : case "bp": case "ebp": case "rbp": case "zbp": return 5;
  276. case "sil" : case "si": case "esi": case "rsi": case "zsi": return 6;
  277. case "dil" : case "di": case "edi": case "rdi": case "zdi": return 7;
  278. case "st0" : return 0;
  279. case "xmm0": return 0;
  280. case "ymm0": return 0;
  281. case "zmm0": return 0;
  282. default:
  283. return -1;
  284. }
  285. }
  286. static controlType(dbInsts) {
  287. if (dbInsts.checkAttribute("Control", "Jump")) return "Jump";
  288. if (dbInsts.checkAttribute("Control", "Call")) return "Call";
  289. if (dbInsts.checkAttribute("Control", "Branch")) return "Branch";
  290. if (dbInsts.checkAttribute("Control", "Return")) return "Return";
  291. return "None";
  292. }
  293. }
  294. // ============================================================================
  295. // [tablegen.x86.X86TableGen]
  296. // ============================================================================
  297. class X86TableGen extends core.TableGen {
  298. constructor() {
  299. super("X86");
  300. }
  301. // --------------------------------------------------------------------------
  302. // [Query]
  303. // --------------------------------------------------------------------------
  304. // Get instructions (dbInsts) having the same name as understood by AsmJit.
  305. query(name) {
  306. const remapped = RemappedInsts[name];
  307. if (!remapped) return x86isa.query(name);
  308. const dbInsts = x86isa.query(remapped.names);
  309. const rep = remapped.rep;
  310. if (rep === null) return dbInsts;
  311. return dbInsts.filter((inst) => {
  312. return rep === !!(inst.attributes.REP || inst.attributes.REPNE);
  313. });
  314. }
  315. // --------------------------------------------------------------------------
  316. // [Parse / Merge]
  317. // --------------------------------------------------------------------------
  318. parse() {
  319. const data = this.dataOfFile("src/asmjit/x86/x86instdb.cpp");
  320. const re = new RegExp(
  321. "INST\\(" +
  322. "([A-Za-z0-9_]+)\\s*" + "," + // [01] Instruction.
  323. "([^,]+)" + "," + // [02] Encoding.
  324. "(.{26}[^,]*)" + "," + // [03] Opcode[0].
  325. "(.{26}[^,]*)" + "," + // [04] Opcode[1].
  326. // --- autogenerated fields ---
  327. "([^\\)]+)" + "," + // [05] MainOpcodeIndex.
  328. "([^\\)]+)" + "," + // [06] AltOpcodeIndex.
  329. "([^\\)]+)" + "," + // [07] NameIndex.
  330. "([^\\)]+)" + "," + // [08] CommonDataIndex.
  331. "([^\\)]+)" + "\\)", // [09] OperationDataIndex.
  332. "g");
  333. var m;
  334. while ((m = re.exec(data)) !== null) {
  335. var enum_ = m[1];
  336. var name = enum_ === "None" ? "" : enum_.toLowerCase();
  337. var encoding = m[2].trim();
  338. var opcode0 = m[3].trim();
  339. var opcode1 = m[4].trim();
  340. const dbInsts = this.query(name);
  341. if (name && !dbInsts.length)
  342. FAIL(`Instruction '${name}' not found in asmdb`);
  343. const flags = GenUtils.flagsOf(dbInsts);
  344. const controlType = GenUtils.controlType(dbInsts);
  345. const singleRegCase = GenUtils.singleRegCase(name);
  346. this.addInst({
  347. id : 0, // Instruction id (numeric value).
  348. name : name, // Instruction name.
  349. enum : enum_, // Instruction enum without `kId` prefix.
  350. dbInsts : dbInsts, // All dbInsts returned from asmdb query.
  351. encoding : encoding, // Instruction encoding.
  352. opcode0 : opcode0, // Primary opcode.
  353. opcode1 : opcode1, // Secondary opcode.
  354. flags : flags,
  355. signatures : null, // Instruction signatures.
  356. controlType : controlType,
  357. singleRegCase : singleRegCase,
  358. mainOpcodeValue : -1, // Main opcode value (0.255 hex).
  359. mainOpcodeIndex : -1, // Index to InstDB::_mainOpcodeTable.
  360. altOpcodeIndex : -1, // Index to InstDB::_altOpcodeTable.
  361. nameIndex : -1, // Index to InstDB::_nameData.
  362. commonInfoIndexA : -1,
  363. commomInfoIndexB : -1,
  364. signatureIndex : -1,
  365. signatureCount : -1
  366. });
  367. }
  368. if (this.insts.length === 0)
  369. FAIL("X86TableGen.parse(): Invalid parsing regexp (no data parsed)");
  370. console.log("Number of Instructions: " + this.insts.length);
  371. }
  372. merge() {
  373. var s = StringUtils.format(this.insts, "", true, function(inst) {
  374. return "INST(" +
  375. String(inst.enum ).padEnd(17) + ", " +
  376. String(inst.encoding ).padEnd(19) + ", " +
  377. String(inst.opcode0 ).padEnd(26) + ", " +
  378. String(inst.opcode1 ).padEnd(26) + ", " +
  379. String(inst.mainOpcodeIndex ).padEnd( 3) + ", " +
  380. String(inst.altOpcodeIndex ).padEnd( 3) + ", " +
  381. String(inst.nameIndex ).padEnd( 5) + ", " +
  382. String(inst.commonInfoIndexA).padEnd( 3) + ", " +
  383. String(inst.commomInfoIndexB).padEnd( 3) + ")";
  384. }) + "\n";
  385. this.inject("InstInfo", s, this.insts.length * 8);
  386. }
  387. // --------------------------------------------------------------------------
  388. // [Other]
  389. // --------------------------------------------------------------------------
  390. printMissing() {
  391. const ignored = MapUtils.arrayToMap([
  392. "cmpsb", "cmpsw", "cmpsd", "cmpsq",
  393. "lodsb", "lodsw", "lodsd", "lodsq",
  394. "movsb", "movsw", "movsd", "movsq",
  395. "scasb", "scasw", "scasd", "scasq",
  396. "stosb", "stosw", "stosd", "stosq",
  397. "insb" , "insw" , "insd" ,
  398. "outsb", "outsw", "outsd",
  399. "wait" // Maps to `fwait`, which AsmJit uses instead.
  400. ]);
  401. var out = "";
  402. x86isa.instructionNames.forEach(function(name) {
  403. var dbInsts = x86isa.query(name);
  404. if (!this.instMap[name] && ignored[name] !== true) {
  405. console.log(`MISSING INSTRUCTION '${name}'`);
  406. var inst = this.newInstFromGroup(dbInsts);
  407. if (inst) {
  408. out += " INST(" +
  409. String(inst.enum ).padEnd(17) + ", " +
  410. String(inst.encoding ).padEnd(19) + ", " +
  411. String(inst.opcode0 ).padEnd(26) + ", " +
  412. String(inst.opcode1 ).padEnd(26) + ", " +
  413. String("0" ).padEnd( 4) + ", " +
  414. String("0" ).padEnd( 3) + ", " +
  415. String("0" ).padEnd( 3) + "),\n";
  416. }
  417. }
  418. }, this);
  419. console.log(out);
  420. }
  421. newInstFromGroup(dbInsts) {
  422. function composeOpCode(obj) {
  423. return `${obj.type}(${obj.prefix},${obj.opcode},${obj.o},${obj.l},${obj.w},${obj.ew},${obj.en},${obj.tt})`;
  424. }
  425. function GetAccess(dbInst) {
  426. var operands = dbInst.operands;
  427. if (!operands.length) return "";
  428. var op = operands[0];
  429. if (op.read && op.write)
  430. return "RW";
  431. else if (op.read)
  432. return "RO";
  433. else
  434. return "WO";
  435. }
  436. function isVecPrefix(s) {
  437. return s === "VEX" || s === "EVEX" || s === "XOP";
  438. }
  439. var dbi = dbInsts[0];
  440. var id = this.insts.length;
  441. var name = dbi.name;
  442. var enum_ = name[0].toUpperCase() + name.substr(1);
  443. var opcode = dbi.opcodeHex;
  444. var rm = dbi.rm;
  445. var mm = dbi.mm;
  446. var pp = dbi.pp;
  447. var encoding = dbi.encoding;
  448. var isVec = isVecPrefix(dbi.prefix);
  449. var access = GetAccess(dbi);
  450. var vexL = undefined;
  451. var vexW = undefined;
  452. var evexW = undefined;
  453. for (var i = 0; i < dbInsts.length; i++) {
  454. dbi = dbInsts[i];
  455. if (dbi.prefix === "VEX" || dbi.prefix === "XOP") {
  456. var newVexL = String(dbi.l === "128" ? 0 : dbi.l === "256" ? 1 : dbi.l === "512" ? 2 : "_");
  457. var newVexW = String(dbi.w === "W0" ? 0 : dbi.w === "W1" ? 1 : "_");
  458. if (vexL !== undefined && vexL !== newVexL)
  459. vexL = "x";
  460. else
  461. vexL = newVexL;
  462. if (vexW !== undefined && vexW !== newVexW)
  463. vexW = "x";
  464. else
  465. vexW = newVexW;
  466. }
  467. if (dbi.prefix === "EVEX") {
  468. var newEvexW = String(dbi.w === "W0" ? 0 : dbi.w === "W1" ? 1 : "_");
  469. if (evexW !== undefined && evexW !== newEvexW)
  470. evexW = "x";
  471. else
  472. evexW = newEvexW;
  473. }
  474. if (opcode !== dbi.opcodeHex ) { console.log(`ISSUE: Opcode ${opcode} != ${dbi.opcodeHex}`); return null; }
  475. if (rm !== dbi.rm ) { console.log(`ISSUE: RM ${rm} != ${dbi.rm}`); return null; }
  476. if (mm !== dbi.mm ) { console.log(`ISSUE: MM ${mm} != ${dbi.mm}`); return null; }
  477. if (pp !== dbi.pp ) { console.log(`ISSUE: PP ${pp} != ${dbi.pp}`); return null; }
  478. if (encoding !== dbi.encoding ) { console.log(`ISSUE: Enc ${encoding} != ${dbi.encoding}`); return null; }
  479. if (access !== GetAccess(dbi)) { console.log(`ISSUE: Access ${access} != ${GetAccess(dbi)}`); return null; }
  480. if (isVec != isVecPrefix(dbi.prefix)) { console.log(`ISSUE: Vex/Non-Vex mismatch`); return null; }
  481. }
  482. var ppmm = pp.padEnd(2).replace(/ /g, "0") +
  483. mm.padEnd(4).replace(/ /g, "0") ;
  484. var composed = composeOpCode({
  485. type : isVec ? "V" : "O",
  486. prefix: ppmm,
  487. opcode: opcode,
  488. o : rm === "r" ? "_" : (rm ? rm : "_"),
  489. l : vexL !== undefined ? vexL : "_",
  490. w : vexW !== undefined ? vexW : "_",
  491. ew : evexW !== undefined ? evexW : "_",
  492. en : "_",
  493. tt : "_ "
  494. });
  495. return {
  496. id : id,
  497. name : name,
  498. enum : enum_,
  499. encoding : encoding,
  500. opcode0 : composed,
  501. opcode1 : "0",
  502. nameIndex : -1,
  503. commonInfoIndexA : -1,
  504. commomInfoIndexB : -1
  505. };
  506. }
  507. // --------------------------------------------------------------------------
  508. // [Hooks]
  509. // --------------------------------------------------------------------------
  510. onBeforeRun() {
  511. this.load([
  512. "src/asmjit/x86/x86globals.h",
  513. "src/asmjit/x86/x86instdb.cpp",
  514. "src/asmjit/x86/x86instdb.h",
  515. "src/asmjit/x86/x86instdb_p.h"
  516. ]);
  517. this.parse();
  518. }
  519. onAfterRun() {
  520. this.merge();
  521. this.save();
  522. this.dumpTableSizes();
  523. this.printMissing();
  524. }
  525. }
  526. // ============================================================================
  527. // [tablegen.x86.IdEnum]
  528. // ============================================================================
  529. class IdEnum extends core.IdEnum {
  530. constructor() {
  531. super("IdEnum");
  532. }
  533. comment(inst) {
  534. function filterAVX(features, avx) {
  535. return features.filter(function(item) { return /^(AVX|FMA)/.test(item) === avx; });
  536. }
  537. var dbInsts = inst.dbInsts;
  538. if (!dbInsts.length) return "Invalid instruction id.";
  539. var text = "";
  540. var features = GenUtils.cpuFeaturesOf(dbInsts);
  541. if (features.length) {
  542. text += "{";
  543. const avxFeatures = filterAVX(features, true);
  544. const otherFeatures = filterAVX(features, false);
  545. const vl = avxFeatures.indexOf("AVX512_VL");
  546. if (vl !== -1) avxFeatures.splice(vl, 1);
  547. const fma = avxFeatures.indexOf("FMA");
  548. if (fma !== -1) { avxFeatures.splice(fma, 1); avxFeatures.splice(0, 0, "FMA"); }
  549. text += avxFeatures.join("|");
  550. if (vl !== -1) text += "+VL";
  551. if (otherFeatures.length)
  552. text += (avxFeatures.length ? " & " : "") + otherFeatures.join("|");
  553. text += "}";
  554. }
  555. var arch = GenUtils.cpuArchOf(dbInsts);
  556. if (arch)
  557. text += (text ? " " : "") + arch;
  558. return `Instruction '${inst.name}'${(text ? " " + text : "")}.`;
  559. }
  560. }
  561. // ============================================================================
  562. // [tablegen.x86.NameTable]
  563. // ============================================================================
  564. class NameTable extends core.NameTable {
  565. constructor() {
  566. super("NameTable");
  567. }
  568. }
  569. // ============================================================================
  570. // [tablegen.x86.AltOpcodeTable]
  571. // ============================================================================
  572. class AltOpcodeTable extends core.Task {
  573. constructor() {
  574. super("AltOpcodeTable");
  575. }
  576. run() {
  577. const insts = this.ctx.insts;
  578. const mainOpcodeTable = new IndexedArray();
  579. const altOpcodeTable = new IndexedArray();
  580. mainOpcodeTable.addIndexed("O(000000,00,0,0,0,0,0,_ )");
  581. function indexOpcode(opcode) {
  582. if (opcode === "0")
  583. return ["00", 0];
  584. // O_FPU(__,__OP,_)
  585. if (opcode.startsWith("O_FPU(")) {
  586. var value = opcode.substring(11, 13);
  587. var remaining = opcode.substring(0, 11) + "00" + opcode.substring(13);
  588. return [value, mainOpcodeTable.addIndexed(remaining.padEnd(26))];
  589. }
  590. // X(______,OP,_,_,_,_,_,_ )
  591. if (opcode.startsWith("O_FPU(") || opcode.startsWith("O(") || opcode.startsWith("V(") || opcode.startsWith("E(")) {
  592. var value = opcode.substring(9, 11);
  593. var remaining = opcode.substring(0, 9) + "00" + opcode.substring(11);
  594. remaining = remaining.replace(/,[_xI],/g, ",0,");
  595. remaining = remaining.replace(/,[_xI],/g, ",0,");
  596. return [value, mainOpcodeTable.addIndexed(remaining.padEnd(26))];
  597. }
  598. FAIL(`Failed to process opcode '${opcode}'`);
  599. }
  600. insts.map((inst) => {
  601. const [value, index] = indexOpcode(inst.opcode0);
  602. inst.mainOpcodeValue = value;
  603. inst.mainOpcodeIndex = index;
  604. inst.altOpcodeIndex = altOpcodeTable.addIndexed(inst.opcode1.padEnd(26));
  605. });
  606. // console.log(mainOpcodeTable.length);
  607. // console.log(StringUtils.format(mainOpcodeTable, kIndent, true));
  608. this.inject("MainOpcodeTable",
  609. disclaimer(`const uint32_t InstDB::_mainOpcodeTable[] = {\n${StringUtils.format(mainOpcodeTable, kIndent, true)}\n};\n`),
  610. mainOpcodeTable.length * 4);
  611. this.inject("AltOpcodeTable",
  612. disclaimer(`const uint32_t InstDB::_altOpcodeTable[] = {\n${StringUtils.format(altOpcodeTable, kIndent, true)}\n};\n`),
  613. altOpcodeTable.length * 4);
  614. }
  615. }
  616. // ============================================================================
  617. // [tablegen.x86.SseToAvxTable]
  618. // ============================================================================
  619. /*
  620. // Removed from asmjit.
  621. class InstSseToAvxTable extends core.Task {
  622. constructor() {
  623. super("InstSseToAvxTable", ["IdEnum"]);
  624. }
  625. run() {
  626. const insts = this.ctx.insts;
  627. const dataTable = new IndexedArray();
  628. const indexTable = [];
  629. function add(data) {
  630. return dataTable.addIndexed("{ " + `SseToAvxData::kMode${data.mode}`.padEnd(28) + ", " + String(data.delta).padEnd(4) + " }");
  631. }
  632. // This will receive a zero index, which means that no SseToAvx or AvxToSSe translation is possible.
  633. const kInvalidIndex = add({ mode: "None", delta: 0 });
  634. insts.forEach((inst) => { indexTable.push(kInvalidIndex); });
  635. insts.forEach((inst) => {
  636. // If it's not `kInvalidIndex` it's an AVX instruction that shares the
  637. // SseToAvx data. We won't touch it as it already has the index assigned.
  638. if (indexTable[inst.id] === kInvalidIndex) {
  639. const data = this.calcSseToAvxData(inst.dbInsts);
  640. const index = add(data);
  641. indexTable[inst.id] = index;
  642. if (data.delta !== 0)
  643. indexTable[this.ctx.instMap["v" + inst.name].id] = index;
  644. }
  645. });
  646. this.inject("SseToAvxIndex",
  647. disclaimer(`static const uint8_t sseToAvxIndex[] = {\n${StringUtils.format(indexTable, kIndent, -1)}\n};\n`),
  648. indexTable.length * 1);
  649. this.inject("SseToAvxTable",
  650. disclaimer(`static const SseToAvxData sseToAvxData[] = {\n${StringUtils.format(dataTable, kIndent, true)}\n};\n`),
  651. dataTable.length * 2);
  652. }
  653. filterSseToAvx(dbInsts) {
  654. const filtered = [];
  655. for (var x = 0; x < dbInsts.length; x++) {
  656. const dbInst = dbInsts[x];
  657. const ops = dbInst.operands;
  658. // SSE instruction does never share its name with AVX one.
  659. if (/^(VEX|XOP|EVEX)$/.test(dbInst.prefix))
  660. return [];
  661. var ok = false;
  662. for (var y = 0; y < ops.length; y++) {
  663. // There is no AVX instruction that works with MMX regs.
  664. if (ops[y].reg === "mm") { ok = false; break; }
  665. if (ops[y].reg === "xmm") { ok = true; }
  666. }
  667. if (ok)
  668. filtered.push(dbInst);
  669. }
  670. return filtered;
  671. }
  672. calcSseToAvxData(dbInsts) {
  673. const data = {
  674. mode : "None", // No conversion by default.
  675. delta: 0 // 0 if no conversion is possible.
  676. };
  677. const dbSseInsts = this.filterSseToAvx(dbInsts);
  678. if (!dbSseInsts.length)
  679. return data;
  680. const sseName = dbSseInsts[0].name;
  681. const avxName = "v" + sseName;
  682. const dbAvxInsts = this.ctx.query(avxName);
  683. if (!dbAvxInsts.length) {
  684. DEBUG(`SseToAvx: Instruction '${sseName}' has no AVX counterpart`);
  685. return data;
  686. }
  687. if (avxName === "vblendvpd" || avxName === "vblendvps" || avxName === "vpblendvb") {
  688. // Special cases first.
  689. data.mode = "Blend";
  690. }
  691. else {
  692. // Common case, deduce conversion mode by checking both SSE and AVX instructions.
  693. const map = Object.create(null);
  694. for (var sseIndex = 0; sseIndex < dbSseInsts.length; sseIndex++) {
  695. const sseInst = dbSseInsts[sseIndex];
  696. var match = false;
  697. for (var avxIndex = 0; avxIndex < dbAvxInsts.length; avxIndex++) {
  698. const avxInst = dbAvxInsts[avxIndex];
  699. // Select only VEX instructions.
  700. if (avxInst.prefix !== "VEX") continue;
  701. // Check if the AVX version is the same.
  702. if (GenUtils.eqOps(avxInst.operands, 0, sseInst.operands, 0)) {
  703. map.raw = true;
  704. match = true;
  705. }
  706. else if (avxInst.operands[0].data === "xmm" && GenUtils.eqOps(avxInst.operands, 1, sseInst.operands, 0)) {
  707. map.nds = true;
  708. match = true;
  709. }
  710. }
  711. if (!match) {
  712. const signature = sseInst.operands.map(function(op) { return op.data; }).join(", ");
  713. console.log(`SseToAvx: Instruction '${sseName}(${signature})' has no AVX counterpart`);
  714. return data;
  715. }
  716. }
  717. data.mode = (map.raw && !map.nds) ? "Move" : (map.raw && map.nds) ? "MoveIfMem" : "Extend";
  718. }
  719. data.delta = this.ctx.instMap[avxName].id - this.ctx.instMap[sseName].id;
  720. return data;
  721. }
  722. }
  723. */
  724. // ============================================================================
  725. // [tablegen.x86.InstSignatureTable]
  726. // ============================================================================
  727. const RegOp = MapUtils.arrayToMap(["al", "ah", "ax", "eax", "rax", "cl", "r8lo", "r8hi", "r16", "r32", "r64", "xmm", "ymm", "zmm", "mm", "k", "sreg", "creg", "dreg", "st", "bnd"]);
  728. const MemOp = MapUtils.arrayToMap(["m8", "m16", "m32", "m48", "m64", "m80", "m128", "m256", "m512", "m1024"]);
  729. const cmpOp = StringUtils.makePriorityCompare([
  730. "r8lo", "r8hi", "r16", "r32", "r64", "xmm", "ymm", "zmm", "mm", "k", "sreg", "creg", "dreg", "st", "bnd",
  731. "mem", "vm", "m8", "m16", "m32", "m48", "m64", "m80", "m128", "m256", "m512", "m1024",
  732. "mib",
  733. "vm32x", "vm32y", "vm32z", "vm64x", "vm64y", "vm64z",
  734. "memBase", "memES", "memDS",
  735. "i4", "u4", "i8", "u8", "i16", "u16", "i32", "u32", "i64", "u64",
  736. "rel8", "rel32",
  737. "implicit"
  738. ]);
  739. const OpToAsmJitOp = {
  740. "implicit": "F(Implicit)",
  741. "r8lo" : "F(GpbLo)",
  742. "r8hi" : "F(GpbHi)",
  743. "r16" : "F(Gpw)",
  744. "r32" : "F(Gpd)",
  745. "r64" : "F(Gpq)",
  746. "xmm" : "F(Xmm)",
  747. "ymm" : "F(Ymm)",
  748. "zmm" : "F(Zmm)",
  749. "mm" : "F(Mm)",
  750. "k" : "F(KReg)",
  751. "sreg" : "F(SReg)",
  752. "creg" : "F(CReg)",
  753. "dreg" : "F(DReg)",
  754. "st" : "F(St)",
  755. "bnd" : "F(Bnd)",
  756. "mem" : "F(Mem)",
  757. "vm" : "F(Vm)",
  758. "i4" : "F(I4)",
  759. "u4" : "F(U4)",
  760. "i8" : "F(I8)",
  761. "u8" : "F(U8)",
  762. "i16" : "F(I16)",
  763. "u16" : "F(U16)",
  764. "i32" : "F(I32)",
  765. "u32" : "F(U32)",
  766. "i64" : "F(I64)",
  767. "u64" : "F(U64)",
  768. "rel8" : "F(Rel8)",
  769. "rel32" : "F(Rel32)",
  770. "m8" : "M(M8)",
  771. "m16" : "M(M16)",
  772. "m32" : "M(M32)",
  773. "m48" : "M(M48)",
  774. "m64" : "M(M64)",
  775. "m80" : "M(M80)",
  776. "m128" : "M(M128)",
  777. "m256" : "M(M256)",
  778. "m512" : "M(M512)",
  779. "m1024" : "M(M1024)",
  780. "mib" : "M(Mib)",
  781. "mAny" : "M(Any)",
  782. "vm32x" : "M(Vm32x)",
  783. "vm32y" : "M(Vm32y)",
  784. "vm32z" : "M(Vm32z)",
  785. "vm64x" : "M(Vm64x)",
  786. "vm64y" : "M(Vm64y)",
  787. "vm64z" : "M(Vm64z)",
  788. "memBase" : "M(BaseOnly)",
  789. "memDS" : "M(Ds)",
  790. "memES" : "M(Es)"
  791. };
  792. function StringifyArray(a, map) {
  793. var s = "";
  794. for (var i = 0; i < a.length; i++) {
  795. const op = a[i];
  796. if (!hasOwn.call(map, op))
  797. FAIL(`UNHANDLED OPERAND '${op}'`);
  798. s += (s ? " | " : "") + map[op];
  799. }
  800. return s ? s : "0";
  801. }
  802. class OSignature {
  803. constructor() {
  804. this.flags = Object.create(null);
  805. }
  806. equals(other) {
  807. return MapUtils.equals(this.flags, other.flags);
  808. }
  809. xor(other) {
  810. const result = MapUtils.xor(this.flags, other.flags);
  811. return Object.getOwnPropertyNames(result).length === 0 ? null : result;
  812. }
  813. mergeWith(other) {
  814. const af = this.flags;
  815. const bf = other.flags;
  816. var k;
  817. var indexKind = "";
  818. var hasReg = false;
  819. for (k in af) {
  820. const index = asmdb.x86.Utils.regIndexOf(k);
  821. const kind = asmdb.x86.Utils.regKindOf(k);
  822. if (kind)
  823. hasReg = true;
  824. if (index !== null && index !== -1)
  825. indexKind = kind;
  826. }
  827. if (hasReg) {
  828. for (k in bf) {
  829. const index = asmdb.x86.Utils.regIndexOf(k);
  830. if (index !== null && index !== -1) {
  831. const kind = asmdb.x86.Utils.regKindOf(k);
  832. if (indexKind !== kind) return false;
  833. }
  834. }
  835. }
  836. // Can merge...
  837. for (k in bf) af[k] = true;
  838. return true;
  839. }
  840. simplify() {
  841. const flags = this.flags;
  842. // 32-bit register or 16-bit memory implies also 16-bit reg.
  843. if (flags.r32 && flags.m16) {
  844. flags.r16 = true;
  845. }
  846. // 32-bit register or 8-bit memory implies also 16-bit and 8-bit reg.
  847. if (flags.r32 && flags.m8) {
  848. flags.r8lo = true;
  849. flags.r8hi = true;
  850. flags.r16 = true;
  851. }
  852. }
  853. toString() {
  854. var s = "";
  855. var flags = this.flags;
  856. for (var k in flags) {
  857. if (k === "read" || k === "write" || k === "implicit" || k === "memDS" || k === "memES")
  858. continue;
  859. var x = k;
  860. if (x === "memZAX") x = "zax";
  861. if (x === "memZDI") x = "zdi";
  862. if (x === "memZSI") x = "zsi";
  863. s += (s ? "|" : "") + x;
  864. }
  865. if (flags.memDS) s = "ds:[" + s + "]";
  866. if (flags.memES) s = "es:[" + s + "]";
  867. if (flags.implicit)
  868. s = "<" + s + ">";
  869. return s;
  870. }
  871. toAsmJitOpData() {
  872. var oFlags = this.flags;
  873. var mFlags = Object.create(null);
  874. var mMemFlags = Object.create(null);
  875. var mExtFlags = Object.create(null);
  876. var sRegMask = 0;
  877. for (var k in oFlags) {
  878. switch (k) {
  879. case "implicit":
  880. case "r8lo" :
  881. case "r8hi" :
  882. case "r16" :
  883. case "r32" :
  884. case "r64" :
  885. case "creg" :
  886. case "dreg" :
  887. case "sreg" :
  888. case "bnd" :
  889. case "st" :
  890. case "k" :
  891. case "mm" :
  892. case "xmm" :
  893. case "ymm" :
  894. case "zmm" : mFlags[k] = true; break;
  895. case "m8" :
  896. case "m16" :
  897. case "m32" :
  898. case "m48" :
  899. case "m64" :
  900. case "m80" :
  901. case "m128" :
  902. case "m256" :
  903. case "m512" :
  904. case "m1024" : mFlags.mem = true; mMemFlags[k] = true; break;
  905. case "mib" : mFlags.mem = true; mMemFlags.mib = true; break;
  906. case "mem" : mFlags.mem = true; mMemFlags.mAny = true; break;
  907. case "memBase" : mFlags.mem = true; mMemFlags.memBase = true; break;
  908. case "memDS" : mFlags.mem = true; mMemFlags.memDS = true; break;
  909. case "memES" : mFlags.mem = true; mMemFlags.memES = true; break;
  910. case "memZAX" : mFlags.mem = true; sRegMask |= 1 << 0; break;
  911. case "memZSI" : mFlags.mem = true; sRegMask |= 1 << 6; break;
  912. case "memZDI" : mFlags.mem = true; sRegMask |= 1 << 7; break;
  913. case "vm32x" : mFlags.vm = true; mMemFlags.vm32x = true; break;
  914. case "vm32y" : mFlags.vm = true; mMemFlags.vm32y = true; break;
  915. case "vm32z" : mFlags.vm = true; mMemFlags.vm32z = true; break;
  916. case "vm64x" : mFlags.vm = true; mMemFlags.vm64x = true; break;
  917. case "vm64y" : mFlags.vm = true; mMemFlags.vm64y = true; break;
  918. case "vm64z" : mFlags.vm = true; mMemFlags.vm64z = true; break;
  919. case "i4" :
  920. case "u4" :
  921. case "i8" :
  922. case "u8" :
  923. case "i16" :
  924. case "u16" :
  925. case "i32" :
  926. case "u32" :
  927. case "i64" :
  928. case "u64" : mFlags[k] = true; break;
  929. case "rel8" :
  930. case "rel32" :
  931. mFlags.i32 = true;
  932. mFlags.i64 = true;
  933. mFlags[k] = true;
  934. break;
  935. case "rel16" :
  936. mFlags.i32 = true;
  937. mFlags.i64 = true;
  938. mFlags.rel32 = true;
  939. break;
  940. default: {
  941. switch (k) {
  942. case "es" : mFlags.sreg = true; sRegMask |= 1 << 1; break;
  943. case "cs" : mFlags.sreg = true; sRegMask |= 1 << 2; break;
  944. case "ss" : mFlags.sreg = true; sRegMask |= 1 << 3; break;
  945. case "ds" : mFlags.sreg = true; sRegMask |= 1 << 4; break;
  946. case "fs" : mFlags.sreg = true; sRegMask |= 1 << 5; break;
  947. case "gs" : mFlags.sreg = true; sRegMask |= 1 << 6; break;
  948. case "al" : mFlags.r8lo = true; sRegMask |= 1 << 0; break;
  949. case "ah" : mFlags.r8hi = true; sRegMask |= 1 << 0; break;
  950. case "ax" : mFlags.r16 = true; sRegMask |= 1 << 0; break;
  951. case "eax" : mFlags.r32 = true; sRegMask |= 1 << 0; break;
  952. case "rax" : mFlags.r64 = true; sRegMask |= 1 << 0; break;
  953. case "cl" : mFlags.r8lo = true; sRegMask |= 1 << 1; break;
  954. case "ch" : mFlags.r8hi = true; sRegMask |= 1 << 1; break;
  955. case "cx" : mFlags.r16 = true; sRegMask |= 1 << 1; break;
  956. case "ecx" : mFlags.r32 = true; sRegMask |= 1 << 1; break;
  957. case "rcx" : mFlags.r64 = true; sRegMask |= 1 << 1; break;
  958. case "dl" : mFlags.r8lo = true; sRegMask |= 1 << 2; break;
  959. case "dh" : mFlags.r8hi = true; sRegMask |= 1 << 2; break;
  960. case "dx" : mFlags.r16 = true; sRegMask |= 1 << 2; break;
  961. case "edx" : mFlags.r32 = true; sRegMask |= 1 << 2; break;
  962. case "rdx" : mFlags.r64 = true; sRegMask |= 1 << 2; break;
  963. case "bl" : mFlags.r8lo = true; sRegMask |= 1 << 3; break;
  964. case "bh" : mFlags.r8hi = true; sRegMask |= 1 << 3; break;
  965. case "bx" : mFlags.r16 = true; sRegMask |= 1 << 3; break;
  966. case "ebx" : mFlags.r32 = true; sRegMask |= 1 << 3; break;
  967. case "rbx" : mFlags.r64 = true; sRegMask |= 1 << 3; break;
  968. case "si" : mFlags.r16 = true; sRegMask |= 1 << 6; break;
  969. case "esi" : mFlags.r32 = true; sRegMask |= 1 << 6; break;
  970. case "rsi" : mFlags.r64 = true; sRegMask |= 1 << 6; break;
  971. case "di" : mFlags.r16 = true; sRegMask |= 1 << 7; break;
  972. case "edi" : mFlags.r32 = true; sRegMask |= 1 << 7; break;
  973. case "rdi" : mFlags.r64 = true; sRegMask |= 1 << 7; break;
  974. case "st0" : mFlags.st = true; sRegMask |= 1 << 0; break;
  975. case "xmm0" : mFlags.xmm = true; sRegMask |= 1 << 0; break;
  976. case "ymm0" : mFlags.ymm = true; sRegMask |= 1 << 0; break;
  977. default:
  978. console.log(`UNKNOWN OPERAND '${k}'`);
  979. }
  980. }
  981. }
  982. }
  983. const sFlags = StringifyArray(ArrayUtils.sorted(mFlags , cmpOp), OpToAsmJitOp);
  984. const sMemFlags = StringifyArray(ArrayUtils.sorted(mMemFlags, cmpOp), OpToAsmJitOp);
  985. const sExtFlags = StringifyArray(ArrayUtils.sorted(mExtFlags, cmpOp), OpToAsmJitOp);
  986. return `ROW(${sFlags || 0}, ${sMemFlags || 0}, ${sExtFlags || 0}, ${decToHex(sRegMask, 2)})`;
  987. }
  988. }
  989. class ISignature extends Array {
  990. constructor(name) {
  991. super();
  992. this.name = name;
  993. this.x86 = false;
  994. this.x64 = false;
  995. this.implicit = 0; // Number of implicit operands.
  996. }
  997. simplify() {
  998. for (var i = 0; i < this.length; i++)
  999. this[i].simplify();
  1000. }
  1001. opEquals(other) {
  1002. const len = this.length;
  1003. if (len !== other.length) return false;
  1004. for (var i = 0; i < len; i++)
  1005. if (!this[i].equals(other[i]))
  1006. return false;
  1007. return true;
  1008. }
  1009. mergeWith(other) {
  1010. // If both architectures are the same, it's fine to merge.
  1011. var ok = this.x86 === other.x86 && this.x64 === other.x64;
  1012. // If the first arch is [X86|X64] and the second [X64] it's also fine.
  1013. if (!ok && this.x86 && this.x64 && !other.x86 && other.x64)
  1014. ok = true;
  1015. // It's not ok if both signatures have different number of implicit operands.
  1016. if (!ok || this.implicit !== other.implicit)
  1017. return false;
  1018. // It's not ok if both signatures have different number of operands.
  1019. const len = this.length;
  1020. if (len !== other.length)
  1021. return false;
  1022. var xorIndex = -1;
  1023. for (var i = 0; i < len; i++) {
  1024. const xor = this[i].xor(other[i]);
  1025. if (xor === null) continue;
  1026. if (xorIndex === -1)
  1027. xorIndex = i;
  1028. else
  1029. return false;
  1030. }
  1031. // Bail if mergeWidth at operand-level failed.
  1032. if (xorIndex !== -1 && !this[xorIndex].mergeWith(other[xorIndex]))
  1033. return false;
  1034. this.x86 = this.x86 || other.x86;
  1035. this.x64 = this.x64 || other.x64;
  1036. return true;
  1037. }
  1038. toString() {
  1039. return "{" + this.join(", ") + "}";
  1040. }
  1041. }
  1042. class SignatureArray extends Array {
  1043. // Iterate over all signatures and check which operands don't need explicit memory size.
  1044. calcImplicitMemSize() {
  1045. // Calculates a hash-value (aka key) of all register operands specified by `regOps` in `inst`.
  1046. function keyOf(inst, regOps) {
  1047. var s = "";
  1048. for (var i = 0; i < inst.length; i++) {
  1049. const op = inst[i];
  1050. if (regOps & (1 << i))
  1051. s += "{" + ArrayUtils.sorted(MapUtils.and(op.flags, RegOp)).join("|") + "}";
  1052. }
  1053. return s || "?";
  1054. }
  1055. var i;
  1056. var aIndex, bIndex;
  1057. for (aIndex = 0; aIndex < this.length; aIndex++) {
  1058. const aInst = this[aIndex];
  1059. const len = aInst.length;
  1060. var memOp = "";
  1061. var memPos = -1;
  1062. var regOps = 0;
  1063. // Check if this instruction signature has a memory operand of explicit size.
  1064. for (i = 0; i < len; i++) {
  1065. const aOp = aInst[i];
  1066. const mem = MapUtils.firstOf(aOp.flags, MemOp);
  1067. if (mem) {
  1068. // Stop if the memory operand has implicit-size or if there is more than one.
  1069. if (aOp.flags.mem || memPos >= 0) {
  1070. memPos = -1;
  1071. break;
  1072. }
  1073. else {
  1074. memOp = mem;
  1075. memPos = i;
  1076. }
  1077. }
  1078. else if (MapUtils.anyOf(aOp.flags, RegOp)) {
  1079. // Doesn't consider 'r/m' as we already checked 'm'.
  1080. regOps |= (1 << i);
  1081. }
  1082. }
  1083. if (memPos < 0)
  1084. continue;
  1085. // Create a `sameSizeSet` set of all instructions having the exact
  1086. // explicit memory operand at the same position and registers at
  1087. // positions matching `regOps` bits and `diffSizeSet` having memory
  1088. // operand of different size, but registers at the same positions.
  1089. const sameSizeSet = [aInst];
  1090. const diffSizeSet = [];
  1091. const diffSizeHash = Object.create(null);
  1092. for (bIndex = 0; bIndex < this.length; bIndex++) {
  1093. const bInst = this[bIndex];
  1094. if (aIndex === bIndex || len !== bInst.length) continue;
  1095. var hasMatch = 1;
  1096. for (i = 0; i < len; i++) {
  1097. if (i === memPos) continue;
  1098. const reg = MapUtils.anyOf(bInst[i].flags, RegOp);
  1099. if (regOps & (1 << i))
  1100. hasMatch &= reg;
  1101. else if (reg)
  1102. hasMatch = 0;
  1103. }
  1104. if (hasMatch) {
  1105. const bOp = bInst[memPos];
  1106. if (bOp.flags.mem) continue;
  1107. const mem = MapUtils.firstOf(bOp.flags, MemOp);
  1108. if (mem === memOp) {
  1109. sameSizeSet.push(bInst);
  1110. }
  1111. else if (mem) {
  1112. const key = keyOf(bInst, regOps);
  1113. diffSizeSet.push(bInst);
  1114. if (!diffSizeHash[key])
  1115. diffSizeHash[key] = [bInst];
  1116. else
  1117. diffSizeHash[key].push(bInst);
  1118. }
  1119. }
  1120. }
  1121. // Two cases.
  1122. // A) The memory operand has implicit-size if `diffSizeSet` is empty. That
  1123. // means that the instruction only uses one size for all reg combinations.
  1124. //
  1125. // B) The memory operand has implicit-size if `diffSizeSet` contains different
  1126. // register signatures than `sameSizeSet`.
  1127. var implicit = true;
  1128. if (!diffSizeSet.length) {
  1129. // Case A:
  1130. }
  1131. else {
  1132. // Case B: Find collisions in `sameSizeSet` and `diffSizeSet`.
  1133. for (bIndex = 0; bIndex < sameSizeSet.length; bIndex++) {
  1134. const bInst = sameSizeSet[bIndex];
  1135. const key = keyOf(bInst, regOps);
  1136. const diff = diffSizeHash[key];
  1137. if (diff) {
  1138. diff.forEach((diffInst) => {
  1139. if ((bInst.x86 && !diffInst.x86) || (!bInst.x86 && diffInst.x86)) {
  1140. // If this is X86|ANY instruction and the other is X64, or vice-versa,
  1141. // then keep this implicit as it won't do any harm. These instructions
  1142. // cannot be mixed and it will make implicit the 32-bit one in cases
  1143. // where X64 introduced 64-bit ones like `cvtsi2ss`.
  1144. }
  1145. else {
  1146. implicit = false;
  1147. }
  1148. });
  1149. }
  1150. }
  1151. }
  1152. // Patch all instructions to accept implicit-size memory operand.
  1153. for (bIndex = 0; bIndex < sameSizeSet.length; bIndex++) {
  1154. const bInst = sameSizeSet[bIndex];
  1155. if (implicit) bInst[memPos].flags.mem = true;
  1156. if (!implicit)
  1157. DEBUG(`${this.name}: Explicit: ${bInst}`);
  1158. }
  1159. }
  1160. }
  1161. simplify() {
  1162. for (var i = 0; i < this.length; i++)
  1163. this[i].simplify();
  1164. }
  1165. compact() {
  1166. for (var i = 0; i < this.length; i++) {
  1167. var row = this[i];
  1168. var j = i + 1;
  1169. while (j < this.length) {
  1170. if (row.mergeWith(this[j])) {
  1171. this.splice(j, 1);
  1172. continue;
  1173. }
  1174. j++;
  1175. }
  1176. }
  1177. }
  1178. toString() {
  1179. return `[${this.join(", ")}]`;
  1180. }
  1181. }
  1182. class InstSignatureTable extends core.Task {
  1183. constructor() {
  1184. super("InstSignatureTable");
  1185. this.maxOpRows = 0;
  1186. this.opBlackList = {
  1187. "moff8" : true,
  1188. "moff16": true,
  1189. "moff32": true,
  1190. "moff64": true
  1191. };
  1192. }
  1193. run() {
  1194. const insts = this.ctx.insts;
  1195. insts.forEach((inst) => {
  1196. inst.signatures = this.makeSignatures(Filter.noAltForm(inst.dbInsts));
  1197. this.maxOpRows = Math.max(this.maxOpRows, inst.signatures.length);
  1198. });
  1199. const iSignatureMap = Object.create(null);
  1200. const iSignatureArr = [];
  1201. const oSignatureMap = Object.create(null);
  1202. const oSignatureArr = [];
  1203. // Must be first to be assigned to zero.
  1204. const oSignatureNone = "ROW(0, 0, 0, 0xFF)";
  1205. oSignatureMap[oSignatureNone] = [0];
  1206. oSignatureArr.push(oSignatureNone);
  1207. function findSignaturesIndex(rows) {
  1208. const len = rows.length;
  1209. if (!len) return 0;
  1210. const indexes = iSignatureMap[rows[0].data];
  1211. if (indexes === undefined) return -1;
  1212. for (var i = 0; i < indexes.length; i++) {
  1213. const index = indexes[i];
  1214. if (index + len > iSignatureArr.length) continue;
  1215. var ok = true;
  1216. for (var j = 0; j < len; j++) {
  1217. if (iSignatureArr[index + j].data !== rows[j].data) {
  1218. ok = false;
  1219. break;
  1220. }
  1221. }
  1222. if (ok)
  1223. return index;
  1224. }
  1225. return -1;
  1226. }
  1227. function indexSignatures(signatures) {
  1228. const result = iSignatureArr.length;
  1229. for (var i = 0; i < signatures.length; i++) {
  1230. const signature = signatures[i];
  1231. const idx = iSignatureArr.length;
  1232. if (!hasOwn.call(iSignatureMap, signature.data))
  1233. iSignatureMap[signature.data] = [];
  1234. iSignatureMap[signature.data].push(idx);
  1235. iSignatureArr.push(signature);
  1236. }
  1237. return result;
  1238. }
  1239. for (var len = this.maxOpRows; len >= 0; len--) {
  1240. insts.forEach((inst) => {
  1241. const signatures = inst.signatures;
  1242. if (signatures.length === len) {
  1243. const signatureEntries = [];
  1244. for (var j = 0; j < len; j++) {
  1245. const signature = signatures[j];
  1246. var signatureEntry = `ROW(${signature.length}, ${signature.x86 ? 1 : 0}, ${signature.x64 ? 1 : 0}, ${signature.implicit}`;
  1247. var signatureComment = signature.toString();
  1248. var x = 0;
  1249. while (x < signature.length) {
  1250. const h = signature[x].toAsmJitOpData();
  1251. var index = -1;
  1252. if (!hasOwn.call(oSignatureMap, h)) {
  1253. index = oSignatureArr.length;
  1254. oSignatureMap[h] = index;
  1255. oSignatureArr.push(h);
  1256. }
  1257. else {
  1258. index = oSignatureMap[h];
  1259. }
  1260. signatureEntry += `, ${String(index).padEnd(3)}`;
  1261. x++;
  1262. }
  1263. while (x < 6) {
  1264. signatureEntry += `, ${String(0).padEnd(3)}`;
  1265. x++;
  1266. }
  1267. signatureEntry += `)`;
  1268. signatureEntries.push({ data: signatureEntry, comment: signatureComment, refs: 0 });
  1269. }
  1270. var count = signatureEntries.length;
  1271. var index = findSignaturesIndex(signatureEntries);
  1272. if (index === -1)
  1273. index = indexSignatures(signatureEntries);
  1274. iSignatureArr[index].refs++;
  1275. inst.signatureIndex = index;
  1276. inst.signatureCount = count;
  1277. }
  1278. });
  1279. }
  1280. var s = `#define ROW(count, x86, x64, implicit, o0, o1, o2, o3, o4, o5) \\\n` +
  1281. ` { count, (x86 ? uint8_t(InstDB::kModeX86) : uint8_t(0)) | \\\n` +
  1282. ` (x64 ? uint8_t(InstDB::kModeX64) : uint8_t(0)) , \\\n` +
  1283. ` implicit, \\\n` +
  1284. ` 0, \\\n` +
  1285. ` { o0, o1, o2, o3, o4, o5 } \\\n` +
  1286. ` }\n` +
  1287. StringUtils.makeCxxArrayWithComment(iSignatureArr, "const InstDB::InstSignature InstDB::_instSignatureTable[]") +
  1288. `#undef ROW\n` +
  1289. `\n` +
  1290. `#define ROW(flags, mFlags, extFlags, regId) { uint32_t(flags), uint16_t(mFlags), uint8_t(extFlags), uint8_t(regId) }\n` +
  1291. `#define F(VAL) InstDB::kOp##VAL\n` +
  1292. `#define M(VAL) InstDB::kMemOp##VAL\n` +
  1293. StringUtils.makeCxxArray(oSignatureArr, "const InstDB::OpSignature InstDB::_opSignatureTable[]") +
  1294. `#undef M\n` +
  1295. `#undef F\n` +
  1296. `#undef ROW\n`;
  1297. this.inject("InstSignatureTable", disclaimer(s), oSignatureArr.length * 8 + iSignatureArr.length * 8);
  1298. }
  1299. makeSignatures(dbInsts) {
  1300. const signatures = new SignatureArray();
  1301. for (var i = 0; i < dbInsts.length; i++) {
  1302. const inst = dbInsts[i];
  1303. const ops = inst.operands;
  1304. // NOTE: This changed from having reg|mem merged into creating two signatures
  1305. // instead. Imagine two instructions in one `dbInsts` array:
  1306. //
  1307. // 1. mov reg, reg/mem
  1308. // 2. mov reg/mem, reg
  1309. //
  1310. // If we merge them and then unmerge, we will have 4 signatures, when iterated:
  1311. //
  1312. // 1a. mov reg, reg
  1313. // 1b. mov reg, mem
  1314. // 2a. mov reg, reg
  1315. // 2b. mov mem, reg
  1316. //
  1317. // So, instead of merging them here, we insert separated signatures and let
  1318. // the tool merge them in a way that can be easily unmerged at runtime into:
  1319. //
  1320. // 1a. mov reg, reg
  1321. // 1b. mov reg, mem
  1322. // 2b. mov mem, reg
  1323. var modrmCount = 1;
  1324. for (var modrm = 0; modrm < modrmCount; modrm++) {
  1325. var row = new ISignature(inst.name);
  1326. row.x86 = (inst.arch === "ANY" || inst.arch === "X86");
  1327. row.x64 = (inst.arch === "ANY" || inst.arch === "X64");
  1328. for (var j = 0; j < ops.length; j++) {
  1329. var iop = ops[j];
  1330. var reg = iop.reg;
  1331. var mem = iop.mem;
  1332. var imm = iop.imm;
  1333. var rel = iop.rel;
  1334. // Terminate if this operand is something asmjit doesn't support
  1335. // and skip all instructions having implicit `imm` operand of `1`,
  1336. // which are handled fine by asmjit.
  1337. if (this.opBlackList[mem] === true || iop.immValue !== null)
  1338. break;
  1339. if (reg === "r8") reg = "r8lo";
  1340. if (reg === "seg") reg = "sreg";
  1341. if (reg === "st(i)") reg = "st";
  1342. if (reg === "st(0)") reg = "st0";
  1343. if (mem === "m32fp") mem = "m32";
  1344. if (mem === "m64fp") mem = "m64";
  1345. if (mem === "m80fp") mem = "m80";
  1346. if (mem === "m80bcd") mem = "m80";
  1347. if (mem === "m80dec") mem = "m80";
  1348. if (mem === "m16int") mem = "m16";
  1349. if (mem === "m32int") mem = "m32";
  1350. if (mem === "m64int") mem = "m64";
  1351. if (mem === "m16_16") mem = "m32";
  1352. if (mem === "m16_32") mem = "m48";
  1353. if (mem === "m16_64") mem = "m80";
  1354. if (reg && mem) {
  1355. if (modrmCount === 1) {
  1356. mem = null;
  1357. modrmCount++;
  1358. }
  1359. else {
  1360. reg = null;
  1361. }
  1362. }
  1363. const op = new OSignature();
  1364. if (iop.implicit) {
  1365. row.implicit++;
  1366. op.flags.implicit = true;
  1367. }
  1368. const seg = iop.memSeg;
  1369. if (seg) {
  1370. if (seg === "ds") op.flags.memDS = true;
  1371. if (seg === "es") op.flags.memES = true;
  1372. if (reg === "reg") { op.flags.memBase = true; }
  1373. if (reg === "r32") { op.flags.memBase = true; }
  1374. if (reg === "r64") { op.flags.memBase = true; }
  1375. if (reg === "zax") { op.flags.memBase = true; op.flags.memZAX = true; }
  1376. if (reg === "zsi") { op.flags.memBase = true; op.flags.memZSI = true; }
  1377. if (reg === "zdi") { op.flags.memBase = true; op.flags.memZDI = true; }
  1378. }
  1379. else if (reg) {
  1380. op.flags[reg] = true;
  1381. if (reg === "r8lo") op.flags.r8hi = true;
  1382. }
  1383. if (mem) {
  1384. op.flags[mem] = true;
  1385. // Exception: Allow LEA to use any memory size.
  1386. if (inst.name === "lea") MapUtils.add(op.flags, MemOp);
  1387. }
  1388. if (imm) {
  1389. if (iop.immSign === "any" || iop.immSign === "signed" ) op.flags["i" + imm] = true;
  1390. if (iop.immSign === "any" || iop.immSign === "unsigned") op.flags["u" + imm] = true;
  1391. }
  1392. if (rel) op.flags["rel" + rel] = true;
  1393. row.push(op);
  1394. }
  1395. // Not equal if we terminated the loop.
  1396. if (j === ops.length)
  1397. signatures.push(row);
  1398. }
  1399. }
  1400. signatures.calcImplicitMemSize();
  1401. signatures.simplify();
  1402. signatures.compact();
  1403. signatures.simplify();
  1404. signatures.compact();
  1405. return signatures;
  1406. }
  1407. }
  1408. // ============================================================================
  1409. // [tablegen.x86.InstCommonInfoTableB]
  1410. // ============================================================================
  1411. class InstCommonInfoTableB extends core.Task {
  1412. constructor() {
  1413. super("InstCommonInfoTableB");
  1414. }
  1415. run() {
  1416. const insts = this.ctx.insts;
  1417. const commonTableB = new IndexedArray();
  1418. const rwInfoTable = new IndexedArray();
  1419. // If the instruction doesn't read any flags it should point to the first index.
  1420. rwInfoTable.addIndexed(`{ 0, 0 }`);
  1421. insts.forEach((inst) => {
  1422. const dbInsts = inst.dbInsts;
  1423. var features = GenUtils.cpuFeaturesOf(dbInsts).map(function(f) { return `EXT(${f})`; }).join(", ");
  1424. if (!features) features = "0";
  1425. var [r, w] = this.rwFlagsOf(dbInsts);
  1426. const rData = r.map(function(flag) { return `FLAG(${flag})`; }).join(" | ") || "0";
  1427. const wData = w.map(function(flag) { return `FLAG(${flag})`; }).join(" | ") || "0";
  1428. const rwDataIndex = rwInfoTable.addIndexed(`{ ${rData}, ${wData} }`);
  1429. inst.commomInfoIndexB = commonTableB.addIndexed(`{ { ${features} }, ${rwDataIndex}, 0 }`);
  1430. });
  1431. var s = `#define EXT(VAL) uint32_t(Features::k##VAL)\n` +
  1432. `const InstDB::CommonInfoTableB InstDB::_commonInfoTableB[] = {\n${StringUtils.format(commonTableB, kIndent, true)}\n};\n` +
  1433. `#undef EXT\n` +
  1434. `\n` +
  1435. `#define FLAG(VAL) uint32_t(Status::k##VAL)\n` +
  1436. `const InstDB::RWFlagsInfoTable InstDB::_rwFlagsInfoTable[] = {\n${StringUtils.format(rwInfoTable, kIndent, true)}\n};\n` +
  1437. `#undef FLAG\n`;
  1438. this.inject("InstCommonInfoTableB", disclaimer(s), commonTableB.length * 8 + rwInfoTable.length * 8);
  1439. }
  1440. rwFlagsOf(dbInsts) {
  1441. const r = Object.create(null);
  1442. const w = Object.create(null);
  1443. for (var i = 0; i < dbInsts.length; i++) {
  1444. const dbInst = dbInsts[i];
  1445. // Omit special cases, this is handled well in C++ code.
  1446. if (dbInst.name === "mov")
  1447. continue;
  1448. const specialRegs = dbInst.specialRegs;
  1449. // Mov is a special case, moving to/from control regs makes flags undefined,
  1450. // which we don't want to have in `X86InstDB::operationData`. This is, thus,
  1451. // a special case instruction analyzer must deal with.
  1452. if (dbInst.name === "mov")
  1453. continue;
  1454. for (var specialReg in specialRegs) {
  1455. var flag = "";
  1456. switch (specialReg) {
  1457. case "FLAGS.CF": flag = "CF"; break;
  1458. case "FLAGS.OF": flag = "OF"; break;
  1459. case "FLAGS.SF": flag = "SF"; break;
  1460. case "FLAGS.ZF": flag = "ZF"; break;
  1461. case "FLAGS.AF": flag = "AF"; break;
  1462. case "FLAGS.PF": flag = "PF"; break;
  1463. case "FLAGS.DF": flag = "DF"; break;
  1464. case "FLAGS.IF": flag = "IF"; break;
  1465. //case "FLAGS.TF": flag = "TF"; break;
  1466. case "FLAGS.AC": flag = "AC"; break;
  1467. case "X86SW.C0": flag = "C0"; break;
  1468. case "X86SW.C1": flag = "C1"; break;
  1469. case "X86SW.C2": flag = "C2"; break;
  1470. case "X86SW.C3": flag = "C3"; break;
  1471. default:
  1472. continue;
  1473. }
  1474. switch (specialRegs[specialReg]) {
  1475. case "R":
  1476. r[flag] = true;
  1477. break;
  1478. case "X":
  1479. r[flag] = true;
  1480. // ... fallthrough ...
  1481. case "W":
  1482. case "U":
  1483. case "0":
  1484. case "1":
  1485. w[flag] = true;
  1486. break;
  1487. }
  1488. }
  1489. }
  1490. return [ArrayUtils.sorted(r), ArrayUtils.sorted(w)];
  1491. }
  1492. }
  1493. // ============================================================================
  1494. // [tablegen.x86.InstRWInfoTable]
  1495. // ============================================================================
  1496. const NOT_MEM_AMBIGUOUS = MapUtils.arrayToMap([
  1497. "call", "movq"
  1498. ]);
  1499. class InstRWInfoTable extends core.Task {
  1500. constructor() {
  1501. super("InstRWInfoTable");
  1502. this.rwInfoIndex = [];
  1503. this.rwInfoTable = new IndexedArray();
  1504. this.rmInfoTable = new IndexedArray();
  1505. this.opInfoTable = new IndexedArray();
  1506. const _ = null;
  1507. this.rwCategoryByName = {
  1508. "imul" : "Imul",
  1509. "mov" : "Mov",
  1510. "movhpd" : "Movh64",
  1511. "movhps" : "Movh64",
  1512. "vmaskmovpd": "Vmaskmov",
  1513. "vmaskmovps": "Vmaskmov",
  1514. "vmovddup" : "Vmovddup",
  1515. "vmovmskpd" : "Vmovmskpd",
  1516. "vmovmskps" : "Vmovmskps",
  1517. "vpmaskmovd": "Vmaskmov",
  1518. "vpmaskmovq": "Vmaskmov"
  1519. };
  1520. this.rwCategoryByData = {
  1521. Vmov1_8: [
  1522. [{access: "W", flags: {}, fixed: -1, index: 0, width: 8}, {access: "R", flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_],
  1523. [{access: "W", flags: {}, fixed: -1, index: 0, width: 16}, {access: "R", flags: {}, fixed: -1, index: 0, width:128},_,_,_,_],
  1524. [{access: "W", flags: {}, fixed: -1, index: 0, width: 32}, {access: "R", flags: {}, fixed: -1, index: 0, width:256},_,_,_,_],
  1525. [{access: "W", flags: {}, fixed: -1, index: 0, width: 64}, {access: "R", flags: {}, fixed: -1, index: 0, width:512},_,_,_,_]
  1526. ],
  1527. Vmov1_4: [
  1528. [{access: "W", flags: {}, fixed: -1, index: 0, width: 32}, {access: "R", flags: {}, fixed: -1, index: 0, width:128},_,_,_,_],
  1529. [{access: "W", flags: {}, fixed: -1, index: 0, width: 64}, {access: "R", flags: {}, fixed: -1, index: 0, width:256},_,_,_,_],
  1530. [{access: "W", flags: {}, fixed: -1, index: 0, width:128}, {access: "R", flags: {}, fixed: -1, index: 0, width:512},_,_,_,_]
  1531. ],
  1532. Vmov1_2: [
  1533. [{access: "W", flags: {}, fixed: -1, index: 0, width: 64}, {access: "R", flags: {}, fixed: -1, index: 0, width:128},_,_,_,_],
  1534. [{access: "W", flags: {}, fixed: -1, index: 0, width:128}, {access: "R", flags: {}, fixed: -1, index: 0, width:256},_,_,_,_],
  1535. [{access: "W", flags: {}, fixed: -1, index: 0, width:256}, {access: "R", flags: {}, fixed: -1, index: 0, width:512},_,_,_,_]
  1536. ],
  1537. Vmov2_1: [
  1538. [{access: "W", flags: {}, fixed: -1, index: 0, width: 128}, {access: "R", flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_],
  1539. [{access: "W", flags: {}, fixed: -1, index: 0, width: 256}, {access: "R", flags: {}, fixed: -1, index: 0, width:128},_,_,_,_],
  1540. [{access: "W", flags: {}, fixed: -1, index: 0, width: 512}, {access: "R", flags: {}, fixed: -1, index: 0, width:256},_,_,_,_]
  1541. ],
  1542. Vmov4_1: [
  1543. [{access: "W", flags: {}, fixed: -1, index: 0, width: 128}, {access: "R", flags: {}, fixed: -1, index: 0, width: 32},_,_,_,_],
  1544. [{access: "W", flags: {}, fixed: -1, index: 0, width: 256}, {access: "R", flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_],
  1545. [{access: "W", flags: {}, fixed: -1, index: 0, width: 512}, {access: "R", flags: {}, fixed: -1, index: 0, width:128},_,_,_,_]
  1546. ],
  1547. Vmov8_1: [
  1548. [{access: "W", flags: {}, fixed: -1, index: 0, width: 128}, {access: "R", flags: {}, fixed: -1, index: 0, width: 16},_,_,_,_],
  1549. [{access: "W", flags: {}, fixed: -1, index: 0, width: 256}, {access: "R", flags: {}, fixed: -1, index: 0, width: 32},_,_,_,_],
  1550. [{access: "W", flags: {}, fixed: -1, index: 0, width: 512}, {access: "R", flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_]
  1551. ]
  1552. };
  1553. }
  1554. run() {
  1555. const insts = this.ctx.insts;
  1556. const noRmInfo = CxxUtils.struct(
  1557. "InstDB::RWInfoRm::kCategory" + "None".padEnd(10),
  1558. StringUtils.decToHex(0, 2),
  1559. String(0).padEnd(2),
  1560. CxxUtils.flags({}),
  1561. "0"
  1562. );
  1563. const noOpInfo = CxxUtils.struct(
  1564. "0x0000000000000000u",
  1565. "0x0000000000000000u",
  1566. "0xFF",
  1567. CxxUtils.struct(0),
  1568. "0"
  1569. );
  1570. this.rmInfoTable.addIndexed(noRmInfo);
  1571. this.opInfoTable.addIndexed(noOpInfo);
  1572. insts.forEach((inst) => {
  1573. // Alternate forms would only mess this up, so filter them out.
  1574. const dbInsts = Filter.noAltForm(inst.dbInsts);
  1575. // The best we can do is to divide instructions that have 2 operands and others.
  1576. // This gives us the highest chance of preventing special cases (which were not
  1577. // entirely avoided).
  1578. const o2Insts = dbInsts.filter((inst) => { return inst.operands.length === 2; });
  1579. const oxInsts = dbInsts.filter((inst) => { return inst.operands.length !== 2; });
  1580. const rwInfoArray = [this.rwInfo(o2Insts), this.rwInfo(oxInsts)];
  1581. const rmInfoArray = [this.rmInfo(o2Insts), this.rmInfo(oxInsts)];
  1582. for (var i = 0; i < 2; i++) {
  1583. const rwInfo = rwInfoArray[i];
  1584. const rmInfo = rmInfoArray[i];
  1585. const rwOps = rwInfo.rwOps;
  1586. const rwOpsIndex = [];
  1587. for (var j = 0; j < rwOps.length; j++) {
  1588. const op = rwOps[j];
  1589. if (!op) {
  1590. rwOpsIndex.push(this.opInfoTable.addIndexed(noOpInfo));
  1591. continue;
  1592. }
  1593. const flags = {};
  1594. const opAcc = op.access;
  1595. if (opAcc === "R") flags.Read = true;
  1596. if (opAcc === "W") flags.Write = true;
  1597. if (opAcc === "X") flags.RW = true;
  1598. Lang.merge(flags, op.flags);
  1599. const rIndex = opAcc === "X" || opAcc === "R" ? op.index : -1;
  1600. const rWidth = opAcc === "X" || opAcc === "R" ? op.width : -1;
  1601. const wIndex = opAcc === "X" || opAcc === "W" ? op.index : -1;
  1602. const wWidth = opAcc === "X" || opAcc === "W" ? op.width : -1;
  1603. const opData = CxxUtils.struct(
  1604. this.byteMaskFromBitRanges([{ start: rIndex, end: rIndex + rWidth - 1 }]) + "u",
  1605. this.byteMaskFromBitRanges([{ start: wIndex, end: wIndex + wWidth - 1 }]) + "u",
  1606. StringUtils.decToHex(op.fixed === -1 ? 0xFF : op.fixed, 2),
  1607. CxxUtils.struct(0),
  1608. CxxUtils.flags(flags, function(flag) { return "OpRWInfo::k" + flag; })
  1609. );
  1610. rwOpsIndex.push(this.opInfoTable.addIndexed(opData));
  1611. }
  1612. const rmData = CxxUtils.struct(
  1613. "InstDB::RWInfoRm::kCategory" + rmInfo.category.padEnd(10),
  1614. StringUtils.decToHex(rmInfo.rmIndexes, 2),
  1615. String(Math.max(rmInfo.memFixed, 0)).padEnd(2),
  1616. CxxUtils.flags({ "InstDB::RWInfoRm::kFlagAmbiguous": Boolean(rmInfo.memAmbiguous) }),
  1617. rmInfo.memExtension === "None" ? "0" : "Features::k" + rmInfo.memExtension
  1618. );
  1619. const rwData = CxxUtils.struct(
  1620. "InstDB::RWInfo::kCategory" + rwInfo.category.padEnd(10),
  1621. String(this.rmInfoTable.addIndexed(rmData)).padEnd(2),
  1622. CxxUtils.struct(...(rwOpsIndex.map(function(item) { return String(item).padEnd(2); })))
  1623. );
  1624. this.rwInfoIndex.push(this.rwInfoTable.addIndexed(rwData));
  1625. }
  1626. });
  1627. var s = "";
  1628. s += "const uint8_t InstDB::rwInfoIndex[Inst::_kIdCount * 2] = {\n" + StringUtils.format(this.rwInfoIndex, kIndent, -1) + "\n};\n";
  1629. s += "\n";
  1630. s += "const InstDB::RWInfo InstDB::rwInfo[] = {\n" + StringUtils.format(this.rwInfoTable, kIndent, true) + "\n};\n";
  1631. s += "\n";
  1632. s += "const InstDB::RWInfoOp InstDB::rwInfoOp[] = {\n" + StringUtils.format(this.opInfoTable, kIndent, true) + "\n};\n";
  1633. s += "\n";
  1634. s += "const InstDB::RWInfoRm InstDB::rwInfoRm[] = {\n" + StringUtils.format(this.rmInfoTable, kIndent, true) + "\n};\n";
  1635. const size = this.rwInfoIndex.length +
  1636. this.rwInfoTable.length * 8 +
  1637. this.rmInfoTable.length * 4 +
  1638. this.opInfoTable.length * 24;
  1639. this.inject("InstRWInfoTable", disclaimer(s), size);
  1640. }
  1641. byteMaskFromBitRanges(ranges) {
  1642. const arr = [];
  1643. for (var i = 0; i < 64; i++)
  1644. arr.push(0);
  1645. for (var i = 0; i < ranges.length; i++) {
  1646. const start = ranges[i].start;
  1647. const end = ranges[i].end;
  1648. if (start < 0)
  1649. continue;
  1650. for (var j = start; j <= end; j++) {
  1651. const bytePos = j >> 3;
  1652. if (bytePos < 0 || bytePos >= arr.length)
  1653. FAIL(`Range ${start}:${end} cannot be used to create a byte-mask`);
  1654. arr[bytePos] = 1;
  1655. }
  1656. }
  1657. var s = "0x";
  1658. for (var i = arr.length - 4; i >= 0; i -= 4) {
  1659. const value = (arr[i + 3] << 3) | (arr[i + 2] << 2) | (arr[i + 1] << 1) | arr[i];
  1660. s += value.toString(16).toUpperCase();
  1661. }
  1662. return s;
  1663. }
  1664. // Read/Write Info
  1665. // ---------------
  1666. rwInfo(dbInsts) {
  1667. function nullOps() {
  1668. return [null, null, null, null, null, null];
  1669. }
  1670. function makeRwFromOp(op) {
  1671. if (!op.isRegOrMem())
  1672. return null;
  1673. return {
  1674. access: op.read && op.write ? "X" : op.read ? "R" : op.write ? "W" : "?",
  1675. flags: {},
  1676. fixed: GenUtils.fixedRegOf(op.reg),
  1677. index: op.rwxIndex,
  1678. width: op.rwxWidth
  1679. };
  1680. }
  1681. function queryRwGeneric(dbInsts, step) {
  1682. var rwOps = nullOps();
  1683. for (var i = 0; i < dbInsts.length; i++) {
  1684. const dbInst = dbInsts[i];
  1685. const operands = dbInst.operands;
  1686. for (var j = 0; j < operands.length; j++) {
  1687. const op = operands[j];
  1688. if (!op.isRegOrMem())
  1689. continue;
  1690. const opSize = op.isReg() ? op.regSize : op.memSize;
  1691. var d = {
  1692. access: op.read && op.write ? "X" : op.read ? "R" : op.write ? "W" : "?",
  1693. flags: {},
  1694. fixed: -1,
  1695. index: -1,
  1696. width: -1
  1697. };
  1698. if (op.isReg())
  1699. d.fixed = GenUtils.fixedRegOf(op.reg);
  1700. else
  1701. d.fixed = GenUtils.fixedRegOf(op.mem);
  1702. if (op.zext)
  1703. d.flags.ZExt = true;
  1704. if ((step === -1 || step === j) || op.rwxIndex !== 0 || op.rwxWidth !== opSize) {
  1705. d.index = op.rwxIndex;
  1706. d.width = op.rwxWidth;
  1707. }
  1708. if (d.fixed !== -1) {
  1709. if (op.memSeg)
  1710. d.flags.MemPhysId = true;
  1711. else
  1712. d.flags.RegPhysId = true;
  1713. }
  1714. if (rwOps[j] === null) {
  1715. rwOps[j] = d;
  1716. }
  1717. else {
  1718. if (!Lang.deepEqExcept(rwOps[j], d, { "fixed": true, "flags": true }))
  1719. return null;
  1720. if (rwOps[j].fixed === -1)
  1721. rwOps[j].fixed = d.fixed;
  1722. Lang.merge(rwOps[j].flags, d.flags);
  1723. }
  1724. }
  1725. }
  1726. return { category: "Generic", rwOps };
  1727. }
  1728. function queryRwByData(dbInsts, rwOpsArray) {
  1729. for (var i = 0; i < dbInsts.length; i++) {
  1730. const dbInst = dbInsts[i];
  1731. const operands = dbInst.operands;
  1732. const rwOps = nullOps();
  1733. for (var j = 0; j < operands.length; j++)
  1734. rwOps[j] = makeRwFromOp(operands[j])
  1735. var match = 0;
  1736. for (var j = 0; j < rwOpsArray.length; j++)
  1737. match |= Lang.deepEq(rwOps, rwOpsArray[j]);
  1738. if (!match)
  1739. return false;
  1740. }
  1741. return true;
  1742. }
  1743. function dumpRwToData(dbInsts) {
  1744. const out = [];
  1745. for (var i = 0; i < dbInsts.length; i++) {
  1746. const dbInst = dbInsts[i];
  1747. const operands = dbInst.operands;
  1748. const rwOps = nullOps();
  1749. for (var j = 0; j < operands.length; j++)
  1750. rwOps[j] = makeRwFromOp(operands[j])
  1751. if (ArrayUtils.deepIndexOf(out, rwOps) !== -1)
  1752. continue;
  1753. out.push(rwOps);
  1754. }
  1755. return out;
  1756. }
  1757. // Some instructions are just special...
  1758. const name = dbInsts.length ? dbInsts[0].name : "";
  1759. if (name in this.rwCategoryByName)
  1760. return { category: this.rwCategoryByName[name], rwOps: nullOps() };
  1761. // Generic rules.
  1762. for (var i = -1; i <= 6; i++) {
  1763. const rwInfo = queryRwGeneric(dbInsts, i);
  1764. if (rwInfo)
  1765. return rwInfo;
  1766. }
  1767. // Specific rules.
  1768. for (var k in this.rwCategoryByData)
  1769. if (queryRwByData(dbInsts, this.rwCategoryByData[k]))
  1770. return { category: k, rwOps: nullOps() };
  1771. // FAILURE: Missing data to categorize this instruction.
  1772. if (name) {
  1773. const items = dumpRwToData(dbInsts)
  1774. console.log(`RW: ${dbInsts.length ? dbInsts[0].name : ""}:`);
  1775. items.forEach((item) => {
  1776. console.log(" " + JSON.stringify(item));
  1777. });
  1778. }
  1779. return null;
  1780. }
  1781. // Reg/Mem Info
  1782. // ------------
  1783. rmInfo(dbInsts) {
  1784. const info = {
  1785. category: "None",
  1786. rmIndexes: this.rmReplaceableIndexes(dbInsts),
  1787. memFixed: this.rmFixedSize(dbInsts),
  1788. memAmbiguous: this.rmIsAmbiguous(dbInsts),
  1789. memConsistent: this.rmIsConsistent(dbInsts),
  1790. memExtension: this.rmExtension(dbInsts)
  1791. };
  1792. if (info.memFixed !== -1)
  1793. info.category = "Fixed";
  1794. else if (info.memConsistent)
  1795. info.category = "Consistent";
  1796. else if (info.rmIndexes)
  1797. info.category = this.rmReplaceableCategory(dbInsts);
  1798. return info;
  1799. }
  1800. rmReplaceableCategory(dbInsts) {
  1801. var category = null;
  1802. for (var i = 0; i < dbInsts.length; i++) {
  1803. const dbInst = dbInsts[i];
  1804. const operands = dbInst.operands;
  1805. var rs = -1;
  1806. var ms = -1;
  1807. for (var j = 0; j < operands.length; j++) {
  1808. const op = operands[j];
  1809. if (op.isMem())
  1810. ms = op.memSize;
  1811. else if (op.isReg())
  1812. rs = Math.max(rs, op.regSize);
  1813. }
  1814. var c = (rs === -1 ) ? "None" :
  1815. (ms === -1 ) ? "None" :
  1816. (ms === rs ) ? "Fixed" :
  1817. (ms === rs / 2) ? "Half" :
  1818. (ms === rs / 4) ? "Quarter" :
  1819. (ms === rs / 8) ? "Eighth" : "Unknown";
  1820. if (category === null)
  1821. category = c;
  1822. else if (category !== c) {
  1823. if (dbInst.name === "mov" || dbInst.name === "vmovddup")
  1824. return "None"; // Special case
  1825. return StringUtils.capitalize(dbInst.name); // Special case.
  1826. }
  1827. }
  1828. if (category === "Unknown")
  1829. console.log(`Instruction '${dbInsts[0].name}' has no RMInfo category.`);
  1830. return category || "Unknown";
  1831. }
  1832. rmReplaceableIndexes(dbInsts) {
  1833. function maskOf(inst, fn) {
  1834. var m = 0;
  1835. var operands = inst.operands;
  1836. for (var i = 0; i < operands.length; i++)
  1837. if (fn(operands[i]))
  1838. m |= (1 << i);
  1839. return m;
  1840. }
  1841. function getRegIndexes(inst) { return maskOf(inst, function(op) { return op.isReg(); }); };
  1842. function getMemIndexes(inst) { return maskOf(inst, function(op) { return op.isMem(); }); };
  1843. var mask = 0;
  1844. for (var i = 0; i < dbInsts.length; i++) {
  1845. const dbInst = dbInsts[i];
  1846. var mi = getMemIndexes(dbInst);
  1847. var ri = getRegIndexes(dbInst) & ~mi;
  1848. if (!mi)
  1849. continue;
  1850. const match = dbInsts.some((inst) => {
  1851. var ti = getRegIndexes(inst);
  1852. return ((ri & ti) === ri && (mi & ti) === mi);
  1853. });
  1854. if (!match)
  1855. return 0;
  1856. mask |= mi;
  1857. }
  1858. return mask;
  1859. }
  1860. rmFixedSize(insts) {
  1861. var savedOp = null;
  1862. for (var i = 0; i < insts.length; i++) {
  1863. const inst = insts[i];
  1864. const operands = inst.operands;
  1865. for (var j = 0; j < operands.length; j++) {
  1866. const op = operands[j];
  1867. if (op.mem) {
  1868. if (savedOp && savedOp.mem !== op.mem)
  1869. return -1;
  1870. savedOp = op;
  1871. }
  1872. }
  1873. }
  1874. return savedOp ? Math.max(savedOp.memSize, 0) / 8 : -1;
  1875. }
  1876. rmIsConsistent(insts) {
  1877. var hasMem = 0;
  1878. for (var i = 0; i < insts.length; i++) {
  1879. const inst = insts[i];
  1880. const operands = inst.operands;
  1881. for (var j = 0; j < operands.length; j++) {
  1882. const op = operands[j];
  1883. if (op.mem) {
  1884. hasMem = 1;
  1885. if (!op.reg)
  1886. return 0;
  1887. if (asmdb.x86.Utils.regSize(op.reg) !== op.memSize)
  1888. return 0;
  1889. }
  1890. }
  1891. }
  1892. return hasMem;
  1893. }
  1894. rmIsAmbiguous(dbInsts) {
  1895. function isAmbiguous(dbInsts) {
  1896. const memMap = {};
  1897. const immMap = {};
  1898. for (var i = 0; i < dbInsts.length; i++) {
  1899. const dbInst = dbInsts[i];
  1900. const operands = dbInst.operands;
  1901. var memStr = "";
  1902. var immStr = "";
  1903. var hasMem = false;
  1904. var hasImm = false;
  1905. for (var j = 0; j < operands.length; j++) {
  1906. const op = operands[j];
  1907. if (j) {
  1908. memStr += ", ";
  1909. immStr += ", ";
  1910. }
  1911. if (op.isImm()) {
  1912. immStr += "imm";
  1913. hasImm = true;
  1914. }
  1915. else {
  1916. immStr += op.toString();
  1917. }
  1918. if (op.mem) {
  1919. memStr += "m";
  1920. hasMem = true;
  1921. }
  1922. else {
  1923. memStr += op.isImm() ? "imm" : op.toString();
  1924. }
  1925. }
  1926. if (hasImm) {
  1927. if (immMap[immStr] === true)
  1928. continue;
  1929. immMap[immStr] = true;
  1930. }
  1931. if (hasMem) {
  1932. if (memMap[memStr] === true)
  1933. return 1;
  1934. memMap[memStr] = true;
  1935. }
  1936. }
  1937. return 0;
  1938. }
  1939. const uniqueInsts = Filter.unique(dbInsts);
  1940. // Special cases.
  1941. if (!dbInsts.length)
  1942. return 0;
  1943. if (NOT_MEM_AMBIGUOUS[dbInsts[0].name])
  1944. return 0;
  1945. return (isAmbiguous(Filter.byArch(uniqueInsts, "X86")) << 0) |
  1946. (isAmbiguous(Filter.byArch(uniqueInsts, "X64")) << 1) ;
  1947. }
  1948. rmExtension(dbInsts) {
  1949. if (!dbInsts.length)
  1950. return "None";
  1951. const name = dbInsts[0].name;
  1952. switch (name) {
  1953. case "pextrw":
  1954. return "SSE4_1";
  1955. case "vpslldq":
  1956. case "vpsrldq":
  1957. return "AVX512_BW";
  1958. default:
  1959. return "None";
  1960. }
  1961. }
  1962. }
  1963. // ============================================================================
  1964. // [tablegen.x86.InstCommonTable]
  1965. // ============================================================================
  1966. class InstCommonTable extends core.Task {
  1967. constructor() {
  1968. super("InstCommonTable", [
  1969. "IdEnum",
  1970. "NameTable",
  1971. "InstSignatureTable",
  1972. "InstCommonInfoTableB",
  1973. "InstRWInfoTable"
  1974. ]);
  1975. }
  1976. run() {
  1977. const insts = this.ctx.insts;
  1978. const table = new IndexedArray();
  1979. insts.forEach((inst) => {
  1980. const flags = inst.flags.map(function(flag) { return `F(${flag})`; }).join("|") || "0";
  1981. const singleRegCase = `SINGLE_REG(${inst.singleRegCase})`;
  1982. const controlType = `CONTROL(${inst.controlType})`;
  1983. const row = "{ " +
  1984. String(flags ).padEnd(54) + ", " +
  1985. String(inst.signatureIndex).padEnd( 3) + ", " +
  1986. String(inst.signatureCount).padEnd( 2) + ", " +
  1987. String(controlType ).padEnd(16) + ", " +
  1988. String(singleRegCase ).padEnd(16) + ", " + "0 }";
  1989. inst.commonInfoIndexA = table.addIndexed(row);
  1990. });
  1991. var s = `#define F(VAL) InstDB::kFlag##VAL\n` +
  1992. `#define CONTROL(VAL) Inst::kControl##VAL\n` +
  1993. `#define SINGLE_REG(VAL) InstDB::kSingleReg##VAL\n` +
  1994. `const InstDB::CommonInfo InstDB::_commonInfoTable[] = {\n${StringUtils.format(table, kIndent, true)}\n};\n` +
  1995. `#undef SINGLE_REG\n` +
  1996. `#undef CONTROL\n` +
  1997. `#undef F\n`;
  1998. this.inject("InstCommonTable", disclaimer(s), table.length * 8);
  1999. }
  2000. }
  2001. // ============================================================================
  2002. // [Main]
  2003. // ============================================================================
  2004. new X86TableGen()
  2005. .addTask(new IdEnum())
  2006. .addTask(new NameTable())
  2007. .addTask(new AltOpcodeTable())
  2008. .addTask(new InstSignatureTable())
  2009. .addTask(new InstCommonInfoTableB())
  2010. .addTask(new InstRWInfoTable())
  2011. .addTask(new InstCommonTable())
  2012. .run();