tablegen.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917
  1. // [AsmJit]
  2. // Machine Code Generation for C++.
  3. //
  4. // [License]
  5. // ZLIB - See LICENSE.md file in the package.
  6. // ============================================================================
  7. // tablegen.js
  8. //
  9. // Provides core foundation for generating tables that AsmJit requires. This
  10. // file should provide everything table generators need in general.
  11. // ============================================================================
  12. "use strict";
  13. const VERBOSE = false;
  14. // ============================================================================
  15. // [Imports]
  16. // ============================================================================
  17. const fs = require("fs");
  18. const hasOwn = Object.prototype.hasOwnProperty;
  19. const asmdb = (function() {
  20. // Try to import a local 'asmdb' package, if available.
  21. try {
  22. return require("./asmdb");
  23. }
  24. catch (ex) {
  25. if (ex.code !== "MODULE_NOT_FOUND") {
  26. console.log(`FATAL ERROR: ${ex.message}`);
  27. throw ex;
  28. }
  29. }
  30. // Try to import global 'asmdb' package as local package is not available.
  31. return require("asmdb");
  32. })();
  33. exports.asmdb = asmdb;
  34. // ============================================================================
  35. // [Constants]
  36. // ============================================================================
  37. const kIndent = " ";
  38. const kJustify = 119;
  39. const kAsmJitRoot = "..";
  40. exports.kIndent = kIndent;
  41. exports.kJustify = kJustify;
  42. exports.kAsmJitRoot = kAsmJitRoot;
  43. // ============================================================================
  44. // [Debugging]
  45. // ============================================================================
  46. function DEBUG(msg) {
  47. if (VERBOSE)
  48. console.log(msg);
  49. }
  50. exports.DEBUG = DEBUG;
  51. function WARN(msg) {
  52. console.log(msg);
  53. }
  54. exports.WARN = WARN;
  55. function FAIL(msg) {
  56. console.log(`FATAL ERROR: ${msg}`);
  57. throw new Error(msg);
  58. }
  59. exports.FAIL = FAIL;
  60. // ============================================================================
  61. // [Lang]
  62. // ============================================================================
  63. function nop(x) { return x; }
  64. class Lang {
  65. static merge(a, b) {
  66. if (a === b)
  67. return a;
  68. for (var k in b) {
  69. var av = a[k];
  70. var bv = b[k];
  71. if (typeof av === "object" && typeof bv === "object")
  72. Lang.merge(av, bv);
  73. else
  74. a[k] = bv;
  75. }
  76. return a;
  77. }
  78. static deepEq(a, b) {
  79. if (a === b)
  80. return true;
  81. if (typeof a !== typeof b)
  82. return false;
  83. if (typeof a !== "object")
  84. return a === b;
  85. if (Array.isArray(a) || Array.isArray(b)) {
  86. if (Array.isArray(a) !== Array.isArray(b))
  87. return false;
  88. const len = a.length;
  89. if (b.length !== len)
  90. return false;
  91. for (var i = 0; i < len; i++)
  92. if (!Lang.deepEq(a[i], b[i]))
  93. return false;
  94. }
  95. else {
  96. if (a === null || b === null)
  97. return a === b;
  98. for (var k in a)
  99. if (!hasOwn.call(b, k) || !Lang.deepEq(a[k], b[k]))
  100. return false;
  101. for (var k in b)
  102. if (!hasOwn.call(a, k))
  103. return false;
  104. }
  105. return true;
  106. }
  107. static deepEqExcept(a, b, except) {
  108. if (a === b)
  109. return true;
  110. if (typeof a !== "object" || typeof b !== "object" || Array.isArray(a) || Array.isArray(b))
  111. return Lang.deepEq(a, b);
  112. for (var k in a)
  113. if (!hasOwn.call(except, k) && (!hasOwn.call(b, k) || !Lang.deepEq(a[k], b[k])))
  114. return false;
  115. for (var k in b)
  116. if (!hasOwn.call(except, k) && !hasOwn.call(a, k))
  117. return false;
  118. return true;
  119. }
  120. }
  121. exports.Lang = Lang;
  122. // ============================================================================
  123. // [StringUtils]
  124. // ============================================================================
  125. class StringUtils {
  126. static asString(x) { return String(x); }
  127. static capitalize(s) {
  128. s = String(s);
  129. return !s ? s : s[0].toUpperCase() + s.substr(1);
  130. }
  131. static trimLeft(s) { return s.replace(/^\s+/, ""); }
  132. static trimRight(s) { return s.replace(/\s+$/, ""); }
  133. static upFirst(s) {
  134. if (!s) return "";
  135. return s[0].toUpperCase() + s.substr(1);
  136. }
  137. static decToHex(n, nPad) {
  138. var hex = Number(n < 0 ? 0x100000000 + n : n).toString(16);
  139. while (nPad > hex.length)
  140. hex = "0" + hex;
  141. return "0x" + hex.toUpperCase();
  142. }
  143. static format(array, indent, showIndex, mapFn) {
  144. if (!mapFn)
  145. mapFn = StringUtils.asString;
  146. var s = "";
  147. var threshold = 80;
  148. if (showIndex === -1)
  149. s += indent;
  150. for (var i = 0; i < array.length; i++) {
  151. const item = array[i];
  152. const last = i === array.length - 1;
  153. if (showIndex !== -1)
  154. s += indent;
  155. s += mapFn(item);
  156. if (showIndex > 0) {
  157. s += `${last ? " " : ","} // #${i}`;
  158. if (typeof array.refCountOf === "function")
  159. s += ` [ref=${array.refCountOf(item)}x]`;
  160. }
  161. else if (!last) {
  162. s += ",";
  163. }
  164. if (showIndex === -1) {
  165. if (s.length >= threshold - 1 && !last) {
  166. s += "\n" + indent;
  167. threshold += 80;
  168. }
  169. else {
  170. if (!last) s += " ";
  171. }
  172. }
  173. else {
  174. if (!last) s += "\n";
  175. }
  176. }
  177. return s;
  178. }
  179. static makeCxxArray(array, code, indent) {
  180. if (!indent) indent = kIndent;
  181. return `${code} = {\n${indent}` + array.join(`,\n${indent}`) + `\n};\n`;
  182. }
  183. static makeCxxArrayWithComment(array, code, indent) {
  184. if (!indent) indent = kIndent;
  185. var s = "";
  186. for (var i = 0; i < array.length; i++) {
  187. const last = i === array.length - 1;
  188. s += indent + array[i].data +
  189. (last ? " // " : ", // ") + (array[i].refs ? "#" + String(i) : "").padEnd(5) + array[i].comment + "\n";
  190. }
  191. return `${code} = {\n${s}};\n`;
  192. }
  193. static disclaimer(s) {
  194. return "// ------------------- Automatically generated, do not edit -------------------\n" +
  195. s +
  196. "// ----------------------------------------------------------------------------\n";
  197. }
  198. static indent(s, indentation) {
  199. var lines = s.split(/\r?\n/g);
  200. if (indentation) {
  201. for (var i = 0; i < lines.length; i++) {
  202. var line = lines[i];
  203. if (line) lines[i] = indentation + line;
  204. }
  205. }
  206. return lines.join("\n");
  207. }
  208. static inject(s, start, end, code) {
  209. var iStart = s.indexOf(start);
  210. var iEnd = s.indexOf(end);
  211. if (iStart === -1)
  212. FAIL(`Utils.inject(): Couldn't locate start mark '${start}'`);
  213. if (iEnd === -1)
  214. FAIL(`Utils.inject(): Couldn't locate end mark '${end}'`);
  215. var nIndent = 0;
  216. while (iStart > 0 && s[iStart-1] === " ") {
  217. iStart--;
  218. nIndent++;
  219. }
  220. if (nIndent) {
  221. const indentation = " ".repeat(nIndent);
  222. code = StringUtils.indent(code, indentation) + indentation;
  223. }
  224. return s.substr(0, iStart + start.length + nIndent) + code + s.substr(iEnd);
  225. }
  226. static makePriorityCompare(priorityArray) {
  227. const map = Object.create(null);
  228. priorityArray.forEach((str, index) => { map[str] = index; });
  229. return function(a, b) {
  230. const ax = hasOwn.call(map, a) ? map[a] : Infinity;
  231. const bx = hasOwn.call(map, b) ? map[b] : Infinity;
  232. return ax != bx ? ax - bx : a < b ? -1 : a > b ? 1 : 0;
  233. }
  234. }
  235. }
  236. exports.StringUtils = StringUtils;
  237. // ============================================================================
  238. // [ArrayUtils]
  239. // ============================================================================
  240. class ArrayUtils {
  241. static min(arr, fn) {
  242. if (!arr.length)
  243. return null;
  244. if (!fn)
  245. fn = nop;
  246. var v = fn(arr[0]);
  247. for (var i = 1; i < arr.length; i++)
  248. v = Math.min(v, fn(arr[i]));
  249. return v;
  250. }
  251. static max(arr, fn) {
  252. if (!arr.length)
  253. return null;
  254. if (!fn)
  255. fn = nop;
  256. var v = fn(arr[0]);
  257. for (var i = 1; i < arr.length; i++)
  258. v = Math.max(v, fn(arr[i]));
  259. return v;
  260. }
  261. static sorted(obj, cmp) {
  262. const out = Array.isArray(obj) ? obj.slice() : Object.getOwnPropertyNames(obj);
  263. out.sort(cmp);
  264. return out;
  265. }
  266. static deepIndexOf(arr, what) {
  267. for (var i = 0; i < arr.length; i++)
  268. if (Lang.deepEq(arr[i], what))
  269. return i;
  270. return -1;
  271. }
  272. }
  273. exports.ArrayUtils = ArrayUtils;
  274. // ============================================================================
  275. // [MapUtils]
  276. // ============================================================================
  277. class MapUtils {
  278. static clone(map) {
  279. return Object.assign(Object.create(null), map);
  280. }
  281. static arrayToMap(arr, value) {
  282. if (value === undefined)
  283. value = true;
  284. const out = Object.create(null);
  285. for (var i = 0; i < arr.length; i++)
  286. out[arr[i]] = value;
  287. return out;
  288. }
  289. static equals(a, b) {
  290. for (var k in a) if (!hasOwn.call(b, k)) return false;
  291. for (var k in b) if (!hasOwn.call(a, k)) return false;
  292. return true;
  293. }
  294. static firstOf(map, flags) {
  295. for (var k in flags)
  296. if (hasOwn.call(map, k))
  297. return k;
  298. return undefined;
  299. }
  300. static anyOf(map, flags) {
  301. for (var k in flags)
  302. if (hasOwn.call(map, k))
  303. return true;
  304. return false;
  305. }
  306. static add(a, b) {
  307. for (var k in b)
  308. a[k] = b[k];
  309. return a;
  310. }
  311. static and(a, b) {
  312. const out = Object.create(null);
  313. for (var k in a)
  314. if (hasOwn.call(b, k))
  315. out[k] = true;
  316. return out;
  317. }
  318. static xor(a, b) {
  319. const out = Object.create(null);
  320. for (var k in a) if (!hasOwn.call(b, k)) out[k] = true;
  321. for (var k in b) if (!hasOwn.call(a, k)) out[k] = true;
  322. return out;
  323. }
  324. };
  325. exports.MapUtils = MapUtils;
  326. // ============================================================================
  327. // [CxxUtils]
  328. // ============================================================================
  329. class CxxUtils {
  330. static flags(obj, fn) {
  331. if (!fn)
  332. fn = nop;
  333. var out = "";
  334. for (var k in obj) {
  335. if (obj[k])
  336. out += (out ? " | " : "") + fn(k);
  337. }
  338. return out ? out : "0";
  339. }
  340. static struct(...args) {
  341. return "{ " + args.join(", ") + " }";
  342. }
  343. };
  344. exports.CxxUtils = CxxUtils;
  345. // ============================================================================
  346. // [IndexedString]
  347. // ============================================================================
  348. // IndexedString is mostly used to merge all instruction names into a single
  349. // string with external index. It's designed mostly for generating C++ tables.
  350. //
  351. // Consider the following cases in C++:
  352. //
  353. // a) static const char* const* instNames = { "add", "mov", "vpunpcklbw" };
  354. //
  355. // b) static const char instNames[] = { "add\0" "mov\0" "vpunpcklbw\0" };
  356. // static const uint16_t instNameIndex[] = { 0, 4, 8 };
  357. //
  358. // The latter (b) has an advantage that it doesn't have to be relocated by the
  359. // linker, which saves a lot of space in the resulting binary and a lot of CPU
  360. // cycles (and memory) when the linker loads it. AsmJit supports thousands of
  361. // instructions so each optimization like this makes it smaller and faster to
  362. // load.
  363. class IndexedString {
  364. constructor() {
  365. this.map = Object.create(null);
  366. this.array = [];
  367. this.size = -1;
  368. }
  369. add(s) {
  370. this.map[s] = -1;
  371. }
  372. index() {
  373. const map = this.map;
  374. const array = this.array;
  375. const partialMap = Object.create(null);
  376. var k, kp;
  377. var i, len;
  378. // Create a map that will contain all keys and partial keys.
  379. for (k in map) {
  380. if (!k) {
  381. partialMap[k] = k;
  382. }
  383. else {
  384. for (i = 0, len = k.length; i < len; i++) {
  385. kp = k.substr(i);
  386. if (!hasOwn.call(partialMap, kp) || partialMap[kp].length < len)
  387. partialMap[kp] = k;
  388. }
  389. }
  390. }
  391. // Create an array that will only contain keys that are needed.
  392. for (k in map)
  393. if (partialMap[k] === k)
  394. array.push(k);
  395. array.sort();
  396. // Create valid offsets to the `array`.
  397. var offMap = Object.create(null);
  398. var offset = 0;
  399. for (i = 0, len = array.length; i < len; i++) {
  400. k = array[i];
  401. offMap[k] = offset;
  402. offset += k.length + 1;
  403. }
  404. this.size = offset;
  405. // Assign valid offsets to `map`.
  406. for (kp in map) {
  407. k = partialMap[kp];
  408. map[kp] = offMap[k] + k.length - kp.length;
  409. }
  410. }
  411. format(indent, justify) {
  412. if (this.size === -1)
  413. FAIL(`IndexedString.format(): not indexed yet, call index()`);
  414. const array = this.array;
  415. if (!justify) justify = 0;
  416. var i;
  417. var s = "";
  418. var line = "";
  419. for (i = 0; i < array.length; i++) {
  420. const item = "\"" + array[i] + ((i !== array.length - 1) ? "\\0\"" : "\";");
  421. const newl = line + (line ? " " : indent) + item;
  422. if (newl.length <= justify) {
  423. line = newl;
  424. continue;
  425. }
  426. else {
  427. s += line + "\n";
  428. line = indent + item;
  429. }
  430. }
  431. return s + line;
  432. }
  433. getSize() {
  434. if (this.size === -1)
  435. FAIL(`IndexedString.getSize(): Not indexed yet, call index()`);
  436. return this.size;
  437. }
  438. getIndex(k) {
  439. if (this.size === -1)
  440. FAIL(`IndexedString.getIndex(): Not indexed yet, call index()`);
  441. if (!hasOwn.call(this.map, k))
  442. FAIL(`IndexedString.getIndex(): Key '${k}' not found.`);
  443. return this.map[k];
  444. }
  445. }
  446. exports.IndexedString = IndexedString;
  447. // ============================================================================
  448. // [IndexedArray]
  449. // ============================================================================
  450. // IndexedArray is an Array replacement that allows to index each item inserted
  451. // to it. Its main purpose is to avoid data duplication, if an item passed to
  452. // `addIndexed()` is already within the Array then it's not inserted and the
  453. // existing index is returned instead.
  454. function IndexedArray_keyOf(item) {
  455. return typeof item === "string" ? item : JSON.stringify(item);
  456. }
  457. class IndexedArray extends Array {
  458. constructor() {
  459. super();
  460. this._index = Object.create(null);
  461. }
  462. refCountOf(item) {
  463. const key = IndexedArray_keyOf(item);
  464. const idx = this._index[key];
  465. return idx !== undefined ? idx.refCount : 0;
  466. }
  467. addIndexed(item) {
  468. const key = IndexedArray_keyOf(item);
  469. var idx = this._index[key];
  470. if (idx !== undefined) {
  471. idx.refCount++;
  472. return idx.data;
  473. }
  474. idx = this.length;
  475. this._index[key] = {
  476. data: idx,
  477. refCount: 1
  478. };
  479. this.push(item);
  480. return idx;
  481. }
  482. }
  483. exports.IndexedArray = IndexedArray;
  484. // ============================================================================
  485. // [Task]
  486. // ============================================================================
  487. // A base runnable task that can access the TableGen through `this.ctx`.
  488. class Task {
  489. constructor(name, deps) {
  490. this.ctx = null;
  491. this.name = name || "";
  492. this.deps = deps || [];
  493. }
  494. inject(key, str, size) {
  495. this.ctx.inject(key, str, size);
  496. return this;
  497. }
  498. run() {
  499. FAIL("Task.run(): Must be reimplemented");
  500. }
  501. }
  502. exports.Task = Task;
  503. // ============================================================================
  504. // [TableGen]
  505. // ============================================================================
  506. // Main context used to load, generate, and store instruction tables. The idea
  507. // is to be extensible, so it stores 'Task's to be executed with minimal deps
  508. // management.
  509. class TableGen {
  510. constructor(arch) {
  511. this.arch = arch;
  512. this.files = Object.create(null);
  513. this.tableSizes = Object.create(null);
  514. this.tasks = [];
  515. this.taskMap = Object.create(null);
  516. this.insts = [];
  517. this.instMap = Object.create(null);
  518. this.aliases = [];
  519. this.aliasMem = Object.create(null);
  520. }
  521. // --------------------------------------------------------------------------
  522. // [File Management]
  523. // --------------------------------------------------------------------------
  524. load(fileList) {
  525. for (var i = 0; i < fileList.length; i++) {
  526. const file = fileList[i];
  527. const path = kAsmJitRoot + "/" + file;
  528. const data = fs.readFileSync(path, "utf8").replace(/\r\n/g, "\n");
  529. this.files[file] = {
  530. prev: data,
  531. data: data
  532. };
  533. }
  534. return this;
  535. }
  536. save() {
  537. for (var file in this.files) {
  538. const obj = this.files[file];
  539. if (obj.data !== obj.prev) {
  540. const path = kAsmJitRoot + "/" + file;
  541. console.log(`MODIFIED '${file}'`);
  542. fs.writeFileSync(path + ".backup", obj.prev, "utf8");
  543. fs.writeFileSync(path, obj.data, "utf8");
  544. }
  545. }
  546. }
  547. dataOfFile(file) {
  548. const obj = this.files[file];
  549. if (!obj)
  550. FAIL(`TableGen.dataOfFile(): File '${file}' not loaded`);
  551. return obj.data;
  552. }
  553. inject(key, str, size) {
  554. const begin = "// ${" + key + ":Begin}\n";
  555. const end = "// ${" + key + ":End}\n";
  556. var done = false;
  557. for (var file in this.files) {
  558. const obj = this.files[file];
  559. const data = obj.data;
  560. if (data.indexOf(begin) !== -1) {
  561. obj.data = StringUtils.inject(data, begin, end, str);
  562. done = true;
  563. break;
  564. }
  565. }
  566. if (!done)
  567. FAIL(`TableGen.inject(): Cannot find '${key}'`);
  568. if (size)
  569. this.tableSizes[key] = size;
  570. return this;
  571. }
  572. // --------------------------------------------------------------------------
  573. // [Task Management]
  574. // --------------------------------------------------------------------------
  575. addTask(task) {
  576. if (!task.name)
  577. FAIL(`TableGen.addModule(): Module must have a name`);
  578. if (this.taskMap[task.name])
  579. FAIL(`TableGen.addModule(): Module '${task.name}' already added`);
  580. task.deps.forEach((dependency) => {
  581. if (!this.taskMap[dependency])
  582. FAIL(`TableGen.addModule(): Dependency '${dependency}' of module '${task.name}' doesn't exist`);
  583. });
  584. this.tasks.push(task);
  585. this.taskMap[task.name] = task;
  586. task.ctx = this;
  587. return this;
  588. }
  589. runTasks() {
  590. const tasks = this.tasks;
  591. const tasksDone = Object.create(null);
  592. var pending = tasks.length;
  593. while (pending) {
  594. const oldPending = pending;
  595. const arrPending = [];
  596. for (var i = 0; i < tasks.length; i++) {
  597. const task = tasks[i];
  598. if (tasksDone[task.name])
  599. continue;
  600. if (task.deps.every((dependency) => { return tasksDone[dependency] === true; })) {
  601. task.run();
  602. tasksDone[task.name] = true;
  603. pending--;
  604. }
  605. else {
  606. arrPending.push(task.name);
  607. }
  608. }
  609. if (oldPending === pending)
  610. throw Error(`TableGen.runModules(): Modules '${arrPending.join("|")}' stuck (cyclic dependency?)`);
  611. }
  612. }
  613. // --------------------------------------------------------------------------
  614. // [Instruction Management]
  615. // --------------------------------------------------------------------------
  616. addInst(inst) {
  617. if (this.instMap[inst.name])
  618. FAIL(`TableGen.addInst(): Instruction '${inst.name}' already added`);
  619. inst.id = this.insts.length;
  620. this.insts.push(inst);
  621. this.instMap[inst.name] = inst;
  622. return this;
  623. }
  624. addAlias(alias, name) {
  625. this.aliases.push(alias);
  626. this.aliasMap[alias] = name;
  627. return this;
  628. }
  629. // --------------------------------------------------------------------------
  630. // [Run]
  631. // --------------------------------------------------------------------------
  632. run() {
  633. this.onBeforeRun();
  634. this.runTasks();
  635. this.onAfterRun();
  636. }
  637. // --------------------------------------------------------------------------
  638. // [Other]
  639. // --------------------------------------------------------------------------
  640. dumpTableSizes() {
  641. const sizes = this.tableSizes;
  642. var pad = 26;
  643. var total = 0;
  644. for (var name in sizes) {
  645. const size = sizes[name];
  646. total += size;
  647. console.log(("Size of " + name).padEnd(pad) + ": " + size);
  648. }
  649. console.log("Size of all tables".padEnd(pad) + ": " + total);
  650. }
  651. // --------------------------------------------------------------------------
  652. // [Hooks]
  653. // --------------------------------------------------------------------------
  654. onBeforeRun() {}
  655. onAfterRun() {}
  656. }
  657. exports.TableGen = TableGen;
  658. // ============================================================================
  659. // [IdEnum]
  660. // ============================================================================
  661. class IdEnum extends Task {
  662. constructor(name, deps) {
  663. super(name || "IdEnum", deps);
  664. }
  665. comment(name) {
  666. FAIL("IdEnum.comment(): Must be reimplemented");
  667. }
  668. run() {
  669. const insts = this.ctx.insts;
  670. var s = "";
  671. for (var i = 0; i < insts.length; i++) {
  672. const inst = insts[i];
  673. var line = "kId" + inst.enum + (i ? "" : " = 0") + ",";
  674. var text = this.comment(inst);
  675. if (text)
  676. line = line.padEnd(37) + "//!< " + text;
  677. s += line + "\n";
  678. }
  679. s += "_kIdCount\n";
  680. return this.ctx.inject("InstId", s);
  681. }
  682. }
  683. exports.IdEnum = IdEnum;
  684. // ============================================================================
  685. // [NameTable]
  686. // ============================================================================
  687. class NameTable extends Task {
  688. constructor(name, deps) {
  689. super(name || "NameTable", deps);
  690. }
  691. run() {
  692. const arch = this.ctx.arch;
  693. const none = "Inst::kIdNone";
  694. const insts = this.ctx.insts;
  695. const instNames = new IndexedString();
  696. const instFirst = new Array(26);
  697. const instLast = new Array(26);
  698. var maxLength = 0;
  699. for (var i = 0; i < insts.length; i++) {
  700. const inst = insts[i];
  701. instNames.add(inst.name);
  702. maxLength = Math.max(maxLength, inst.name.length);
  703. }
  704. instNames.index();
  705. for (var i = 0; i < insts.length; i++) {
  706. const inst = insts[i];
  707. const name = inst.name;
  708. const nameIndex = instNames.getIndex(name);
  709. const index = name.charCodeAt(0) - 'a'.charCodeAt(0);
  710. if (index < 0 || index >= 26)
  711. FAIL(`TableGen.generateNameData(): Invalid lookup character '${name[0]}' of '${name}'`);
  712. inst.nameIndex = nameIndex;
  713. if (instFirst[index] === undefined)
  714. instFirst[index] = `Inst::kId${inst.enum}`;
  715. instLast[index] = `Inst::kId${inst.enum}`;
  716. }
  717. var s = "";
  718. s += `const char InstDB::_nameData[] =\n${instNames.format(kIndent, kJustify)}\n`;
  719. s += `\n`;
  720. s += `const InstDB::InstNameIndex InstDB::instNameIndex[26] = {\n`;
  721. for (var i = 0; i < instFirst.length; i++) {
  722. const firstId = instFirst[i] || none;
  723. const lastId = instLast[i] || none;
  724. s += ` { ${String(firstId).padEnd(22)}, ${String(lastId).padEnd(22)} + 1 }`;
  725. if (i !== 26 - 1)
  726. s += `,`;
  727. s += `\n`;
  728. }
  729. s += `};\n`;
  730. this.ctx.inject("NameLimits",
  731. StringUtils.disclaimer(`enum : uint32_t { kMaxNameSize = ${maxLength} };\n`));
  732. return this.ctx.inject("NameData", StringUtils.disclaimer(s), instNames.getSize() + 26 * 4);
  733. }
  734. }
  735. exports.NameTable = NameTable;