odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

aarch64.js (27384B)


      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 (function($scope, $as) {
      7 "use strict";
      8 
      9 function FAIL(msg) { throw new Error("[AArch64] " + msg); }
     10 
     11 // Import
     12 // ======
     13 
     14 const base = $scope.base ? $scope.base : require("./base.js");
     15 const exp = $scope.exp ? $scope.exp : require("./exp.js")
     16 
     17 const dict = base.dict;
     18 const NONE = base.NONE;
     19 const Parsing = base.Parsing;
     20 const MapUtils = base.MapUtils;
     21 
     22 // Export
     23 // ======
     24 
     25 const arm = $scope[$as] = dict();
     26 
     27 // Database
     28 // ========
     29 
     30 arm.dbName = "isa_aarch64.json";
     31 
     32 // asmdb.aarch64.Utils
     33 // ===================
     34 
     35 // Can be used to assign the number of bits each part of the opcode occupies.
     36 // NOTE: THUMB instructions that use halfword must always specify the width
     37 // of all registers as many instructions accept only LO (r0..r7) registers.
     38 const FieldInfo = {
     39   "P"     : { "bits": 1 },
     40   "U"     : { "bits": 1 },
     41   "W"     : { "bits": 1 },
     42   "S"     : { "bits": 1 },
     43   "R"     : { "bits": 1 },
     44   "H"     : { "bits": 1 },
     45   "F"     : { "bits": 1 },
     46   "post"  : { "bits": 1 },
     47   "!post" : { "bits": 1 },
     48   "op"    : { "bits": 1 }, // TODO: This should be fixed.
     49   "s"     : { "bits": 1 },
     50   "sz"    : { "bits": 2 },
     51   "msz"   : { "bits": 2 },
     52   "sop"   : { "bits": 2 },
     53   "cond"  : { "bits": 4 },
     54   "nzcv"  : { "bits": 4 },
     55   "cmode" : { "bits": 4 },
     56   "CRn"   : { "bits": 4 },
     57   "CRm"   : { "bits": 4 },
     58 
     59   "Rx"    : { "bits": 5, "read": true , "write": true  },
     60   "Rx2"   : { "bits": 5, "read": true , "write": true  },
     61   "Rdn"   : { "bits": 5, "read": true , "write": true  },
     62   "Rd"    : { "bits": 5, "read": false, "write": true  },
     63   "Rd2"   : { "bits": 5, "read": false, "write": true  },
     64   "Rs"    : { "bits": 5, "read": true , "write": false },
     65   "Rs2"   : { "bits": 5, "read": true , "write": false },
     66   "Rn"    : { "bits": 5, "read": true , "write": false },
     67   "Rm"    : { "bits": 5, "read": true , "write": false },
     68   "Ra"    : { "bits": 5, "read": true , "write": false },
     69   "Rt"    : { "bits": 5, "read": true , "write": false },
     70   "Rt2"   : { "bits": 5, "read": true , "write": false },
     71 
     72   "Wx"    : { "bits": 5, "read": true , "write": true  },
     73   "Wx2"   : { "bits": 5, "read": true , "write": true  },
     74   "Wdn"   : { "bits": 5, "read": true , "write": true  },
     75   "Wd"    : { "bits": 5, "read": false, "write": true  },
     76   "Wd2"   : { "bits": 5, "read": false, "write": true  },
     77   "Ws"    : { "bits": 5, "read": true , "write": false },
     78   "Ws2"   : { "bits": 5, "read": true , "write": false },
     79   "Wn"    : { "bits": 5, "read": true , "write": false },
     80   "Wm"    : { "bits": 5, "read": true , "write": false },
     81   "Wa"    : { "bits": 5, "read": true , "write": false },
     82   "Wt"    : { "bits": 5, "read": true , "write": false },
     83   "Wt2"   : { "bits": 5, "read": true , "write": false },
     84 
     85   "Xx"    : { "bits": 5, "read": true , "write": true  },
     86   "Xx2"   : { "bits": 5, "read": true , "write": true  },
     87   "Xdn"   : { "bits": 5, "read": true , "write": true  },
     88   "Xd"    : { "bits": 5, "read": false, "write": true  },
     89   "Xd2"   : { "bits": 5, "read": false, "write": true  },
     90   "Xs"    : { "bits": 5, "read": true , "write": false },
     91   "Xs2"   : { "bits": 5, "read": true , "write": false },
     92   "Xn"    : { "bits": 5, "read": true , "write": false },
     93   "Xm"    : { "bits": 5, "read": true , "write": false },
     94   "Xa"    : { "bits": 5, "read": true , "write": false },
     95   "Xt"    : { "bits": 5, "read": true , "write": false },
     96   "Xt2"   : { "bits": 5, "read": true , "write": false },
     97 
     98   "Bx"    : { "bits": 5, "read": true , "write": true  },
     99   "Bx2"   : { "bits": 5, "read": true , "write": true  },
    100   "Bdn"   : { "bits": 5, "read": true , "write": true  },
    101   "Bd"    : { "bits": 5, "read": false, "write": true  },
    102   "Bd2"   : { "bits": 5, "read": false, "write": true  },
    103   "Bs"    : { "bits": 5, "read": true , "write": false },
    104   "Bs2"   : { "bits": 5, "read": true , "write": false },
    105   "Bn"    : { "bits": 5, "read": true , "write": false },
    106   "Bm"    : { "bits": 5, "read": true , "write": false },
    107   "Ba"    : { "bits": 5, "read": true , "write": false },
    108 
    109   "Hx"    : { "bits": 5, "read": true , "write": true  },
    110   "Hx2"   : { "bits": 5, "read": true , "write": true  },
    111   "Hdn"   : { "bits": 5, "read": true , "write": true  },
    112   "Hd"    : { "bits": 5, "read": false, "write": true  },
    113   "Hd2"   : { "bits": 5, "read": false, "write": true  },
    114   "Hs"    : { "bits": 5, "read": true , "write": false },
    115   "Hs2"   : { "bits": 5, "read": true , "write": false },
    116   "Hn"    : { "bits": 5, "read": true , "write": false },
    117   "Hm"    : { "bits": 5, "read": true , "write": false },
    118   "Ha"    : { "bits": 5, "read": true , "write": false },
    119 
    120   "Sx"    : { "bits": 5, "read": true , "write": true  },
    121   "Sx2"   : { "bits": 5, "read": true , "write": true  },
    122   "Sdn"   : { "bits": 5, "read": true , "write": true  },
    123   "Sd"    : { "bits": 5, "read": false, "write": true  },
    124   "Sd2"   : { "bits": 5, "read": false, "write": true  },
    125   "Ss"    : { "bits": 5, "read": true , "write": false },
    126   "Ss2"   : { "bits": 5, "read": true , "write": false },
    127   "Sn"    : { "bits": 5, "read": true , "write": false },
    128   "Sm"    : { "bits": 5, "read": true , "write": false },
    129   "Sa"    : { "bits": 5, "read": true , "write": false },
    130 
    131   "Dx"    : { "bits": 5, "read": true , "write": true  },
    132   "Dx2"   : { "bits": 5, "read": true , "write": true  },
    133   "Ddn"   : { "bits": 5, "read": true , "write": true  },
    134   "Dd"    : { "bits": 5, "read": false, "write": true  },
    135   "Dd2"   : { "bits": 5, "read": false, "write": true  },
    136   "Ds"    : { "bits": 5, "read": true , "write": false },
    137   "Ds2"   : { "bits": 5, "read": true , "write": false },
    138   "Dn"    : { "bits": 5, "read": true , "write": false },
    139   "Dn2"   : { "bits": 5, "read": true , "write": false },
    140   "Dm"    : { "bits": 5, "read": true , "write": false },
    141   "Da"    : { "bits": 5, "read": true , "write": false },
    142 
    143   "Qx"    : { "bits": 5, "read": true , "write": true  },
    144   "Qx2"   : { "bits": 5, "read": true , "write": true  },
    145   "Qdn"   : { "bits": 5, "read": true , "write": true  },
    146   "Qd"    : { "bits": 5, "read": false, "write": true  },
    147   "Qd2"   : { "bits": 5, "read": false, "write": true  },
    148   "Qs"    : { "bits": 5, "read": true , "write": false },
    149   "Qs2"   : { "bits": 5, "read": true , "write": false },
    150   "Qn"    : { "bits": 5, "read": true , "write": false },
    151   "Qn2"   : { "bits": 5, "read": true , "write": false },
    152   "Qm"    : { "bits": 5, "read": true , "write": false },
    153   "Qa"    : { "bits": 5, "read": true , "write": false },
    154 
    155   "Vx"    : { "bits": 5, "read": true , "write": true  },
    156   "Vx2"   : { "bits": 5, "read": true , "write": true  },
    157   "Vdn"   : { "bits": 5, "read": true , "write": true  },
    158   "Vd"    : { "bits": 5, "read": false, "write": true  },
    159   "Vd2"   : { "bits": 5, "read": false, "write": true  },
    160   "Vs"    : { "bits": 5, "read": true , "write": false },
    161   "Vs2"   : { "bits": 5, "read": true , "write": false },
    162   "Vn"    : { "bits": 5, "read": true , "write": false },
    163   "Vm"    : { "bits": 5, "read": true , "write": false },
    164   "Va"    : { "bits": 5, "read": true , "write": false },
    165 
    166   "Zx"    : { "bits": 5, "read": true , "write": true  },
    167   "Zx2"   : { "bits": 5, "read": true , "write": true  },
    168   "Zda"   : { "bits": 5, "read": true , "write": true  },
    169   "Zdn"   : { "bits": 5, "read": true , "write": true  },
    170   "Zdn2"  : { "bits": 5, "read": true , "write": true  },
    171   "Zd"    : { "bits": 5, "read": false, "write": true  },
    172   "Zd2"   : { "bits": 5, "read": false, "write": true  },
    173   "Zs"    : { "bits": 5, "read": true , "write": false },
    174   "Zs2"   : { "bits": 5, "read": true , "write": false },
    175   "Zn"    : { "bits": 5, "read": true , "write": false },
    176   "Zm"    : { "bits": 5, "read": true , "write": false },
    177   "Zk"    : { "bits": 5, "read": true , "write": false },
    178   "Za"    : { "bits": 5, "read": true , "write": false },
    179 
    180   "Pdn"   : { "bits": 4, "read": true , "write": true  },
    181   "Pdm"   : { "bits": 4, "read": true , "write": true  },
    182   "Pd"    : { "bits": 4, "read": false, "write": true  },
    183   "Ps"    : { "bits": 4, "read": true , "write": false },
    184   "Pn"    : { "bits": 4, "read": true , "write": false },
    185   "Pm"    : { "bits": 4, "read": true , "write": false },
    186   "Pg"    : { "bits": 4, "read": true , "write": false }
    187 };
    188 
    189 arm.FieldInfo = FieldInfo;
    190 
    191 // AArch64 utilities.
    192 class Utils {
    193   static splitInstructionSignature(s) {
    194     const names = s.match(/^[\w\|]+/)[0];
    195     s = s.substring(names.length);
    196 
    197     const opOffset = s.indexOf(" ")
    198     const suffix = s.substring(0, opOffset).trim();
    199     const operands = opOffset === -1 ? "" : s.substring(opOffset + 1).trim();
    200 
    201     return {
    202       names: names.split("|").map((base)=>{ return base + suffix}),
    203       operands: operands
    204     }
    205   }
    206 
    207   static parseShiftOrExtendOp(s) {
    208     const space = s.indexOf(" ");
    209     if (space === -1)
    210       return "";
    211 
    212     const ops = s.substring(0, space).trim();
    213     for (let op of ops.split("|"))
    214       if (!/^(sop|extend|lsl|lsr|asr|uxtw|sxtw|sxtx|mul)$/.test(op))
    215         return "";
    216 
    217     return ops;
    218   }
    219 }
    220 arm.Utils = Utils;
    221 
    222 function normalizeNumber(n) {
    223   return n < 0 ? 0x100000000 + n : n;
    224 }
    225 
    226 function decomposeOperand(s) {
    227   let type = null;
    228   let element = null;
    229   let consecutive = 0;
    230   let maskType = "";
    231 
    232   const elementM = s.match(/\[#(\w+)\]$/);
    233   if (elementM) {
    234     element = elementM[1];
    235     s = s.substring(0, s.length - elementM[0].length);
    236   }
    237 
    238   const typeM = s.match(/\.(\w+)$/);
    239   if (typeM) {
    240     type = typeM[1];
    241     s = s.substring(0, s.length - typeM[0].length);
    242   }
    243 
    244   const maskM = s.match(/\/(M|Z|MZ)$/);
    245   if (maskM) {
    246     maskType = maskM[1];
    247     s = s.substring(0, s.length - maskM[0].length);
    248   }
    249 
    250   if (s.endsWith("++")) {
    251     consecutive = 2;
    252     s = s.substring(0, s.length - 2);
    253   }
    254   else if (s.endsWith("+")) {
    255     consecutive = 1;
    256     s = s.substring(0, s.length - 1);
    257   }
    258 
    259   let m = s.match(/==|\!=|>=|<=|\*/);
    260   let restrict = false;
    261 
    262   if (m) {
    263     restrict = s.substring(m.index);
    264     s = s.substring(0, m.index);
    265   }
    266 
    267   return {
    268     data       : s,
    269     maskType   : maskType,
    270     type       : type,
    271     element    : element,
    272     restrict   : restrict,
    273     consecutive: consecutive
    274   };
    275 }
    276 
    277 function splitOpcodeFields(s) {
    278   const arr = s.split("|");
    279   const out = [];
    280 
    281   for (let i = 0; i < arr.length; i++) {
    282     const val = arr[i];
    283     if (/^[0-1A-Z]{2,}$/.test(val))
    284       out.push.apply(out, val.match(/([0-1]+)|[A-Z]/g));
    285     else
    286       out.push(val);
    287   }
    288 
    289   return out.map((field)=>{return field.trim(); });
    290 }
    291 
    292 // asmdb.aarch64.Operand
    293 // =====================
    294 
    295 // ARM operand.
    296 class Operand extends base.Operand {
    297   constructor(def) {
    298     super();
    299     this.data = def;
    300 
    301     // Register.
    302     this.sp = "";   // GP register stack access: ["", "WSP" or "SP"].
    303     this.mask = ""; // Masking specifier.
    304   }
    305 
    306   hasMemModes() {
    307     return Object.keys(this.memModes).length !== 0;
    308   }
    309 
    310   get name() {
    311     switch (this.type) {
    312       case "reg": return this.reg;
    313       case "mem": return this.mem;
    314       case "imm": return this.imm;
    315       case "rel": return this.rel;
    316       default   : return "";
    317     }
    318   }
    319 
    320   get scale() {
    321     if (this.restrict && this.restrict.startsWith("*"))
    322       return parseInt(this.restrict.substring(1), 10);
    323     else
    324       return 0;
    325   }
    326 }
    327 arm.Operand = Operand;
    328 
    329 // asmdb.aarch64.Instruction
    330 // =========================
    331 
    332 function patternFromOperand(key) { return key; }
    333 
    334 // ARM instruction.
    335 class Instruction extends base.Instruction {
    336   constructor(db, data) {
    337     super(db, data);
    338 
    339     this.name = data.name;
    340     this.it = dict();                // THUMB's 'it' flags.
    341     this.apsr = dict();
    342     this.fpcsr = dict();
    343     this.calc = dict();              // Calculations required to generate opcode.
    344     this.immCond = [];               // Immediate value conditions (array of conditions).
    345 
    346     this._assignOperands(data.operands);
    347     this._assignOpcode(data.op);
    348 
    349     for (let k in data) {
    350       if (k === "name" || k == "op" || k === "operands")
    351         continue;
    352       this._assignAttribute(k, data[k]);
    353     }
    354 
    355     this._updateOperandsInfo();
    356     this._postProcess();
    357   }
    358 
    359   _assignAttribute(key, value) {
    360     switch (key) {
    361       case "it":
    362         for (let it of value.split(" "))
    363           this.it[it.trim()] = true;
    364         break;
    365 
    366       case "apsr":
    367       case "fpcsr":
    368         this._assignAttributeKeyValue(key, value);
    369         break;
    370 
    371       case "imm":
    372         this.imm = exp.parse(value);
    373         break;
    374 
    375       case "calc":
    376         for (let calcKey in value)
    377           this.calc[calcKey] = exp.parse(value[calcKey]);
    378         break;
    379 
    380       default:
    381         super._assignAttribute(key, value);
    382     }
    383   }
    384 
    385   _assignAttributeKeyValue(name, content) {
    386     const attributes = content.trim().split(/[ ]+/);
    387 
    388     for (let i = 0; i < attributes.length; i++) {
    389       const attr = attributes[i].trim();
    390       if (!attr)
    391         continue;
    392 
    393       const eq = attr.indexOf("=");
    394       let key = eq === -1 ? attr : attr.substring(0, eq);
    395       let val = eq === -1 ? true : attr.substring(eq + 1);
    396 
    397       // If the key contains "|" it's a definition of multiple attributes.
    398       if (key.indexOf("|") !== -1) {
    399         const dot = key.indexOf(".");
    400 
    401         const base = dot === -1 ? "" : key.substring(0, dot + 1);
    402         const keys = (dot === -1 ? key : key.substring(dot + 1)).split("|");
    403 
    404         for (let j = 0; j < keys.length; j++)
    405           this[name][base + keys[j]] = val;
    406       }
    407       else {
    408         this[name][key] = val;
    409       }
    410     }
    411   }
    412 
    413   _assignOperands(s) {
    414     if (!s) return;
    415 
    416     // Split into individual operands and push them to `operands`.
    417     const arr = base.Parsing.splitOperands(s);
    418     for (let i = 0; i < arr.length; i++) {
    419       let def = arr[i].trim();
    420       const op = new Operand(def);
    421 
    422       const sp = def.match(/^(\w+)\|(SP|WSP)$/);
    423       if (sp) {
    424         def = sp[1];
    425         op.sp = sp[2];
    426       }
    427 
    428       const consecutive = def.match(/(\d+)x\{(.*)\}([+]?[+]?)/);
    429       if (consecutive)
    430         def = consecutive[2];
    431 
    432       op.sign = false;
    433       op.element = null;
    434       op.shiftOp = "";
    435       op.shiftImm = null;
    436       op.shiftCond = "";
    437 
    438       // Handle {optional} attribute.
    439       if (Parsing.isOptional(def)) {
    440         op.optional = true;
    441         def = Parsing.clearOptional(def);
    442       }
    443 
    444       // Handle commutativity <-> symbol.
    445       if (Parsing.isCommutative(def)) {
    446         op.commutative = true;
    447         def = Parsing.clearCommutative(def);
    448       }
    449 
    450       // Handle shift operation.
    451       let shiftOp = Utils.parseShiftOrExtendOp(def);
    452       if (shiftOp) {
    453         op.shiftOp = shiftOp;
    454         def = def.substring(shiftOp.length + 1);
    455       }
    456 
    457       if (def.startsWith("[")) {
    458         op.type = "mem";
    459         op.memModes = dict();
    460 
    461         op.base = null;
    462         op.index = null;
    463         op.offset = null;
    464 
    465         let mem = def;
    466         let didHaveMemMode = false;
    467 
    468         for (;;) {
    469           if (mem.endsWith("!")) {
    470             op.memModes.preIndex = true;
    471             mem = mem.substring(0, mem.length - 1);
    472 
    473             didHaveMemMode = true;
    474             break;
    475           }
    476 
    477           if (mem.endsWith("@")) {
    478             op.memModes.postIndex = true;
    479             mem = mem.substring(0, mem.length - 1);
    480 
    481             didHaveMemMode = true;
    482             break;
    483           }
    484 
    485           if (mem.endsWith("{!}")) {
    486             op.memModes.offset = true;
    487             op.memModes.preIndex = true;
    488             mem = mem.substring(0, mem.length - 3);
    489 
    490             didHaveMemMode = true;
    491             continue;
    492           }
    493 
    494           if (mem.endsWith("{@}")) {
    495             op.memModes.offset = true;
    496             op.memModes.postIndex = true;
    497             mem = mem.substring(0, mem.length - 3);
    498 
    499             didHaveMemMode = true;
    500             continue;
    501           }
    502 
    503           break;
    504         }
    505 
    506         if (!mem.endsWith("]"))
    507           FAIL(`Unknown memory operand '${mem}' in '${def}'`);
    508 
    509         let parts = mem.substring(1, mem.length - 1).split(",").map(function(s) { return s.trim() });
    510         for (let i = 0; i < parts.length; i++) {
    511           const part = parts[i];
    512 
    513           const m = part.match(/^\{(([a-z]+)(\|[a-z]+)*)\s+#(\w+)\s*(\*\s*\d+\s*)?\}$/);
    514           if (m) {
    515             op.shiftOp = m[1];
    516             op.shiftImm = m[2];
    517             if (m[3])
    518               op.shiftCond = m[3]
    519             continue;
    520           }
    521 
    522           if (i === 0) {
    523             op.base = dict();
    524             op.base.field = part;
    525             op.base.exp = null;
    526 
    527             const m = part.match(/^([A-Za-z]\w*(?:\.\w+)?)/);
    528             if (m && m[1].length < part.length) {
    529               op.base.exp = exp.parse(part);
    530               op.base.field = m[1];
    531             }
    532           }
    533           else if (part.startsWith("#")) {
    534             let p = part.substring(1);
    535             let u = "1";
    536 
    537             let offExp = null;
    538             let offMul = 1;
    539 
    540             if (p.startsWith("+/-")) {
    541               u = "U";
    542               p = p.substring(3);
    543             }
    544 
    545             const expMatch = p.match(/^([A-Za-z]\w*)==/);
    546             if (expMatch) {
    547               offExp = exp.parse(p);
    548               p = p.substring(0, expMatch[1].length);
    549             }
    550 
    551             const mulMatch = p.match(/\s*\*\s*(\d+)$/);
    552             if (mulMatch) {
    553               offMul = parseInt(mulMatch[1]);
    554               p = p.substring(0, mulMatch.index);
    555             }
    556 
    557             op.offset = dict();
    558             op.offset.field = p;
    559             op.offset.u = u;
    560             op.offset.exp = offExp;
    561             op.offset.mul = offMul;
    562           }
    563           else {
    564             let p = part;
    565             let u = "1";
    566 
    567             if (p.startsWith("+/-")) {
    568               u = "U";
    569               p = p.substring(3);
    570             }
    571 
    572             op.index = dict();
    573             op.index.field = p;
    574             op.index.u = u;
    575 
    576             const m = p.match(/^([A-Za-z\|]\w*(?:\.\w+)?)/);
    577             if (m && m[1].length < p.length) {
    578               op.index.exp = exp.parse(p);
    579               op.index.field = m[1];
    580             }
    581           }
    582         }
    583 
    584         if (!op.hasMemModes() && (op.offset || op.index))
    585           op.memModes.offset = true;
    586 
    587         op.mem = mem;
    588       }
    589       else if (def.startsWith("#")) {
    590         const obj = decomposeOperand(def);
    591         const imm = obj.data;
    592 
    593         op.type = "imm";
    594         op.imm = imm.substring(1);        // Immediate operand name.
    595         op.immSize = 0;                   // Immediate size in bits.
    596         op.restrict = obj.restrict;       // Immediate condition.
    597       }
    598       else {
    599         // Some instructions use Reg! to specify that the register increments.
    600         if (def.endsWith("!")) {
    601           def = def.substring(0, def.length - 1)
    602           op.regInc = true
    603         }
    604 
    605         const obj = decomposeOperand(def);
    606         const reg = obj.data;
    607 
    608         const type = reg.substring(0, 1).toLowerCase();
    609         const info = FieldInfo[reg];
    610 
    611         if (!info)
    612           FAIL(`Unknown register operand '${reg}' in '${def}'`);
    613 
    614         op.type        = info.list ? "reg-list" : "reg";
    615         op.reg         = reg;                // Register name (as specified in manual).
    616         op.regType     = type;               // Register type.
    617         op.regList     = !!info.list;        // Register list.
    618         op.maskType    = obj.maskType;       // Mask type.
    619         op.elementType = obj.type            // Element type or t, ta, tb.
    620         op.read        = info.read;          // Register access (read).
    621         op.write       = info.write;         // Register access (write).
    622         op.element     = obj.element;        // Register element[] access.
    623         op.restrict    = obj.restrict;       // Register condition.
    624         op.consecutive = obj.consecutive;
    625       }
    626 
    627       this.operands.push(op);
    628 
    629       if (consecutive) {
    630         const count = parseInt(consecutive[1]);
    631         for (let n = 2; n <= count; n++) {
    632           const def = consecutive[3].replace(op.reg, op.reg + n);
    633           const opN = new Operand(def);
    634           opN.type = "reg";
    635           opN.reg = op.reg + n;
    636           opN.regType = op.regType;
    637           opN.read = op.read;
    638           opN.write = op.write;
    639           opN.element = op.element;
    640           opN.consecutive = consecutive[3].length;
    641           opN.artificial = true;
    642           this.operands.push(opN);
    643         }
    644       }
    645     }
    646   }
    647 
    648   _assignOpcode(s) {
    649     this.opcodeString = s;
    650 
    651     let opcodeIndex = 0;
    652     let opcodeValue = 0;
    653 
    654     let patternMap = {};
    655 
    656     // Split opcode into its fields.
    657     const arr = splitOpcodeFields(s);
    658     const dup = dict();
    659 
    660     const fields = this.fields;
    661     const pattern = [];
    662 
    663     const fieldMap = Object.create(null);
    664     for (let field of arr) {
    665       fieldMap[field] = true;
    666     }
    667 
    668     for (let i = arr.length - 1; i >= 0; i--) {
    669       let key = arr[i].trim();
    670       let m;
    671 
    672       if (/^[0-1]+$/.test(key)) {
    673         // This part of the opcode is RAW bits, they contribute to the `opcodeValue`.
    674         opcodeValue |= parseInt(key, 2) << opcodeIndex;
    675         opcodeIndex += key.length;
    676         pattern.unshift("_".repeat(key.length));
    677       }
    678       else {
    679         pattern.unshift(patternFromOperand(key));
    680         patternMap[patternFromOperand(key)] = true;
    681 
    682         let size = 0;
    683         let mask = 0;
    684         let bits = 0;
    685         let from = -1;
    686 
    687         let lbit = key.startsWith("'");
    688         let hbit = key.endsWith("'");
    689 
    690         if ((m = key.match(/\[\s*(\d+)\s*\:\s*(\d+)\s*\]$/))) {
    691           const a = parseInt(m[1], 10);
    692           const b = parseInt(m[2], 10);
    693           if (a < b)
    694             FAIL(`Invalid bit range '${key}' in opcode '${s}'`);
    695           from = b;
    696           size = a - b + 1;
    697           mask = ((1 << size) - 1) << b;
    698           key = key.substring(0, m.index).trim();
    699         }
    700         else if ((m = key.match(/\[\s*(\d+)\s*\]$/))) {
    701           from = parseInt(m[1], 10);
    702           size = 1;
    703           mask = 1 << from;
    704           key = key.substring(0, m.index).trim();
    705         }
    706         else if ((m = key.match(/\:\s*(\d+)$/))) {
    707           size = parseInt(m[1], 10);
    708           bits = size;
    709           key = key.substring(0, m.index).trim();
    710         }
    711         else {
    712           const key_ = key;
    713 
    714           if (lbit || hbit) {
    715             from = 0;
    716 
    717             if (lbit && hbit)
    718               FAIL(`Couldn't recognize the format of '${key}' in opcode '${s}'`);
    719 
    720             if (lbit) {
    721               key = key.substring(1);
    722             }
    723 
    724             if (hbit) {
    725               key = key.substring(0, key.length - 1);
    726               from = 4;
    727             }
    728 
    729             size = 1;
    730           }
    731           else if (FieldInfo[key]) {
    732             // Sizes of some standard fields can be assigned automatically.
    733             size = FieldInfo[key].bits;
    734             bits = size;
    735 
    736             if (fieldMap["'" + key])
    737               from = 1;
    738           }
    739           else if (key.length === 1) {
    740             // Sizes of one-letter fields (like 'U', 'F', etc...) is 1 if not specified.
    741             size = 1;
    742             bits = 1;
    743           }
    744           else {
    745             FAIL(`Couldn't recognize the size of '${key}' in opcode '${s}'`);
    746           }
    747 
    748           if (dup[key_] === true) {
    749             bits = 0;
    750             lbit = 0;
    751             hbit = 0;
    752           }
    753           else {
    754             dup[key_] = true;
    755           }
    756         }
    757 
    758         let field = fields[key];
    759         if (!field) {
    760           field = {
    761             index: opcodeIndex,
    762             values: [],
    763             bits: 0,
    764             mask: 0,
    765             lbit: 0,
    766             hbit: 0 // Only 1 if a single quote (') was used.
    767           }
    768           fields[key] = field;
    769         }
    770 
    771         if (from === -1)
    772           from = field.bits;
    773 
    774         field.mask |= mask;
    775         field.bits += bits;
    776         field.lbit += lbit;
    777         field.hbit += hbit;
    778         field.values.push({
    779           index: opcodeIndex,
    780           from: from,
    781           size: size
    782         });
    783 
    784         opcodeIndex += size;
    785       }
    786     }
    787 
    788     for (let i = 0; i < pattern.length; i++)
    789       if (pattern[i] === 'U')
    790         pattern[i] = "_";
    791 
    792     // Normalize all fields.
    793     for (let key in fields) {
    794       const field = fields[key];
    795 
    796       // There should be either number of bits or mask, there shouldn't be both.
    797       if (!field.bits && !field.mask)
    798         FAIL(`Part '${key}' of opcode '${s}' contains neither size nor mask`);
    799 
    800       if (field.bits && field.mask)
    801         FAIL(`Part '${key}' of opcode '${s}' contains both size and mask`);
    802 
    803       if (field.bits)
    804         field.mask = ((1 << field.bits) - 1);
    805       else if (field.mask)
    806         field.bits = 32 - Math.clz32(field.mask);
    807 
    808       // Handle field that used single-quote.
    809       if (field.lbit) {
    810         field.mask = (field.mask << 1) | 0x1;
    811         field.bits++;
    812       }
    813 
    814       if (field.hbit) {
    815         field.mask |= 1 << field.bits;
    816         field.bits++;
    817       }
    818 
    819       const op = this.operandByName(key);
    820       if (op && op.isImm())
    821         op.immSize = field.bits;
    822     }
    823 
    824     // Check if the opcode value has the correct number of bits.
    825     if (opcodeIndex !== 32)
    826       FAIL(`The number of bits '${opcodeIndex}' used by the opcode '${s}' doesn't match 32`);
    827     this.opcodeValue = normalizeNumber(opcodeValue);
    828   }
    829 
    830   _assignSpecificAttribute(key, value) {
    831     switch (key) {
    832       case "it": {
    833         const values = String(value).split("|");
    834         for (let i = 0; i < values.length; i++) {
    835           const value = values[i];
    836           switch (value) {
    837             case "in"  : this.it.IN   = true; break;
    838             case "out" : this.it.OUT  = true; break;
    839             case "any" : this.it.IN   = true;
    840                          this.it.OUT  = true; break;
    841             case "last": this.it.LAST = true; break;
    842             case "def" : this.it.DEF  = true; break;
    843             default:
    844               this.report(`${this.name}: Unhandled IT value '${value}'`);
    845           }
    846         }
    847         return true;
    848       }
    849     }
    850 
    851     return false;
    852   }
    853 
    854   _postProcess() {}
    855 
    856   operandByName(name) {
    857     const operands = this.operands;
    858     for (let i = 0; i < operands.length; i++) {
    859       const op = operands[i];
    860       if (op.name === name)
    861         return op;
    862     }
    863     return null;
    864   }
    865 }
    866 arm.Instruction = Instruction;
    867 
    868 // asmdb.aarch64.ISA
    869 // =================
    870 
    871 function mergeGroupData(data, group) {
    872   for (let k in group) {
    873     switch (k) {
    874       case "group":
    875       case "data":
    876         break;
    877 
    878       case "ext":
    879         data[k] = (data[k] ? data[k] + " " : "") + group[k];
    880         break;
    881 
    882       default:
    883         if (data[k] === undefined)
    884           data[k] = group[k]
    885         break;
    886     }
    887   }
    888 }
    889 
    890 class ISA extends base.ISA {
    891   constructor(data) {
    892     super(data);
    893     this.addData(data || NONE);
    894   }
    895 
    896   _addInstructions(groups) {
    897     for (let group of groups) {
    898       for (let instructions of group.data) {
    899         const sgn = Utils.splitInstructionSignature(instructions.inst);
    900         const data = MapUtils.cloneExcept(instructions, { "inst": true });
    901 
    902         mergeGroupData(data, group)
    903 
    904         for (let j = 0; j < sgn.names.length; j++) {
    905           data.name = sgn.names[j];
    906           data.operands = sgn.operands;
    907           if (j > 0)
    908             data.aliasOf = sgn.names[0];
    909           this._addInstruction(new Instruction(this, data));
    910         }
    911       }
    912     }
    913 
    914     return this;
    915   }
    916 }
    917 arm.ISA = ISA;
    918 
    919 }).apply(this, typeof module === "object" && module && module.exports
    920   ? [module, "exports"] : [this.asmdb || (this.asmdb = {}), "aarch64"]);