tablegen-a64.js (9948B)
1 // This file is part of AsmJit project <https://asmjit.com> 2 // 3 // See <asmjit/core.h> or LICENSE.md for license and copyright information 4 // SPDX-License-Identifier: Zlib 5 6 "use strict"; 7 8 const core = require("./tablegen.js"); 9 const commons = require("./generator-commons.js"); 10 11 const asmdb = core.asmdb; 12 const kIndent = commons.kIndent; 13 const IndexedArray = commons.IndexedArray; 14 const StringUtils = commons.StringUtils; 15 16 const FATAL = commons.FATAL; 17 18 // ============================================================================ 19 // [ArmDB] 20 // ============================================================================ 21 22 // Create AArch64 ISA. 23 const isa = new asmdb.aarch64.ISA(); 24 25 /* 26 class GenUtils { 27 // Get a list of instructions based on `name` and optional `mode`. 28 static query(name, mode) { 29 const insts = isa.query(name); 30 return !mode ? insts : insts.filter(function(inst) { return inst.arch === mode; }); 31 } 32 33 static archOf(records) { 34 var t16Arch = false; 35 var t32Arch = false; 36 var a32Arch = false; 37 var a64Arch = false; 38 39 for (var i = 0; i < records.length; i++) { 40 const record = records[i]; 41 if (record.encoding === "T16") t16Arch = true; 42 if (record.encoding === "T32") t32Arch = true; 43 if (record.encoding === "A32") a32Arch = true; 44 if (record.encoding === "A64") a64Arch = true; 45 } 46 47 var s = (t16Arch && !t32Arch) ? "T16" : 48 (t32Arch && !t16Arch) ? "T32" : 49 (t16Arch && t32Arch) ? "Txx" : "---"; 50 s += " "; 51 s += (a32Arch) ? "A32" : "---"; 52 s += " "; 53 s += (a64Arch) ? "A64" : "---"; 54 55 return `[${s}]`; 56 } 57 58 static featuresOf(records) { 59 const exts = Object.create(null); 60 for (var i = 0; i < records.length; i++) { 61 const record = records[i]; 62 for (var k in record.extensions) 63 exts[k] = true; 64 } 65 const arr = Object.keys(exts); 66 arr.sort(); 67 return arr; 68 } 69 } 70 */ 71 72 // ============================================================================ 73 // [tablegen.arm.ArmTableGen] 74 // ============================================================================ 75 76 class ArmTableGen extends core.TableGen { 77 constructor() { 78 super("A64"); 79 } 80 81 // -------------------------------------------------------------------------- 82 // [Parse / Merge] 83 // -------------------------------------------------------------------------- 84 85 parse() { 86 const rawData = this.dataOfFile("src/asmjit/arm/a64instdb.cpp"); 87 const stringData = StringUtils.extract(rawData, "// ${InstInfo:Begin}", "// ${InstInfo:End"); 88 89 const re = new RegExp( 90 "INST\\(\\s*" + 91 // [01] Instruction. 92 "(" + 93 "[A-Za-z0-9_]+" + 94 ")\\s*,\\s*" + 95 96 // [02] Encoding. 97 "(" + 98 "[^,]+" + 99 ")\\s*,\\s*" + 100 101 // [03] OpcodeData. 102 "(" + 103 "\\([^\\)]+\\)" + 104 ")\\s*,\\s*" + 105 106 // [04] RWInfo. 107 "(" + 108 "[^,]+" + 109 ")\\s*,\\s*" + 110 111 // [05] InstructionFlags. 112 "(\\s*" + 113 "(?:" + 114 "(?:" + 115 "[\\d]+" + 116 "|" + 117 "F\\([^\\)]*\\)" + 118 ")" + 119 "\\s*" + 120 "[|]?\\s*" + 121 ")+" + 122 ")\\s*,\\s*" + 123 124 // --- autogenerated fields --- 125 126 // [06] OpcodeDataIndex. 127 "([^\\)]+)" + 128 "\\s*\\)" 129 130 , "g"); 131 132 var m; 133 while ((m = re.exec(stringData)) !== null) { 134 var enumName = m[1]; 135 var name = enumName === "None" ? "" : enumName.toLowerCase(); 136 var encoding = m[2].trim(); 137 var opcodeData = m[3].trim(); 138 var rwInfo = m[4].trim(); 139 var instFlags = m[5].trim(); 140 141 var displayName = name; 142 if (name.endsWith("_v")) 143 displayName = name.substring(0, name.length - 2); 144 145 // We have just matched #define INST() 146 if (name == "id" && 147 encoding === "encoding" && 148 encodingDataIndex === "encodingDataIndex") 149 continue; 150 151 this.addInstruction({ 152 id : 0, // Instruction id (numeric value). 153 name : name, // Instruction name. 154 displayName : displayName, // Instruction name to display. 155 enum : enumName, // Instruction enum without `kId` prefix. 156 encoding : encoding, // Opcode encoding. 157 opcodeData : opcodeData, // Opcode data. 158 opcodeDataIndex : -1, // Opcode data index. 159 rwInfo : rwInfo, // RW info. 160 flags : instFlags // Instruction flags. 161 }); 162 } 163 164 if (this.insts.length === 0 || this.insts.length !== StringUtils.countOf(stringData, "INST(")) 165 FATAL("ARMTableGen.parse(): Invalid parsing regexp (no data parsed)"); 166 167 console.log("Number of Instructions: " + this.insts.length); 168 } 169 170 merge() { 171 var s = StringUtils.format(this.insts, "", true, function(inst) { 172 return "INST(" + 173 String(inst.enum ).padEnd(17) + ", " + 174 String(inst.encoding ).padEnd(19) + ", " + 175 String(inst.opcodeData ).padEnd(86) + ", " + 176 String(inst.rwInfo ).padEnd(10) + ", " + 177 String(inst.flags ).padEnd(26) + ", " + 178 String(inst.opcodeDataIndex ).padEnd( 3) + ")" ; 179 }) + "\n"; 180 return this.inject("InstInfo", s, this.insts.length * 4); 181 } 182 183 // -------------------------------------------------------------------------- 184 // [Hooks] 185 // -------------------------------------------------------------------------- 186 187 onBeforeRun() { 188 this.load([ 189 "src/asmjit/arm/a64emitter.h", 190 "src/asmjit/arm/a64globals.h", 191 "src/asmjit/arm/a64instdb.cpp", 192 "src/asmjit/arm/a64instdb.h", 193 "src/asmjit/arm/a64instdb_p.h" 194 ]); 195 this.parse(); 196 } 197 198 onAfterRun() { 199 this.merge(); 200 this.save(); 201 this.dumpTableSizes(); 202 } 203 } 204 205 // ============================================================================ 206 // [tablegen.arm.IdEnum] 207 // ============================================================================ 208 209 class IdEnum extends core.IdEnum { 210 constructor() { 211 super("IdEnum"); 212 } 213 214 comment(inst) { 215 let name = inst.name; 216 let ext = []; 217 218 if (name.endsWith("_v")) { 219 name = name.substr(0, name.length - 2); 220 ext.push("ASIMD"); 221 } 222 223 let exts = ""; 224 if (ext.length) 225 exts = " {" + ext.join("&") + "}"; 226 227 return `Instruction '${name}'${exts}.`; 228 } 229 } 230 231 // ============================================================================ 232 // [tablegen.arm.NameTable] 233 // ============================================================================ 234 235 class NameTable extends core.NameTable { 236 constructor() { 237 super("NameTable"); 238 } 239 } 240 241 // ============================================================================ 242 // [tablegen.arm.EncodingTable] 243 // ============================================================================ 244 245 class EncodingTable extends core.Task { 246 constructor() { 247 super("EncodingTable"); 248 } 249 250 run() { 251 const insts = this.ctx.insts; 252 const map = {}; 253 254 for (var i = 0; i < insts.length; i++) { 255 const inst = insts[i]; 256 257 const encoding = inst.encoding; 258 const opcodeData = inst.opcodeData.replace(/\(/g, "{ ").replace(/\)/g, " }"); 259 260 if (!Object.hasOwn(map, encoding)) 261 map[encoding] = []; 262 263 if (inst.opcodeData === "(_)") { 264 inst.opcodeDataIndex = 0; 265 continue; 266 } 267 268 const opcodeTable = map[encoding]; 269 const opcodeDataIndex = opcodeTable.length; 270 271 opcodeTable.push({ name: inst.name, data: opcodeData }); 272 inst.opcodeDataIndex = opcodeDataIndex; 273 } 274 275 const keys = Object.keys(map); 276 keys.sort(); 277 278 var tableSource = ""; 279 var tableHeader = ""; 280 var encodingIds = ""; 281 282 encodingIds += "enum EncodingId : uint32_t {\n" 283 encodingIds += " kEncodingNone = 0"; 284 285 keys.forEach((dataClass) => { 286 const dataName = dataClass[0].toLowerCase() + dataClass.substr(1); 287 const opcodeTable = map[dataClass]; 288 const count = opcodeTable.length; 289 290 if (dataClass !== "None") { 291 encodingIds += ",\n" 292 encodingIds += " kEncoding" + dataClass; 293 } 294 295 if (count) { 296 tableHeader += `extern const ${dataClass} ${dataName}[${count}];\n`; 297 298 if (tableSource) 299 tableSource += "\n"; 300 301 tableSource += `const ${dataClass} ${dataName}[${count}] = {\n`; 302 for (var i = 0; i < count; i++) { 303 tableSource += ` ${opcodeTable[i].data}` + (i == count - 1 ? " " : ",") + " // " + opcodeTable[i].name + "\n"; 304 } 305 tableSource += `};\n`; 306 } 307 }); 308 309 encodingIds += "\n};\n"; 310 311 return this.ctx.inject("EncodingId" , StringUtils.disclaimer(encodingIds), 0) + 312 this.ctx.inject("EncodingDataForward", StringUtils.disclaimer(tableHeader), 0) + 313 this.ctx.inject("EncodingData" , StringUtils.disclaimer(tableSource), 0); 314 } 315 } 316 // ============================================================================ 317 // [tablegen.arm.CommonTable] 318 // ============================================================================ 319 320 class CommonTable extends core.Task { 321 constructor() { 322 super("CommonTable", [ 323 "IdEnum", 324 "NameTable" 325 ]); 326 } 327 328 run() { 329 //const table = new IndexedArray(); 330 331 //for (var i = 0; i < insts.length; i++) { 332 // const inst = insts[i]; 333 // const item = "{ " + "0" + "}"; 334 // inst.commonIndex = table.addIndexed(item); 335 //} 336 337 // return this.ctx.inject("InstInfo", StringUtils.disclaimer(s), 0); 338 return 0; 339 } 340 } 341 342 // ============================================================================ 343 // [Main] 344 // ============================================================================ 345 346 new ArmTableGen() 347 .addTask(new IdEnum()) 348 .addTask(new NameTable()) 349 .addTask(new EncodingTable()) 350 .addTask(new CommonTable()) 351 .run();