diff options
author | Nick Clifton <nickc@redhat.com> | 2012-08-13 14:52:54 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2012-08-13 14:52:54 +0000 |
commit | a06ea96464a2928865beb2ac6f12deb0464bfcd7 (patch) | |
tree | 5af98be87fc6e7ea4e8197c241698b97cceeafb8 /opcodes | |
parent | f47f77df4e0f38c96bf5a4c4d8ecda6c73f5ffc2 (diff) | |
download | gdb-a06ea96464a2928865beb2ac6f12deb0464bfcd7.zip gdb-a06ea96464a2928865beb2ac6f12deb0464bfcd7.tar.gz gdb-a06ea96464a2928865beb2ac6f12deb0464bfcd7.tar.bz2 |
Add support for 64-bit ARM architecture: AArch64
Diffstat (limited to 'opcodes')
-rw-r--r-- | opcodes/ChangeLog | 29 | ||||
-rw-r--r-- | opcodes/Makefile.am | 31 | ||||
-rw-r--r-- | opcodes/Makefile.in | 37 | ||||
-rw-r--r-- | opcodes/aarch64-asm-2.c | 345 | ||||
-rw-r--r-- | opcodes/aarch64-asm.c | 1268 | ||||
-rw-r--r-- | opcodes/aarch64-asm.h | 73 | ||||
-rw-r--r-- | opcodes/aarch64-dis-2.c | 7655 | ||||
-rw-r--r-- | opcodes/aarch64-dis.c | 2392 | ||||
-rw-r--r-- | opcodes/aarch64-dis.h | 94 | ||||
-rw-r--r-- | opcodes/aarch64-gen.c | 1317 | ||||
-rw-r--r-- | opcodes/aarch64-opc-2.c | 195 | ||||
-rw-r--r-- | opcodes/aarch64-opc.c | 3074 | ||||
-rw-r--r-- | opcodes/aarch64-opc.h | 392 | ||||
-rw-r--r-- | opcodes/aarch64-tbl.h | 2253 | ||||
-rwxr-xr-x | opcodes/configure | 1 | ||||
-rw-r--r-- | opcodes/configure.in | 1 | ||||
-rw-r--r-- | opcodes/disassemble.c | 15 |
17 files changed, 19164 insertions, 8 deletions
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 4379c1c..91a0dee 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,32 @@ +2012-08-13 Ian Bolton <ian.bolton@arm.com> + Laurent Desnogues <laurent.desnogues@arm.com> + Jim MacArthur <jim.macarthur@arm.com> + Marcus Shawcroft <marcus.shawcroft@arm.com> + Nigel Stephens <nigel.stephens@arm.com> + Ramana Radhakrishnan <ramana.radhakrishnan@arm.com> + Richard Earnshaw <rearnsha@arm.com> + Sofiane Naci <sofiane.naci@arm.com> + Tejas Belagod <tejas.belagod@arm.com> + Yufeng Zhang <yufeng.zhang@arm.com> + + * Makefile.am: Add AArch64. + * Makefile.in: Regenerate. + * aarch64-asm.c: New file. + * aarch64-asm.h: New file. + * aarch64-dis.c: New file. + * aarch64-dis.h: New file. + * aarch64-gen.c: New file. + * aarch64-opc.c: New file. + * aarch64-opc.h: New file. + * aarch64-tbl.h: New file. + * configure.in: Add AArch64. + * configure: Regenerate. + * disassemble.c: Add AArch64. + * aarch64-asm-2.c: New file (automatically generated). + * aarch64-dis-2.c: New file (automatically generated). + * aarch64-opc-2.c: New file (automatically generated). + * po/POTFILES.in: Regenerate. + 2012-08-13 Maciej W. Rozycki <macro@codesourcery.com> * micromips-opc.c (micromips_opcodes): Update comment. diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am index f76776c..3e6ceeb 100644 --- a/opcodes/Makefile.am +++ b/opcodes/Makefile.am @@ -42,6 +42,7 @@ BUILD_LIB_DEPS = @BUILD_LIB_DEPS@ # Header files. HFILES = \ + aarch64-asm.h aarch64-dis.h aarch64-opc.h aarch64-tbl.h \ epiphany-desc.h epiphany-opc.h \ fr30-desc.h fr30-opc.h \ frv-desc.h frv-opc.h \ @@ -74,6 +75,12 @@ HFILES = \ # C source files that correspond to .o's ending up in libopcodes # for all machines. TARGET_LIBOPCODES_CFILES = \ + aarch64-asm.c \ + aarch64-asm-2.c \ + aarch64-dis.c \ + aarch64-dis-2.c \ + aarch64-opc.c \ + aarch64-opc-2.c \ alpha-dis.c \ alpha-opc.c \ arc-dis.c \ @@ -250,6 +257,7 @@ LIBOPCODES_CFILES = \ # C source files that correspond to .o's. CFILES = \ $(LIBOPCODES_CFILES) \ + aarch64-gen.c \ i386-gen.c \ ia64-asmtab.c \ ia64-gen.c \ @@ -481,15 +489,30 @@ stamp-xstormy16: $(CGENDEPS) $(CPUDIR)/xstormy16.cpu $(CPUDIR)/xstormy16.opc $(MAKE) run-cgen arch=xstormy16 prefix=xstormy16 options= \ archfile=$(CPUDIR)/xstormy16.cpu opcfile=$(CPUDIR)/xstormy16.opc extrafiles= -MOSTLYCLEANFILES = i386-gen$(EXEEXT_FOR_BUILD) ia64-gen$(EXEEXT_FOR_BUILD) \ - s390-mkopc$(EXEEXT_FOR_BUILD) s390-opc.tab z8kgen$(EXEEXT_FOR_BUILD) \ - opc2c$(EXEEXT_FOR_BUILD) +MOSTLYCLEANFILES = aarch64-gen$(EXEEXT_FOR_BUILD) i386-gen$(EXEEXT_FOR_BUILD) \ + ia64-gen$(EXEEXT_FOR_BUILD) s390-mkopc$(EXEEXT_FOR_BUILD) s390-opc.tab \ + z8kgen$(EXEEXT_FOR_BUILD) opc2c$(EXEEXT_FOR_BUILD) -MAINTAINERCLEANFILES = $(srcdir)/i386-tbl.h $(srcdir)/i386-init.h \ +MAINTAINERCLEANFILES = $(srcdir)/aarch64-asm-2.c $(srcdir)/aarch64-dis-2.c \ + $(srcdir)/aarch64-opc-2.c $(srcdir)/i386-tbl.h $(srcdir)/i386-init.h \ $(srcdir)/ia64-asmtab.c $(srcdir)/z8k-opc.h \ $(srcdir)/rl78-decode.c \ $(srcdir)/rx-decode.c +aarch64-gen$(EXEEXT_FOR_BUILD): aarch64-gen.o $(BUILD_LIB_DEPS) + $(LINK_FOR_BUILD) aarch64-gen.o $(BUILD_LIBS) + +aarch64-gen.o: aarch64-gen.c $(BFD_H) $(INCDIR)/getopt.h $(INCDIR)/libiberty.h\ + $(INCDIR)/opcode/aarch64.h config.h aarch64-opc.h aarch64-tbl.h + $(COMPILE_FOR_BUILD) -c $(srcdir)/aarch64-gen.c + +$(srcdir)/aarch64-asm-2.c: @MAINT@ aarch64-gen$(exeext_for_build) + ./aarch64-gen$(exeext_for_build) --gen-asm > $@ +$(srcdir)/aarch64-dis-2.c: @MAINT@ aarch64-gen$(exeext_for_build) + ./aarch64-gen$(exeext_for_build) --gen-dis > $@ +$(srcdir)/aarch64-opc-2.c: @MAINT@ aarch64-gen$(exeext_for_build) + ./aarch64-gen$(exeext_for_build) --gen-opc > $@ + i386-gen$(EXEEXT_FOR_BUILD): i386-gen.o $(BUILD_LIB_DEPS) $(LINK_FOR_BUILD) i386-gen.o $(BUILD_LIBS) diff --git a/opcodes/Makefile.in b/opcodes/Makefile.in index f51c98d..56d4734 100644 --- a/opcodes/Makefile.in +++ b/opcodes/Makefile.in @@ -312,6 +312,7 @@ BFD_H = ../bfd/bfd.h # Header files. HFILES = \ + aarch64-asm.h aarch64-dis.h aarch64-opc.h aarch64-tbl.h \ epiphany-desc.h epiphany-opc.h \ fr30-desc.h fr30-opc.h \ frv-desc.h frv-opc.h \ @@ -345,6 +346,12 @@ HFILES = \ # C source files that correspond to .o's ending up in libopcodes # for all machines. TARGET_LIBOPCODES_CFILES = \ + aarch64-asm.c \ + aarch64-asm-2.c \ + aarch64-dis.c \ + aarch64-dis-2.c \ + aarch64-opc.c \ + aarch64-opc-2.c \ alpha-dis.c \ alpha-opc.c \ arc-dis.c \ @@ -523,6 +530,7 @@ LIBOPCODES_CFILES = \ # C source files that correspond to .o's. CFILES = \ $(LIBOPCODES_CFILES) \ + aarch64-gen.c \ i386-gen.c \ ia64-asmtab.c \ ia64-gen.c \ @@ -605,11 +613,12 @@ CGEN_CPUS = epiphany fr30 frv ip2k iq2000 lm32 m32c m32r mep mt openrisc xc16x x @CGEN_MAINT_TRUE@XC16X_DEPS = stamp-xc16x @CGEN_MAINT_FALSE@XSTORMY16_DEPS = @CGEN_MAINT_TRUE@XSTORMY16_DEPS = stamp-xstormy16 -MOSTLYCLEANFILES = i386-gen$(EXEEXT_FOR_BUILD) ia64-gen$(EXEEXT_FOR_BUILD) \ - s390-mkopc$(EXEEXT_FOR_BUILD) s390-opc.tab z8kgen$(EXEEXT_FOR_BUILD) \ - opc2c$(EXEEXT_FOR_BUILD) +MOSTLYCLEANFILES = aarch64-gen$(EXEEXT_FOR_BUILD) i386-gen$(EXEEXT_FOR_BUILD) \ + ia64-gen$(EXEEXT_FOR_BUILD) s390-mkopc$(EXEEXT_FOR_BUILD) s390-opc.tab \ + z8kgen$(EXEEXT_FOR_BUILD) opc2c$(EXEEXT_FOR_BUILD) -MAINTAINERCLEANFILES = $(srcdir)/i386-tbl.h $(srcdir)/i386-init.h \ +MAINTAINERCLEANFILES = $(srcdir)/aarch64-asm-2.c $(srcdir)/aarch64-dis-2.c \ + $(srcdir)/aarch64-opc-2.c $(srcdir)/i386-tbl.h $(srcdir)/i386-init.h \ $(srcdir)/ia64-asmtab.c $(srcdir)/z8k-opc.h \ $(srcdir)/rl78-decode.c \ $(srcdir)/rx-decode.c @@ -730,6 +739,12 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aarch64-asm-2.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aarch64-asm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aarch64-dis-2.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aarch64-dis.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aarch64-opc-2.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aarch64-opc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alpha-dis.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alpha-opc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arc-dis.Plo@am__quote@ @@ -1345,6 +1360,20 @@ stamp-xstormy16: $(CGENDEPS) $(CPUDIR)/xstormy16.cpu $(CPUDIR)/xstormy16.opc $(MAKE) run-cgen arch=xstormy16 prefix=xstormy16 options= \ archfile=$(CPUDIR)/xstormy16.cpu opcfile=$(CPUDIR)/xstormy16.opc extrafiles= +aarch64-gen$(EXEEXT_FOR_BUILD): aarch64-gen.o $(BUILD_LIB_DEPS) + $(LINK_FOR_BUILD) aarch64-gen.o $(BUILD_LIBS) + +aarch64-gen.o: aarch64-gen.c $(BFD_H) $(INCDIR)/getopt.h $(INCDIR)/libiberty.h\ + $(INCDIR)/opcode/aarch64.h config.h aarch64-opc.h aarch64-tbl.h + $(COMPILE_FOR_BUILD) -c $(srcdir)/aarch64-gen.c + +$(srcdir)/aarch64-asm-2.c: @MAINT@ aarch64-gen$(exeext_for_build) + ./aarch64-gen$(exeext_for_build) --gen-asm > $@ +$(srcdir)/aarch64-dis-2.c: @MAINT@ aarch64-gen$(exeext_for_build) + ./aarch64-gen$(exeext_for_build) --gen-dis > $@ +$(srcdir)/aarch64-opc-2.c: @MAINT@ aarch64-gen$(exeext_for_build) + ./aarch64-gen$(exeext_for_build) --gen-opc > $@ + i386-gen$(EXEEXT_FOR_BUILD): i386-gen.o $(BUILD_LIB_DEPS) $(LINK_FOR_BUILD) i386-gen.o $(BUILD_LIBS) diff --git a/opcodes/aarch64-asm-2.c b/opcodes/aarch64-asm-2.c new file mode 100644 index 0000000..b633b86 --- /dev/null +++ b/opcodes/aarch64-asm-2.c @@ -0,0 +1,345 @@ +/* This file is automatically generated by aarch64-gen. Do not edit! */ +/* Copyright 2012 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING3. If not, + see <http://www.gnu.org/licenses/>. */ + +#include "sysdep.h" +#include "aarch64-asm.h" + + +const aarch64_opcode * +aarch64_find_real_opcode (const aarch64_opcode *opcode) +{ + /* Use the index as the key to locate the real opcode. */ + int key = opcode - aarch64_opcode_table; + int value; + switch (key) + { + case 3: /* ngc */ + value = 2; /* --> sbc. */ + break; + case 5: /* ngcs */ + value = 4; /* --> sbcs. */ + break; + case 8: /* cmn */ + value = 7; /* --> adds. */ + break; + case 11: /* cmp */ + value = 10; /* --> subs. */ + break; + case 13: /* mov */ + value = 12; /* --> add. */ + break; + case 15: /* cmn */ + value = 14; /* --> adds. */ + break; + case 18: /* cmp */ + value = 17; /* --> subs. */ + break; + case 21: /* cmn */ + value = 20; /* --> adds. */ + break; + case 23: /* neg */ + value = 22; /* --> sub. */ + break; + case 26: /* negs */ + case 25: /* cmp */ + value = 24; /* --> subs. */ + break; + case 139: /* mov */ + value = 138; /* --> umov. */ + break; + case 141: /* mov */ + value = 140; /* --> ins. */ + break; + case 143: /* mov */ + value = 142; /* --> ins. */ + break; + case 204: /* mvn */ + value = 203; /* --> not. */ + break; + case 259: /* mov */ + value = 258; /* --> orr. */ + break; + case 427: /* mov */ + value = 426; /* --> dup. */ + break; + case 494: /* sxtw */ + case 493: /* sxth */ + case 492: /* sxtb */ + case 495: /* asr */ + case 491: /* sbfx */ + case 490: /* sbfiz */ + value = 489; /* --> sbfm. */ + break; + case 498: /* bfxil */ + case 497: /* bfi */ + value = 496; /* --> bfm. */ + break; + case 503: /* uxth */ + case 502: /* uxtb */ + case 505: /* lsr */ + case 504: /* lsl */ + case 501: /* ubfx */ + case 500: /* ubfiz */ + value = 499; /* --> ubfm. */ + break; + case 523: /* cset */ + case 522: /* cinc */ + value = 521; /* --> csinc. */ + break; + case 526: /* csetm */ + case 525: /* cinv */ + value = 524; /* --> csinv. */ + break; + case 528: /* cneg */ + value = 527; /* --> csneg. */ + break; + case 553: /* lsl */ + value = 552; /* --> lslv. */ + break; + case 555: /* lsr */ + value = 554; /* --> lsrv. */ + break; + case 557: /* asr */ + value = 556; /* --> asrv. */ + break; + case 559: /* ror */ + value = 558; /* --> rorv. */ + break; + case 561: /* mul */ + value = 560; /* --> madd. */ + break; + case 563: /* mneg */ + value = 562; /* --> msub. */ + break; + case 565: /* smull */ + value = 564; /* --> smaddl. */ + break; + case 567: /* smnegl */ + value = 566; /* --> smsubl. */ + break; + case 570: /* umull */ + value = 569; /* --> umaddl. */ + break; + case 572: /* umnegl */ + value = 571; /* --> umsubl. */ + break; + case 583: /* ror */ + value = 582; /* --> extr. */ + break; + case 683: /* strb */ + value = 681; /* --> sturb. */ + break; + case 684: /* ldrb */ + value = 682; /* --> ldurb. */ + break; + case 686: /* ldrsb */ + value = 685; /* --> ldursb. */ + break; + case 689: /* str */ + value = 687; /* --> stur. */ + break; + case 690: /* ldr */ + value = 688; /* --> ldur. */ + break; + case 693: /* strh */ + value = 691; /* --> sturh. */ + break; + case 694: /* ldrh */ + value = 692; /* --> ldurh. */ + break; + case 696: /* ldrsh */ + value = 695; /* --> ldursh. */ + break; + case 699: /* str */ + value = 697; /* --> stur. */ + break; + case 700: /* ldr */ + value = 698; /* --> ldur. */ + break; + case 702: /* ldrsw */ + value = 701; /* --> ldursw. */ + break; + case 704: /* prfm */ + value = 703; /* --> prfum. */ + break; + case 746: /* bic */ + value = 745; /* --> and. */ + break; + case 748: /* mov */ + value = 747; /* --> orr. */ + break; + case 751: /* tst */ + value = 750; /* --> ands. */ + break; + case 756: /* uxtw */ + case 755: /* mov */ + value = 754; /* --> orr. */ + break; + case 758: /* mvn */ + value = 757; /* --> orn. */ + break; + case 762: /* tst */ + value = 761; /* --> ands. */ + break; + case 765: /* mov */ + value = 764; /* --> movn. */ + break; + case 767: /* mov */ + value = 766; /* --> movz. */ + break; + case 778: /* sevl */ + case 777: /* sev */ + case 776: /* wfi */ + case 775: /* wfe */ + case 774: /* yield */ + case 773: /* nop */ + value = 772; /* --> hint. */ + break; + case 787: /* tlbi */ + case 786: /* ic */ + case 785: /* dc */ + case 784: /* at */ + value = 783; /* --> sys. */ + break; + default: return NULL; + } + + return aarch64_opcode_table + value; +} + +const char* +aarch64_insert_operand (const aarch64_operand *self, + const aarch64_opnd_info *info, + aarch64_insn *code, const aarch64_inst *inst) +{ + /* Use the index as the key. */ + int key = self - aarch64_operands; + switch (key) + { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 13: + case 14: + case 15: + case 16: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 34: + case 35: + return aarch64_ins_regno (self, info, code, inst); + case 11: + return aarch64_ins_reg_extended (self, info, code, inst); + case 12: + return aarch64_ins_reg_shifted (self, info, code, inst); + case 17: + return aarch64_ins_ft (self, info, code, inst); + case 27: + case 28: + case 29: + return aarch64_ins_reglane (self, info, code, inst); + case 30: + return aarch64_ins_reglist (self, info, code, inst); + case 31: + return aarch64_ins_ldst_reglist (self, info, code, inst); + case 32: + return aarch64_ins_ldst_reglist_r (self, info, code, inst); + case 33: + return aarch64_ins_ldst_elemlist (self, info, code, inst); + case 36: + case 45: + case 46: + case 47: + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case 65: + case 66: + case 67: + case 68: + return aarch64_ins_imm (self, info, code, inst); + case 37: + case 38: + return aarch64_ins_advsimd_imm_shift (self, info, code, inst); + case 39: + case 40: + case 41: + return aarch64_ins_advsimd_imm_modified (self, info, code, inst); + case 58: + return aarch64_ins_limm (self, info, code, inst); + case 59: + return aarch64_ins_aimm (self, info, code, inst); + case 60: + return aarch64_ins_imm_half (self, info, code, inst); + case 61: + return aarch64_ins_fbits (self, info, code, inst); + case 63: + return aarch64_ins_cond (self, info, code, inst); + case 69: + case 75: + return aarch64_ins_addr_simple (self, info, code, inst); + case 70: + return aarch64_ins_addr_regoff (self, info, code, inst); + case 71: + case 72: + case 73: + return aarch64_ins_addr_simm (self, info, code, inst); + case 74: + return aarch64_ins_addr_uimm12 (self, info, code, inst); + case 76: + return aarch64_ins_simd_addr_post (self, info, code, inst); + case 77: + return aarch64_ins_sysreg (self, info, code, inst); + case 78: + return aarch64_ins_pstatefield (self, info, code, inst); + case 79: + case 80: + case 81: + case 82: + return aarch64_ins_sysins_op (self, info, code, inst); + case 83: + case 84: + return aarch64_ins_barrier (self, info, code, inst); + case 85: + return aarch64_ins_prfop (self, info, code, inst); + default: assert (0); abort (); + } +} diff --git a/opcodes/aarch64-asm.c b/opcodes/aarch64-asm.c new file mode 100644 index 0000000..e10240a --- /dev/null +++ b/opcodes/aarch64-asm.c @@ -0,0 +1,1268 @@ +/* aarch64-asm.c -- AArch64 assembler support. + Copyright 2012 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING3. If not, + see <http://www.gnu.org/licenses/>. */ + +#include "sysdep.h" +#include <stdarg.h> +#include "aarch64-asm.h" + +/* Utilities. */ + +/* The unnamed arguments consist of the number of fields and information about + these fields where the VALUE will be inserted into CODE. MASK can be zero or + the base mask of the opcode. + + N.B. the fields are required to be in such an order than the least signficant + field for VALUE comes the first, e.g. the <index> in + SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>] + is encoded in H:L:M in some cases, the the fields H:L:M should be passed in + the order of M, L, H. */ + +static inline void +insert_fields (aarch64_insn *code, aarch64_insn value, aarch64_insn mask, ...) +{ + uint32_t num; + const aarch64_field *field; + enum aarch64_field_kind kind; + va_list va; + + va_start (va, mask); + num = va_arg (va, uint32_t); + assert (num <= 5); + while (num--) + { + kind = va_arg (va, enum aarch64_field_kind); + field = &fields[kind]; + insert_field (kind, code, value, mask); + value >>= field->width; + } + va_end (va); +} + +/* Operand inserters. */ + +/* Insert register number. */ +const char * +aarch64_ins_regno (const aarch64_operand *self, const aarch64_opnd_info *info, + aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + insert_field (self->fields[0], code, info->reg.regno, 0); + return NULL; +} + +/* Insert register number, index and/or other data for SIMD register element + operand, e.g. the last source operand in + SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>]. */ +const char * +aarch64_ins_reglane (const aarch64_operand *self, const aarch64_opnd_info *info, + aarch64_insn *code, const aarch64_inst *inst) +{ + /* regno */ + insert_field (self->fields[0], code, info->reglane.regno, inst->opcode->mask); + /* index and/or type */ + if (inst->opcode->iclass == asisdone || inst->opcode->iclass == asimdins) + { + int pos = info->qualifier - AARCH64_OPND_QLF_S_B; + if (info->type == AARCH64_OPND_En + && inst->opcode->operands[0] == AARCH64_OPND_Ed) + { + /* index2 for e.g. INS <Vd>.<Ts>[<index1>], <Vn>.<Ts>[<index2>]. */ + assert (info->idx == 1); /* Vn */ + aarch64_insn value = info->reglane.index << pos; + insert_field (FLD_imm4, code, value, 0); + } + else + { + /* index and type for e.g. DUP <V><d>, <Vn>.<T>[<index>]. + imm5<3:0> <V> + 0000 RESERVED + xxx1 B + xx10 H + x100 S + 1000 D */ + aarch64_insn value = ((info->reglane.index << 1) | 1) << pos; + insert_field (FLD_imm5, code, value, 0); + } + } + else + { + /* index for e.g. SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>] + or SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>]. */ + switch (info->qualifier) + { + case AARCH64_OPND_QLF_S_H: + /* H:L:M */ + insert_fields (code, info->reglane.index, 0, 3, FLD_M, FLD_L, FLD_H); + break; + case AARCH64_OPND_QLF_S_S: + /* H:L */ + insert_fields (code, info->reglane.index, 0, 2, FLD_L, FLD_H); + break; + case AARCH64_OPND_QLF_S_D: + /* H */ + insert_field (FLD_H, code, info->reglane.index, 0); + break; + default: + assert (0); + } + } + return NULL; +} + +/* Insert regno and len field of a register list operand, e.g. Vn in TBL. */ +const char * +aarch64_ins_reglist (const aarch64_operand *self, const aarch64_opnd_info *info, + aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* R */ + insert_field (self->fields[0], code, info->reglist.first_regno, 0); + /* len */ + insert_field (FLD_len, code, info->reglist.num_regs - 1, 0); + return NULL; +} + +/* Insert Rt and opcode fields for a register list operand, e.g. Vt + in AdvSIMD load/store instructions. */ +const char * +aarch64_ins_ldst_reglist (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst) +{ + aarch64_insn value; + /* Number of elements in each structure to be loaded/stored. */ + unsigned num = get_opcode_dependent_value (inst->opcode); + + /* Rt */ + insert_field (FLD_Rt, code, info->reglist.first_regno, 0); + /* opcode */ + switch (num) + { + case 1: + switch (info->reglist.num_regs) + { + case 1: value = 0x7; break; + case 2: value = 0xa; break; + case 3: value = 0x6; break; + case 4: value = 0x2; break; + default: assert (0); + } + break; + case 2: + value = info->reglist.num_regs == 4 ? 0x3 : 0x8; + break; + case 3: + value = 0x4; + break; + case 4: + value = 0x0; + break; + default: + assert (0); + } + insert_field (FLD_opcode, code, value, 0); + + return NULL; +} + +/* Insert Rt and S fields for a register list operand, e.g. Vt in AdvSIMD load + single structure to all lanes instructions. */ +const char * +aarch64_ins_ldst_reglist_r (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst) +{ + aarch64_insn value; + /* The opcode dependent area stores the number of elements in + each structure to be loaded/stored. */ + int is_ld1r = get_opcode_dependent_value (inst->opcode) == 1; + + /* Rt */ + insert_field (FLD_Rt, code, info->reglist.first_regno, 0); + /* S */ + value = (aarch64_insn) 0; + if (is_ld1r && info->reglist.num_regs == 2) + /* OP_LD1R does not have alternating variant, but have "two consecutive" + instead. */ + value = (aarch64_insn) 1; + insert_field (FLD_S, code, value, 0); + + return NULL; +} + +/* Insert Q, opcode<2:1>, S, size and Rt fields for a register element list + operand e.g. Vt in AdvSIMD load/store single element instructions. */ +const char * +aarch64_ins_ldst_elemlist (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + aarch64_field field = {0, 0}; + aarch64_insn QSsize; /* fields Q:S:size. */ + aarch64_insn opcodeh2; /* opcode<2:1> */ + + assert (info->reglist.has_index); + + /* Rt */ + insert_field (FLD_Rt, code, info->reglist.first_regno, 0); + /* Encode the index, opcode<2:1> and size. */ + switch (info->qualifier) + { + case AARCH64_OPND_QLF_S_B: + /* Index encoded in "Q:S:size". */ + QSsize = info->reglist.index; + opcodeh2 = 0x0; + break; + case AARCH64_OPND_QLF_S_H: + /* Index encoded in "Q:S:size<1>". */ + QSsize = info->reglist.index << 1; + opcodeh2 = 0x1; + break; + case AARCH64_OPND_QLF_S_S: + /* Index encoded in "Q:S". */ + QSsize = info->reglist.index << 2; + opcodeh2 = 0x2; + break; + case AARCH64_OPND_QLF_S_D: + /* Index encoded in "Q". */ + QSsize = info->reglist.index << 3 | 0x1; + opcodeh2 = 0x2; + break; + default: + assert (0); + } + insert_fields (code, QSsize, 0, 3, FLD_vldst_size, FLD_S, FLD_Q); + gen_sub_field (FLD_asisdlso_opcode, 1, 2, &field); + insert_field_2 (&field, code, opcodeh2, 0); + + return NULL; +} + +/* Insert fields immh:immb and/or Q for e.g. the shift immediate in + SSHR <Vd>.<T>, <Vn>.<T>, #<shift> + or SSHR <V><d>, <V><n>, #<shift>. */ +const char * +aarch64_ins_advsimd_imm_shift (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, + aarch64_insn *code, const aarch64_inst *inst) +{ + unsigned val = aarch64_get_qualifier_standard_value (info->qualifier); + aarch64_insn Q, imm; + + if (inst->opcode->iclass == asimdshf) + { + /* Q + immh Q <T> + 0000 x SEE AdvSIMD modified immediate + 0001 0 8B + 0001 1 16B + 001x 0 4H + 001x 1 8H + 01xx 0 2S + 01xx 1 4S + 1xxx 0 RESERVED + 1xxx 1 2D */ + Q = (val & 0x1) ? 1 : 0; + insert_field (FLD_Q, code, Q, inst->opcode->mask); + val >>= 1; + } + + assert (info->type == AARCH64_OPND_IMM_VLSR + || info->type == AARCH64_OPND_IMM_VLSL); + + if (info->type == AARCH64_OPND_IMM_VLSR) + /* immh:immb + immh <shift> + 0000 SEE AdvSIMD modified immediate + 0001 (16-UInt(immh:immb)) + 001x (32-UInt(immh:immb)) + 01xx (64-UInt(immh:immb)) + 1xxx (128-UInt(immh:immb)) */ + imm = (16 << (unsigned)val) - info->imm.value; + else + /* immh:immb + immh <shift> + 0000 SEE AdvSIMD modified immediate + 0001 (UInt(immh:immb)-8) + 001x (UInt(immh:immb)-16) + 01xx (UInt(immh:immb)-32) + 1xxx (UInt(immh:immb)-64) */ + imm = info->imm.value + (8 << (unsigned)val); + insert_fields (code, imm, 0, 2, FLD_immb, FLD_immh); + + return NULL; +} + +/* Insert fields for e.g. the immediate operands in + BFM <Wd>, <Wn>, #<immr>, #<imms>. */ +const char * +aarch64_ins_imm (const aarch64_operand *self, const aarch64_opnd_info *info, + aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + int64_t imm; + /* Maximum of two fields to insert. */ + assert (self->fields[2] == FLD_NIL); + + imm = info->imm.value; + if (operand_need_shift_by_two (self)) + imm >>= 2; + if (self->fields[1] == FLD_NIL) + insert_field (self->fields[0], code, imm, 0); + else + /* e.g. TBZ b5:b40. */ + insert_fields (code, imm, 0, 2, self->fields[1], self->fields[0]); + return NULL; +} + +/* Insert immediate and its shift amount for e.g. the last operand in + MOVZ <Wd>, #<imm16>{, LSL #<shift>}. */ +const char * +aarch64_ins_imm_half (const aarch64_operand *self, const aarch64_opnd_info *info, + aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* imm16 */ + aarch64_ins_imm (self, info, code, inst); + /* hw */ + insert_field (FLD_hw, code, info->shifter.amount >> 4, 0); + return NULL; +} + +/* Insert cmode and "a:b:c:d:e:f:g:h" fields for e.g. the last operand in + MOVI <Vd>.<T>, #<imm8> {, LSL #<amount>}. */ +const char * +aarch64_ins_advsimd_imm_modified (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, + aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + enum aarch64_opnd_qualifier opnd0_qualifier = inst->operands[0].qualifier; + uint64_t imm = info->imm.value; + enum aarch64_modifier_kind kind = info->shifter.kind; + int amount = info->shifter.amount; + aarch64_field field = {0, 0}; + + /* a:b:c:d:e:f:g:h */ + if (!info->imm.is_fp && aarch64_get_qualifier_esize (opnd0_qualifier) == 8) + { + /* Either MOVI <Dd>, #<imm> + or MOVI <Vd>.2D, #<imm>. + <imm> is a 64-bit immediate + "aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh", + encoded in "a:b:c:d:e:f:g:h". */ + imm = aarch64_shrink_expanded_imm8 (imm); + assert ((int)imm >= 0); + } + assert (imm <= 255); + insert_fields (code, imm, 0, 2, FLD_defgh, FLD_abc); + + if (kind == AARCH64_MOD_NONE) + return NULL; + + /* shift amount partially in cmode */ + assert (kind == AARCH64_MOD_LSL || kind == AARCH64_MOD_MSL); + if (kind == AARCH64_MOD_LSL) + { + /* AARCH64_MOD_LSL: shift zeros. */ + int esize = aarch64_get_qualifier_esize (opnd0_qualifier); + assert (esize == 4 || esize == 2); + amount >>= 3; + if (esize == 4) + gen_sub_field (FLD_cmode, 1, 2, &field); /* per word */ + else + gen_sub_field (FLD_cmode, 1, 1, &field); /* per halfword */ + } + else + { + /* AARCH64_MOD_MSL: shift ones. */ + amount >>= 4; + gen_sub_field (FLD_cmode, 0, 1, &field); /* per word */ + } + insert_field_2 (&field, code, amount, 0); + + return NULL; +} + +/* Insert #<fbits> for the immediate operand in fp fix-point instructions, + e.g. SCVTF <Dd>, <Wn>, #<fbits>. */ +const char * +aarch64_ins_fbits (const aarch64_operand *self, const aarch64_opnd_info *info, + aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + insert_field (self->fields[0], code, 64 - info->imm.value, 0); + return NULL; +} + +/* Insert arithmetic immediate for e.g. the last operand in + SUBS <Wd>, <Wn|WSP>, #<imm> {, <shift>}. */ +const char * +aarch64_ins_aimm (const aarch64_operand *self, const aarch64_opnd_info *info, + aarch64_insn *code, const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* shift */ + aarch64_insn value = info->shifter.amount ? 1 : 0; + insert_field (self->fields[0], code, value, 0); + /* imm12 (unsigned) */ + insert_field (self->fields[1], code, info->imm.value, 0); + return NULL; +} + +/* Insert logical/bitmask immediate for e.g. the last operand in + ORR <Wd|WSP>, <Wn>, #<imm>. */ +const char * +aarch64_ins_limm (const aarch64_operand *self, const aarch64_opnd_info *info, + aarch64_insn *code, const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + aarch64_insn value; + uint64_t imm = info->imm.value; + int is32 = aarch64_get_qualifier_esize (inst->operands[0].qualifier) == 4; + + if (inst->opcode->op == OP_BIC) + imm = ~imm; + if (aarch64_logical_immediate_p (imm, is32, &value) == FALSE) + /* The constraint check should have guaranteed this wouldn't happen. */ + assert (0); + + insert_fields (code, value, 0, 3, self->fields[2], self->fields[1], + self->fields[0]); + return NULL; +} + +/* Encode Ft for e.g. STR <Qt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}] + or LDP <Qt1>, <Qt2>, [<Xn|SP>], #<imm>. */ +const char * +aarch64_ins_ft (const aarch64_operand *self, const aarch64_opnd_info *info, + aarch64_insn *code, const aarch64_inst *inst) +{ + aarch64_insn value; + + assert (info->idx == 0); + + /* Rt */ + aarch64_ins_regno (self, info, code, inst); + if (inst->opcode->iclass == ldstpair_indexed + || inst->opcode->iclass == ldstnapair_offs + || inst->opcode->iclass == ldstpair_off + || inst->opcode->iclass == loadlit) + { + /* size */ + switch (info->qualifier) + { + case AARCH64_OPND_QLF_S_S: value = 0; break; + case AARCH64_OPND_QLF_S_D: value = 1; break; + case AARCH64_OPND_QLF_S_Q: value = 2; break; + default: assert (0); + } + insert_field (FLD_ldst_size, code, value, 0); + } + else + { + /* opc[1]:size */ + value = aarch64_get_qualifier_standard_value (info->qualifier); + insert_fields (code, value, 0, 2, FLD_ldst_size, FLD_opc1); + } + + return NULL; +} + +/* Encode the address operand for e.g. STXRB <Ws>, <Wt>, [<Xn|SP>{,#0}]. */ +const char * +aarch64_ins_addr_simple (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* Rn */ + insert_field (FLD_Rn, code, info->addr.base_regno, 0); + return NULL; +} + +/* Encode the address operand for e.g. + STR <Qt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */ +const char * +aarch64_ins_addr_regoff (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + aarch64_insn S; + enum aarch64_modifier_kind kind = info->shifter.kind; + + /* Rn */ + insert_field (FLD_Rn, code, info->addr.base_regno, 0); + /* Rm */ + insert_field (FLD_Rm, code, info->addr.offset.regno, 0); + /* option */ + if (kind == AARCH64_MOD_LSL) + kind = AARCH64_MOD_UXTX; /* Trick to enable the table-driven. */ + insert_field (FLD_option, code, aarch64_get_operand_modifier_value (kind), 0); + /* S */ + if (info->qualifier != AARCH64_OPND_QLF_S_B) + S = info->shifter.amount != 0; + else + /* For STR <Bt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}, + S <amount> + 0 [absent] + 1 #0 + Must be #0 if <extend> is explicitly LSL. */ + S = info->shifter.operator_present && info->shifter.amount_present; + insert_field (FLD_S, code, S, 0); + + return NULL; +} + +/* Encode the address operand for e.g. LDRSW <Xt>, [<Xn|SP>, #<simm>]!. */ +const char * +aarch64_ins_addr_simm (const aarch64_operand *self, + const aarch64_opnd_info *info, + aarch64_insn *code, const aarch64_inst *inst) +{ + int imm; + + /* Rn */ + insert_field (FLD_Rn, code, info->addr.base_regno, 0); + /* simm (imm9 or imm7) */ + imm = info->addr.offset.imm; + if (self->fields[0] == FLD_imm7) + /* scaled immediate in ld/st pair instructions.. */ + imm >>= get_logsz (aarch64_get_qualifier_esize (info->qualifier)); + insert_field (self->fields[0], code, imm, 0); + /* pre/post- index */ + if (info->addr.writeback) + { + assert (inst->opcode->iclass != ldst_unscaled + && inst->opcode->iclass != ldstnapair_offs + && inst->opcode->iclass != ldstpair_off + && inst->opcode->iclass != ldst_unpriv); + assert (info->addr.preind != info->addr.postind); + if (info->addr.preind) + insert_field (self->fields[1], code, 1, 0); + } + + return NULL; +} + +/* Encode the address operand for e.g. LDRSW <Xt>, [<Xn|SP>{, #<pimm>}]. */ +const char * +aarch64_ins_addr_uimm12 (const aarch64_operand *self, + const aarch64_opnd_info *info, + aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + int shift = get_logsz (aarch64_get_qualifier_esize (info->qualifier)); + + /* Rn */ + insert_field (self->fields[0], code, info->addr.base_regno, 0); + /* uimm12 */ + insert_field (self->fields[1], code,info->addr.offset.imm >> shift, 0); + return NULL; +} + +/* Encode the address operand for e.g. + LD1 {<Vt>.<T>, <Vt2>.<T>, <Vt3>.<T>}, [<Xn|SP>], <Xm|#<amount>>. */ +const char * +aarch64_ins_simd_addr_post (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* Rn */ + insert_field (FLD_Rn, code, info->addr.base_regno, 0); + /* Rm | #<amount> */ + if (info->addr.offset.is_reg) + insert_field (FLD_Rm, code, info->addr.offset.regno, 0); + else + insert_field (FLD_Rm, code, 0x1f, 0); + return NULL; +} + +/* Encode the condition operand for e.g. CSEL <Xd>, <Xn>, <Xm>, <cond>. */ +const char * +aarch64_ins_cond (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* cond */ + insert_field (FLD_cond, code, info->cond->value, 0); + return NULL; +} + +/* Encode the system register operand for e.g. MRS <Xt>, <systemreg>. */ +const char * +aarch64_ins_sysreg (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* op0:op1:CRn:CRm:op2 */ + insert_fields (code, info->sysreg, inst->opcode->mask, 5, + FLD_op2, FLD_CRm, FLD_CRn, FLD_op1, FLD_op0); + return NULL; +} + +/* Encode the PSTATE field operand for e.g. MSR <pstatefield>, #<imm>. */ +const char * +aarch64_ins_pstatefield (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* op1:op2 */ + insert_fields (code, info->pstatefield, inst->opcode->mask, 2, + FLD_op2, FLD_op1); + return NULL; +} + +/* Encode the system instruction op operand for e.g. AT <at_op>, <Xt>. */ +const char * +aarch64_ins_sysins_op (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* op1:CRn:CRm:op2 */ + insert_fields (code, info->sysins_op->value, inst->opcode->mask, 4, + FLD_op2, FLD_CRm, FLD_CRn, FLD_op1); + return NULL; +} + +/* Encode the memory barrier option operand for e.g. DMB <option>|#<imm>. */ + +const char * +aarch64_ins_barrier (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* CRm */ + insert_field (FLD_CRm, code, info->barrier->value, 0); + return NULL; +} + +/* Encode the prefetch operation option operand for e.g. + PRFM <prfop>, [<Xn|SP>{, #<pimm>}]. */ + +const char * +aarch64_ins_prfop (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* prfop in Rt */ + insert_field (FLD_Rt, code, info->prfop->value, 0); + return NULL; +} + +/* Encode the extended register operand for e.g. + STR <Qt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */ +const char * +aarch64_ins_reg_extended (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + enum aarch64_modifier_kind kind; + + /* Rm */ + insert_field (FLD_Rm, code, info->reg.regno, 0); + /* option */ + kind = info->shifter.kind; + if (kind == AARCH64_MOD_LSL) + kind = info->qualifier == AARCH64_OPND_QLF_W + ? AARCH64_MOD_UXTW : AARCH64_MOD_UXTX; + insert_field (FLD_option, code, aarch64_get_operand_modifier_value (kind), 0); + /* imm3 */ + insert_field (FLD_imm3, code, info->shifter.amount, 0); + + return NULL; +} + +/* Encode the shifted register operand for e.g. + SUBS <Xd>, <Xn>, <Xm> {, <shift> #<amount>}. */ +const char * +aarch64_ins_reg_shifted (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* Rm */ + insert_field (FLD_Rm, code, info->reg.regno, 0); + /* shift */ + insert_field (FLD_shift, code, + aarch64_get_operand_modifier_value (info->shifter.kind), 0); + /* imm6 */ + insert_field (FLD_imm6, code, info->shifter.amount, 0); + + return NULL; +} + +/* Miscellaneous encoding functions. */ + +/* Encode size[0], i.e. bit 22, for + e.g. FCVTN<Q> <Vd>.<Tb>, <Vn>.<Ta>. */ + +static void +encode_asimd_fcvt (aarch64_inst *inst) +{ + aarch64_insn value; + aarch64_field field = {0, 0}; + enum aarch64_opnd_qualifier qualifier; + + switch (inst->opcode->op) + { + case OP_FCVTN: + case OP_FCVTN2: + /* FCVTN<Q> <Vd>.<Tb>, <Vn>.<Ta>. */ + qualifier = inst->operands[1].qualifier; + break; + case OP_FCVTL: + case OP_FCVTL2: + /* FCVTL<Q> <Vd>.<Ta>, <Vn>.<Tb>. */ + qualifier = inst->operands[0].qualifier; + break; + default: + assert (0); + } + assert (qualifier == AARCH64_OPND_QLF_V_4S + || qualifier == AARCH64_OPND_QLF_V_2D); + value = (qualifier == AARCH64_OPND_QLF_V_4S) ? 0 : 1; + gen_sub_field (FLD_size, 0, 1, &field); + insert_field_2 (&field, &inst->value, value, 0); +} + +/* Encode size[0], i.e. bit 22, for + e.g. FCVTXN <Vb><d>, <Va><n>. */ + +static void +encode_asisd_fcvtxn (aarch64_inst *inst) +{ + aarch64_insn val = 1; + aarch64_field field = {0, 0}; + assert (inst->operands[0].qualifier == AARCH64_OPND_QLF_S_S); + gen_sub_field (FLD_size, 0, 1, &field); + insert_field_2 (&field, &inst->value, val, 0); +} + +/* Encode the 'opc' field for e.g. FCVT <Dd>, <Sn>. */ +static void +encode_fcvt (aarch64_inst *inst) +{ + aarch64_insn val; + const aarch64_field field = {15, 2}; + + /* opc dstsize */ + switch (inst->operands[0].qualifier) + { + case AARCH64_OPND_QLF_S_S: val = 0; break; + case AARCH64_OPND_QLF_S_D: val = 1; break; + case AARCH64_OPND_QLF_S_H: val = 3; break; + default: abort (); + } + insert_field_2 (&field, &inst->value, val, 0); + + return; +} + +/* Do miscellaneous encodings that are not common enough to be driven by + flags. */ + +static void +do_misc_encoding (aarch64_inst *inst) +{ + switch (inst->opcode->op) + { + case OP_FCVT: + encode_fcvt (inst); + break; + case OP_FCVTN: + case OP_FCVTN2: + case OP_FCVTL: + case OP_FCVTL2: + encode_asimd_fcvt (inst); + break; + case OP_FCVTXN_S: + encode_asisd_fcvtxn (inst); + break; + default: break; + } +} + +/* Encode the 'size' and 'Q' field for e.g. SHADD. */ +static void +encode_sizeq (aarch64_inst *inst) +{ + aarch64_insn sizeq; + enum aarch64_field_kind kind; + int idx; + + /* Get the index of the operand whose information we are going to use + to encode the size and Q fields. + This is deduced from the possible valid qualifier lists. */ + idx = aarch64_select_operand_for_sizeq_field_coding (inst->opcode); + DEBUG_TRACE ("idx: %d; qualifier: %s", idx, + aarch64_get_qualifier_name (inst->operands[idx].qualifier)); + sizeq = aarch64_get_qualifier_standard_value (inst->operands[idx].qualifier); + /* Q */ + insert_field (FLD_Q, &inst->value, sizeq & 0x1, inst->opcode->mask); + /* size */ + if (inst->opcode->iclass == asisdlse + || inst->opcode->iclass == asisdlsep + || inst->opcode->iclass == asisdlso + || inst->opcode->iclass == asisdlsop) + kind = FLD_vldst_size; + else + kind = FLD_size; + insert_field (kind, &inst->value, (sizeq >> 1) & 0x3, inst->opcode->mask); +} + +/* Opcodes that have fields shared by multiple operands are usually flagged + with flags. In this function, we detect such flags and use the + information in one of the related operands to do the encoding. The 'one' + operand is not any operand but one of the operands that has the enough + information for such an encoding. */ + +static void +do_special_encoding (struct aarch64_inst *inst) +{ + int idx; + aarch64_insn value; + + DEBUG_TRACE ("enter with coding 0x%x", (uint32_t) inst->value); + + /* Condition for truly conditional executed instructions, e.g. b.cond. */ + if (inst->opcode->flags & F_COND) + { + insert_field (FLD_cond2, &inst->value, inst->cond->value, 0); + } + if (inst->opcode->flags & F_SF) + { + idx = select_operand_for_sf_field_coding (inst->opcode); + value = (inst->operands[idx].qualifier == AARCH64_OPND_QLF_X + || inst->operands[idx].qualifier == AARCH64_OPND_QLF_SP) + ? 1 : 0; + insert_field (FLD_sf, &inst->value, value, 0); + if (inst->opcode->flags & F_N) + insert_field (FLD_N, &inst->value, value, inst->opcode->mask); + } + if (inst->opcode->flags & F_SIZEQ) + encode_sizeq (inst); + if (inst->opcode->flags & F_FPTYPE) + { + idx = select_operand_for_fptype_field_coding (inst->opcode); + switch (inst->operands[idx].qualifier) + { + case AARCH64_OPND_QLF_S_S: value = 0; break; + case AARCH64_OPND_QLF_S_D: value = 1; break; + case AARCH64_OPND_QLF_S_H: value = 3; break; + default: assert (0); + } + insert_field (FLD_type, &inst->value, value, 0); + } + if (inst->opcode->flags & F_SSIZE) + { + enum aarch64_opnd_qualifier qualifier; + idx = select_operand_for_scalar_size_field_coding (inst->opcode); + qualifier = inst->operands[idx].qualifier; + assert (qualifier >= AARCH64_OPND_QLF_S_B + && qualifier <= AARCH64_OPND_QLF_S_Q); + value = aarch64_get_qualifier_standard_value (qualifier); + insert_field (FLD_size, &inst->value, value, inst->opcode->mask); + } + if (inst->opcode->flags & F_T) + { + int num; /* num of consecutive '0's on the right side of imm5<3:0>. */ + aarch64_field field = {0, 0}; + enum aarch64_opnd_qualifier qualifier; + + idx = 0; + qualifier = inst->operands[idx].qualifier; + assert (aarch64_get_operand_class (inst->opcode->operands[0]) + == AARCH64_OPND_CLASS_SIMD_REG + && qualifier >= AARCH64_OPND_QLF_V_8B + && qualifier <= AARCH64_OPND_QLF_V_2D); + /* imm5<3:0> q <t> + 0000 x reserved + xxx1 0 8b + xxx1 1 16b + xx10 0 4h + xx10 1 8h + x100 0 2s + x100 1 4s + 1000 0 reserved + 1000 1 2d */ + value = aarch64_get_qualifier_standard_value (qualifier); + insert_field (FLD_Q, &inst->value, value & 0x1, inst->opcode->mask); + num = (int) value >> 1; + assert (num >= 0 && num <= 3); + gen_sub_field (FLD_imm5, 0, num + 1, &field); + insert_field_2 (&field, &inst->value, 1 << num, inst->opcode->mask); + } + if (inst->opcode->flags & F_GPRSIZE_IN_Q) + { + /* Use Rt to encode in the case of e.g. + STXP <Ws>, <Xt1>, <Xt2>, [<Xn|SP>{,#0}]. */ + enum aarch64_opnd_qualifier qualifier; + idx = aarch64_operand_index (inst->opcode->operands, AARCH64_OPND_Rt); + if (idx == -1) + /* Otherwise use the result operand, which has to be a integer + register. */ + idx = 0; + assert (idx == 0 || idx == 1); + assert (aarch64_get_operand_class (inst->opcode->operands[idx]) + == AARCH64_OPND_CLASS_INT_REG); + qualifier = inst->operands[idx].qualifier; + insert_field (FLD_Q, &inst->value, + aarch64_get_qualifier_standard_value (qualifier), 0); + } + if (inst->opcode->flags & F_LDS_SIZE) + { + /* e.g. LDRSB <Wt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */ + enum aarch64_opnd_qualifier qualifier; + aarch64_field field = {0, 0}; + assert (aarch64_get_operand_class (inst->opcode->operands[0]) + == AARCH64_OPND_CLASS_INT_REG); + gen_sub_field (FLD_opc, 0, 1, &field); + qualifier = inst->operands[0].qualifier; + insert_field_2 (&field, &inst->value, + 1 - aarch64_get_qualifier_standard_value (qualifier), 0); + } + /* Miscellaneous encoding as the last step. */ + if (inst->opcode->flags & F_MISC) + do_misc_encoding (inst); + + DEBUG_TRACE ("exit with coding 0x%x", (uint32_t) inst->value); +} + +/* Converters converting an alias opcode instruction to its real form. */ + +/* ROR <Wd>, <Ws>, #<shift> + is equivalent to: + EXTR <Wd>, <Ws>, <Ws>, #<shift>. */ +static void +convert_ror_to_extr (aarch64_inst *inst) +{ + copy_operand_info (inst, 3, 2); + copy_operand_info (inst, 2, 1); +} + +/* Convert + LSR <Xd>, <Xn>, #<shift> + to + UBFM <Xd>, <Xn>, #<shift>, #63. */ +static void +convert_sr_to_bfm (aarch64_inst *inst) +{ + inst->operands[3].imm.value = + inst->operands[2].qualifier == AARCH64_OPND_QLF_imm_0_31 ? 31 : 63; +} + +/* Convert MOV to ORR. */ +static void +convert_mov_to_orr (aarch64_inst *inst) +{ + /* MOV <Vd>.<T>, <Vn>.<T> + is equivalent to: + ORR <Vd>.<T>, <Vn>.<T>, <Vn>.<T>. */ + copy_operand_info (inst, 2, 1); +} + +/* When <imms> >= <immr>, the instruction written: + SBFX <Xd>, <Xn>, #<lsb>, #<width> + is equivalent to: + SBFM <Xd>, <Xn>, #<lsb>, #(<lsb>+<width>-1). */ + +static void +convert_bfx_to_bfm (aarch64_inst *inst) +{ + int64_t lsb, width; + + /* Convert the operand. */ + lsb = inst->operands[2].imm.value; + width = inst->operands[3].imm.value; + inst->operands[2].imm.value = lsb; + inst->operands[3].imm.value = lsb + width - 1; +} + +/* When <imms> < <immr>, the instruction written: + SBFIZ <Xd>, <Xn>, #<lsb>, #<width> + is equivalent to: + SBFM <Xd>, <Xn>, #((64-<lsb>)&0x3f), #(<width>-1). */ + +static void +convert_bfi_to_bfm (aarch64_inst *inst) +{ + int64_t lsb, width; + + /* Convert the operand. */ + lsb = inst->operands[2].imm.value; + width = inst->operands[3].imm.value; + if (inst->operands[2].qualifier == AARCH64_OPND_QLF_imm_0_31) + { + inst->operands[2].imm.value = (32 - lsb) & 0x1f; + inst->operands[3].imm.value = width - 1; + } + else + { + inst->operands[2].imm.value = (64 - lsb) & 0x3f; + inst->operands[3].imm.value = width - 1; + } +} + +/* The instruction written: + LSL <Xd>, <Xn>, #<shift> + is equivalent to: + UBFM <Xd>, <Xn>, #((64-<shift>)&0x3f), #(63-<shift>). */ + +static void +convert_lsl_to_ubfm (aarch64_inst *inst) +{ + int64_t shift = inst->operands[2].imm.value; + + if (inst->operands[2].qualifier == AARCH64_OPND_QLF_imm_0_31) + { + inst->operands[2].imm.value = (32 - shift) & 0x1f; + inst->operands[3].imm.value = 31 - shift; + } + else + { + inst->operands[2].imm.value = (64 - shift) & 0x3f; + inst->operands[3].imm.value = 63 - shift; + } +} + +/* CINC <Wd>, <Wn>, <cond> + is equivalent to: + CSINC <Wd>, <Wn>, <Wn>, invert(<cond>). */ + +static void +convert_to_csel (aarch64_inst *inst) +{ + copy_operand_info (inst, 3, 2); + copy_operand_info (inst, 2, 1); + inst->operands[3].cond = get_inverted_cond (inst->operands[3].cond); +} + +/* CSET <Wd>, <cond> + is equivalent to: + CSINC <Wd>, WZR, WZR, invert(<cond>). */ + +static void +convert_cset_to_csinc (aarch64_inst *inst) +{ + copy_operand_info (inst, 3, 1); + copy_operand_info (inst, 2, 0); + copy_operand_info (inst, 1, 0); + inst->operands[1].reg.regno = 0x1f; + inst->operands[2].reg.regno = 0x1f; + inst->operands[3].cond = get_inverted_cond (inst->operands[3].cond); +} + +/* MOV <Wd>, #<imm> + is equivalent to: + MOVZ <Wd>, #<imm16>, LSL #<shift>. */ + +static void +convert_mov_to_movewide (aarch64_inst *inst) +{ + int is32; + uint32_t shift_amount; + uint64_t value; + + switch (inst->opcode->op) + { + case OP_MOV_IMM_WIDE: + value = inst->operands[1].imm.value; + break; + case OP_MOV_IMM_WIDEN: + value = ~inst->operands[1].imm.value; + break; + default: + assert (0); + } + inst->operands[1].type = AARCH64_OPND_HALF; + is32 = inst->operands[0].qualifier == AARCH64_OPND_QLF_W; + /* This should have been guaranteed by the constraint check. */ + assert (aarch64_wide_constant_p (value, is32, &shift_amount) == TRUE); + value >>= shift_amount; + value &= 0xffff; + inst->operands[1].imm.value = value; + inst->operands[1].shifter.kind = AARCH64_MOD_LSL; + inst->operands[1].shifter.amount = shift_amount; +} + +/* MOV <Wd>, #<imm> + is equivalent to: + ORR <Wd>, WZR, #<imm>. */ + +static void +convert_mov_to_movebitmask (aarch64_inst *inst) +{ + copy_operand_info (inst, 2, 1); + inst->operands[1].reg.regno = 0x1f; + inst->operands[1].skip = 0; +} + +/* Some alias opcodes are assembled by being converted to their real-form. */ + +static void +convert_to_real (aarch64_inst *inst, const aarch64_opcode *real) +{ + const aarch64_opcode *alias = inst->opcode; + + if ((alias->flags & F_CONV) == 0) + goto convert_to_real_return; + + switch (alias->op) + { + case OP_ASR_IMM: + case OP_LSR_IMM: + convert_sr_to_bfm (inst); + break; + case OP_LSL_IMM: + convert_lsl_to_ubfm (inst); + break; + case OP_CINC: + case OP_CINV: + case OP_CNEG: + convert_to_csel (inst); + break; + case OP_CSET: + case OP_CSETM: + convert_cset_to_csinc (inst); + break; + case OP_UBFX: + case OP_BFXIL: + case OP_SBFX: + convert_bfx_to_bfm (inst); + break; + case OP_SBFIZ: + case OP_BFI: + case OP_UBFIZ: + convert_bfi_to_bfm (inst); + break; + case OP_MOV_V: + convert_mov_to_orr (inst); + break; + case OP_MOV_IMM_WIDE: + case OP_MOV_IMM_WIDEN: + convert_mov_to_movewide (inst); + break; + case OP_MOV_IMM_LOG: + convert_mov_to_movebitmask (inst); + break; + case OP_ROR_IMM: + convert_ror_to_extr (inst); + break; + default: + break; + } + +convert_to_real_return: + aarch64_replace_opcode (inst, real); +} + +/* Encode *INST_ORI of the opcode code OPCODE. + Return the encoded result in *CODE and if QLF_SEQ is not NULL, return the + matched operand qualifier sequence in *QLF_SEQ. */ + +int +aarch64_opcode_encode (const aarch64_opcode *opcode, + const aarch64_inst *inst_ori, aarch64_insn *code, + aarch64_opnd_qualifier_t *qlf_seq, + aarch64_operand_error *mismatch_detail) +{ + int i; + const aarch64_opcode *aliased; + aarch64_inst copy, *inst; + + DEBUG_TRACE ("enter with %s", opcode->name); + + /* Create a copy of *INST_ORI, so that we can do any change we want. */ + copy = *inst_ori; + inst = © + + assert (inst->opcode == NULL || inst->opcode == opcode); + if (inst->opcode == NULL) + inst->opcode = opcode; + + /* Constrain the operands. + After passing this, the encoding is guaranteed to succeed. */ + if (aarch64_match_operands_constraint (inst, mismatch_detail) == 0) + { + DEBUG_TRACE ("FAIL since operand constraint not met"); + return 0; + } + + /* Get the base value. + Note: this has to be before the aliasing handling below in order to + get the base value from the alias opcode before we move on to the + aliased opcode for encoding. */ + inst->value = opcode->opcode; + + /* No need to do anything else if the opcode does not have any operand. */ + if (aarch64_num_of_operands (opcode) == 0) + goto encoding_exit; + + /* Assign operand indexes and check types. Also put the matched + operand qualifiers in *QLF_SEQ to return. */ + for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i) + { + assert (opcode->operands[i] == inst->operands[i].type); + inst->operands[i].idx = i; + if (qlf_seq != NULL) + *qlf_seq = inst->operands[i].qualifier; + } + + aliased = aarch64_find_real_opcode (opcode); + /* If the opcode is an alias and it does not ask for direct encoding by + itself, the instruction will be transformed to the form of real opcode + and the encoding will be carried out using the rules for the aliased + opcode. */ + if (aliased != NULL && (opcode->flags & F_CONV)) + { + DEBUG_TRACE ("real opcode '%s' has been found for the alias %s", + aliased->name, opcode->name); + /* Convert the operands to the form of the real opcode. */ + convert_to_real (inst, aliased); + opcode = aliased; + } + + aarch64_opnd_info *info = inst->operands; + + /* Call the inserter of each operand. */ + for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i, ++info) + { + const aarch64_operand *opnd; + enum aarch64_opnd type = opcode->operands[i]; + if (type == AARCH64_OPND_NIL) + break; + if (info->skip) + { + DEBUG_TRACE ("skip the incomplete operand %d", i); + continue; + } + opnd = &aarch64_operands[type]; + if (operand_has_inserter (opnd)) + aarch64_insert_operand (opnd, info, &inst->value, inst); + } + + /* Call opcode encoders indicated by flags. */ + if (opcode_has_special_coder (opcode)) + do_special_encoding (inst); + +encoding_exit: + DEBUG_TRACE ("exit with %s", opcode->name); + + *code = inst->value; + + return 1; +} diff --git a/opcodes/aarch64-asm.h b/opcodes/aarch64-asm.h new file mode 100644 index 0000000..b14383b --- /dev/null +++ b/opcodes/aarch64-asm.h @@ -0,0 +1,73 @@ +/* aarch64-asm.h -- Header file for aarch64-asm.c and aarch64-asm-2.c. + Copyright 2012 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING3. If not, + see <http://www.gnu.org/licenses/>. */ + +#ifndef OPCODES_AARCH64_ASM_H +#define OPCODES_AARCH64_ASM_H + +#include "aarch64-opc.h" + +/* Given OPCODE, return the opcode entry that OPCODE aliases to, e.g. + given LSL, return UBFM. */ + +const aarch64_opcode* aarch64_find_real_opcode (const aarch64_opcode *); + +/* Switch-table-based high-level operand inserter. */ + +const char* aarch64_insert_operand (const aarch64_operand *, + const aarch64_opnd_info *, aarch64_insn *, + const aarch64_inst *); + +/* Operand inserters. */ + +#define AARCH64_DECL_OPD_INSERTER(x) \ + const char* aarch64_##x (const aarch64_operand *, const aarch64_opnd_info *, \ + aarch64_insn *, const aarch64_inst *) + +AARCH64_DECL_OPD_INSERTER (ins_regno); +AARCH64_DECL_OPD_INSERTER (ins_reglane); +AARCH64_DECL_OPD_INSERTER (ins_reglist); +AARCH64_DECL_OPD_INSERTER (ins_ldst_reglist); +AARCH64_DECL_OPD_INSERTER (ins_ldst_reglist_r); +AARCH64_DECL_OPD_INSERTER (ins_ldst_elemlist); +AARCH64_DECL_OPD_INSERTER (ins_advsimd_imm_shift); +AARCH64_DECL_OPD_INSERTER (ins_imm); +AARCH64_DECL_OPD_INSERTER (ins_imm_half); +AARCH64_DECL_OPD_INSERTER (ins_advsimd_imm_modified); +AARCH64_DECL_OPD_INSERTER (ins_fbits); +AARCH64_DECL_OPD_INSERTER (ins_aimm); +AARCH64_DECL_OPD_INSERTER (ins_limm); +AARCH64_DECL_OPD_INSERTER (ins_ft); +AARCH64_DECL_OPD_INSERTER (ins_addr_simple); +AARCH64_DECL_OPD_INSERTER (ins_addr_regoff); +AARCH64_DECL_OPD_INSERTER (ins_addr_simm); +AARCH64_DECL_OPD_INSERTER (ins_addr_uimm12); +AARCH64_DECL_OPD_INSERTER (ins_simd_addr_post); +AARCH64_DECL_OPD_INSERTER (ins_cond); +AARCH64_DECL_OPD_INSERTER (ins_sysreg); +AARCH64_DECL_OPD_INSERTER (ins_pstatefield); +AARCH64_DECL_OPD_INSERTER (ins_sysins_op); +AARCH64_DECL_OPD_INSERTER (ins_barrier); +AARCH64_DECL_OPD_INSERTER (ins_prfop); +AARCH64_DECL_OPD_INSERTER (ins_reg_extended); +AARCH64_DECL_OPD_INSERTER (ins_reg_shifted); + +#undef AARCH64_DECL_OPD_INSERTER + +#endif /* OPCODES_AARCH64_ASM_H */ diff --git a/opcodes/aarch64-dis-2.c b/opcodes/aarch64-dis-2.c new file mode 100644 index 0000000..cf508ae --- /dev/null +++ b/opcodes/aarch64-dis-2.c @@ -0,0 +1,7655 @@ +/* This file is automatically generated by aarch64-gen. Do not edit! */ +/* Copyright 2012 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING3. If not, + see <http://www.gnu.org/licenses/>. */ + +#include "sysdep.h" +#include "aarch64-dis.h" + +/* Called by aarch64_opcode_lookup. */ + +static int +aarch64_opcode_lookup_1 (uint32_t word) +{ + if (((word >> 26) & 0x1) == 0) + { + if (((word >> 25) & 0x1) == 0) + { + if (((word >> 27) & 0x1) == 0) + { + if (((word >> 24) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx0000xxx0 + adr. */ + return 769; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx0000xxx1 + adrp. */ + return 770; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx1000x00x + add. */ + return 12; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx1000x01x + sub. */ + return 16; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx1000x10x + adds. */ + return 14; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx1000x11x + subs. */ + return 17; + } + } + } + } + else + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 22) & 0x1) == 0) + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 21) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx000x0010000 + stxrb. */ + return 705; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx000x0010010 + stxrh. */ + return 711; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx000x00100x1 + stxr. */ + return 717; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx100x00100xx + stxp. */ + return 719; + } + } + else + { + if (((word >> 21) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx1xxxxx000x0010000 + stlxrb. */ + return 706; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx1xxxxx000x0010010 + stlxrh. */ + return 712; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx1xxxxx000x00100x1 + stlxr. */ + return 718; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx1xxxxx100x00100xx + stlxp. */ + return 720; + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx00x00101xx + stnp. */ + return 727; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx01x0010000 + stlrb. */ + return 709; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx01x0010010 + stlrh. */ + return 715; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx01x00100x1 + stlr. */ + return 725; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx01x00101xx + stp. */ + return 736; + } + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 21) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx010x0010000 + ldxrb. */ + return 707; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx010x0010010 + ldxrh. */ + return 713; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx010x00100x1 + ldxr. */ + return 721; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx110x00100xx + ldxp. */ + return 723; + } + } + else + { + if (((word >> 21) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx1xxxxx010x0010000 + ldaxrb. */ + return 708; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx1xxxxx010x0010010 + ldaxrh. */ + return 714; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx1xxxxx010x00100x1 + ldaxr. */ + return 722; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx1xxxxx110x00100xx + ldaxp. */ + return 724; + } + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx10x001010x + ldnp. */ + return 728; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx10x001011x + ldpsw. */ + return 735; + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx11x0010000 + ldarb. */ + return 710; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx11x0010010 + ldarh. */ + return 716; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx11x00100x1 + ldar. */ + return 726; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx11x001010x + ldp. */ + return 737; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx11x001011x + ldpsw. */ + return 740; + } + } + } + } + } + else + { + if (((word >> 24) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx000110x0 + ldr. */ + return 741; + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx00011001 + ldrsw. */ + return 743; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx00011011 + prfm. */ + return 744; + } + } + } + else + { + if (((word >> 10) & 0x1) == 0) + { + if (((word >> 11) & 0x1) == 0) + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 22) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxxx0000011100 + sturb. */ + return 681; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxxx0000011110 + sturh. */ + return 691; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxxx00000111x1 + stur. */ + return 697; + } + } + else + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxxx1000011100 + ldurb. */ + return 682; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxxx1000011110 + ldurh. */ + return 692; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxxx10000111x1 + ldur. */ + return 698; + } + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxxxx100011100 + ldursb. */ + return 685; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxxxx100011101 + ldursw. */ + return 701; + } + } + else + { + if (((word >> 31) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxxxx100011110 + ldursh. */ + return 695; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxxxx100011111 + prfum. */ + return 703; + } + } + } + } + else + { + if (((word >> 21) & 0x1) == 0) + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 22) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx00000011100 + sttrb. */ + return 672; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx00000011110 + sttrh. */ + return 675; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx000000111x1 + sttr. */ + return 678; + } + } + else + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx01000011100 + ldtrb. */ + return 673; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx01000011110 + ldtrh. */ + return 676; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx010000111x1 + ldtr. */ + return 679; + } + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx0x100011100 + ldtrsb. */ + return 674; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx0x100011101 + ldtrsw. */ + return 680; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx0x10001111x + ldtrsh. */ + return 677; + } + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 22) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx10000011100 + strb. */ + return 660; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx10000011110 + strh. */ + return 665; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx100000111x1 + str. */ + return 668; + } + } + else + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx11000011100 + ldrb. */ + return 661; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx11000011110 + ldrh. */ + return 666; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx110000111x1 + ldr. */ + return 669; + } + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx1x100011100 + ldrsb. */ + return 662; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx1x100011101 + ldrsw. */ + return 670; + } + } + else + { + if (((word >> 31) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx1x100011110 + ldrsh. */ + return 667; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx1x100011111 + prfm. */ + return 671; + } + } + } + } + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 22) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1xxxxxxxxxxx0000011100 + strb. */ + return 637; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1xxxxxxxxxxx0000011110 + strh. */ + return 642; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1xxxxxxxxxxx00000111x1 + str. */ + return 645; + } + } + else + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1xxxxxxxxxxx1000011100 + ldrb. */ + return 638; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1xxxxxxxxxxx1000011110 + ldrh. */ + return 643; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1xxxxxxxxxxx10000111x1 + ldr. */ + return 646; + } + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1xxxxxxxxxxxx100011100 + ldrsb. */ + return 639; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1xxxxxxxxxxxx100011101 + ldrsw. */ + return 647; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1xxxxxxxxxxxx10001111x + ldrsh. */ + return 644; + } + } + } + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 22) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx0010011x00 + strb. */ + return 648; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx0010011x10 + strh. */ + return 653; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx0010011xx1 + str. */ + return 656; + } + } + else + { + if (((word >> 31) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx1010011x00 + ldrb. */ + return 649; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx1010011x10 + ldrh. */ + return 654; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx1010011xx1 + ldr. */ + return 657; + } + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx110011x00 + ldrsb. */ + return 650; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx110011x01 + ldrsw. */ + return 658; + } + } + else + { + if (((word >> 31) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx110011x10 + ldrsh. */ + return 655; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx110011x11 + prfm. */ + return 659; + } + } + } + } + } + } + } + else + { + if (((word >> 24) & 0x1) == 0) + { + if (((word >> 27) & 0x1) == 0) + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx00100x00x + and. */ + return 745; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx00100x01x + eor. */ + return 749; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx00100x10x + orr. */ + return 747; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx00100x11x + ands. */ + return 750; + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx10100x00x + movn. */ + return 764; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx10100x01x + movz. */ + return 766; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx10100x1xx + movk. */ + return 768; + } + } + } + else + { + if (((word >> 21) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx0xx0101000x + and. */ + return 752; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx0xx0101001x + eor. */ + return 759; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx0xx0101010x + orr. */ + return 754; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx0xx0101011x + ands. */ + return 761; + } + } + } + else + { + if (((word >> 10) & 0x1) == 0) + { + if (((word >> 11) & 0x1) == 0) + { + if (((word >> 22) & 0x1) == 0) + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxx0000101100x + adc. */ + return 0; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxx0000101101x + sbc. */ + return 2; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxx0000101110x + adcs. */ + return 1; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxx0000101111x + sbcs. */ + return 4; + } + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxx00101011x0x + csel. */ + return 520; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxx00101011x1x + csinv. */ + return 524; + } + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxx01001011x0x + ccmn. */ + return 518; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxx01001011x1x + ccmp. */ + return 519; + } + } + else + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0000xxxxxxx01101011xxx + rbit. */ + return 543; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0001xxxxxxx01101011xxx + lslv. */ + return 552; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001xxxxxxxx01101011xxx + clz. */ + return 547; + } + } + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx0x001011x0x + ccmn. */ + return 516; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxx0x001011x1x + ccmp. */ + return 517; + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01x0xxxxxxx0x101011x0x + udiv. */ + return 550; + } + else + { + if (((word >> 31) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01x0xxxxxxx0x101011x10 + rev. */ + return 545; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01x0xxxxxxx0x101011x11 + rev32. */ + return 549; + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01x1xxxxxxx0x101011xxx + asrv. */ + return 556; + } + } + } + } + else + { + if (((word >> 11) & 0x1) == 0) + { + if (((word >> 22) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx10xxxxxxxxx00x01011x0x + csinc. */ + return 521; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx10xxxxxxxxx00x01011x1x + csneg. */ + return 527; + } + } + else + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1000xxxxxxx01x01011xxx + rev16. */ + return 544; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1001xxxxxxx01x01011xxx + lsrv. */ + return 554; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101xxxxxxxx01x01011xxx + cls. */ + return 548; + } + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx11x0xxxxxxx0xx01011x0x + sdiv. */ + return 551; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx11x0xxxxxxx0xx01011x1x + rev. */ + return 546; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx11x1xxxxxxx0xx01011xxx + rorv. */ + return 558; + } + } + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx1xx0101x00x + bic. */ + return 753; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx1xx0101x01x + eon. */ + return 760; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx1xx0101x10x + orn. */ + return 757; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx1xx0101x11x + bics. */ + return 763; + } + } + } + } + } + else + { + if (((word >> 27) & 0x1) == 0) + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx01100x00x + sbfm. */ + return 489; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx01100x01x + ubfm. */ + return 499; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx01100x1xx + bfm. */ + return 496; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxx11100xxxx + extr. */ + return 582; + } + } + else + { + if (((word >> 21) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx0xx1101000x + add. */ + return 19; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx0xx1101001x + sub. */ + return 22; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx0xx1101010x + adds. */ + return 20; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx0xx1101011x + subs. */ + return 24; + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 22) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx00x11011xxx + madd. */ + return 560; + } + else + { + if (((word >> 23) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx01011011xxx + smulh. */ + return 568; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx01111011xxx + umulh. */ + return 573; + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx1xxxxx0xx11011xxx + msub. */ + return 562; + } + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx1x01101000x + add. */ + return 6; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx1x01101001x + sub. */ + return 9; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx1x01101010x + adds. */ + return 7; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx1x01101011x + subs. */ + return 10; + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx1x011011xxx + smaddl. */ + return 564; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx1xxxxx1x011011xxx + smsubl. */ + return 566; + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx1x11101xxxx + umaddl. */ + return 569; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx1xxxxx1x11101xxxx + umsubl. */ + return 571; + } + } + } + } + } + } + } + else + { + if (((word >> 27) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxxxx10x000 + b. */ + return 506; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxxxx10x001 + bl. */ + return 507; + } + } + else + { + if (((word >> 24) & 0x1) == 0) + { + if (((word >> 25) & 0x1) == 0) + { + if (((word >> 31) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx0010x010 + b.c. */ + return 515; + } + else + { + if (((word >> 0) & 0x1) == 0) + { + if (((word >> 1) & 0x1) == 0) + { + if (((word >> 21) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + 00xxxxxxxxxxxxxxxxxxx0xx0010x011 + hlt. */ + return 578; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + 00xxxxxxxxxxxxxxxxxxx1xx0010x011 + brk. */ + return 577; + } + } + else + { + if (((word >> 21) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + 01xxxxxxxxxxxxxxxxxxx0xx0010x011 + hvc. */ + return 575; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + 01xxxxxxxxxxxxxxxxxxx1xx0010x011 + dcps2. */ + return 580; + } + } + } + else + { + if (((word >> 1) & 0x1) == 0) + { + if (((word >> 21) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + 10xxxxxxxxxxxxxxxxxxx0xx0010x011 + svc. */ + return 574; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + 10xxxxxxxxxxxxxxxxxxx1xx0010x011 + dcps1. */ + return 579; + } + } + else + { + if (((word >> 21) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + 11xxxxxxxxxxxxxxxxxxx0xx0010x011 + smc. */ + return 576; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + 11xxxxxxxxxxxxxxxxxxx1xx0010x011 + dcps3. */ + return 581; + } + } + } + } + } + else + { + if (((word >> 21) & 0x1) == 0) + { + if (((word >> 22) & 0x1) == 0) + { + if (((word >> 23) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx0000110x01x + br. */ + return 508; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx0010110x01x + eret. */ + return 511; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx01x0110x01x + ret. */ + return 510; + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx1x00110x01x + blr. */ + return 509; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx1x10110x01x + drps. */ + return 512; + } + } + } + } + else + { + if (((word >> 20) & 0x1) == 0) + { + if (((word >> 19) & 0x1) == 0) + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxx00xxxxx00xxx1x10x01x + msr. */ + return 771; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxx01xxxxx00xxx1x10x01x + hint. */ + return 772; + } + } + else + { + if (((word >> 5) & 0x1) == 0) + { + if (((word >> 6) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxx00xxxxx1xxxxxx00xxx1x10x01x + dsb. */ + return 780; + } + else + { + if (((word >> 7) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxx010xxxx1xxxxxx00xxx1x10x01x + clrex. */ + return 779; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxx011xxxx1xxxxxx00xxx1x10x01x + isb. */ + return 782; + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxx1xxxxxx1xxxxxx00xxx1x10x01x + dmb. */ + return 781; + } + } + } + else + { + if (((word >> 21) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxx100xx1x10x01x + sys. */ + return 783; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxx101xx1x10x01x + sysl. */ + return 789; + } + } + } + else + { + if (((word >> 21) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxx10xx1x10x01x + msr. */ + return 788; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxx11xx1x10x01x + mrs. */ + return 790; + } + } + } + } + } + else + { + if (((word >> 24) & 0x1) == 0) + { + if (((word >> 25) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx0010x1xx + cbz. */ + return 513; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx0110x1xx + tbz. */ + return 791; + } + } + else + { + if (((word >> 25) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx1010x1xx + cbnz. */ + return 514; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx1110x1xx + tbnz. */ + return 792; + } + } + } + } + else + { + if (((word >> 25) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 22) & 0x1) == 0) + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 24) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx00001100xx + st4. */ + return 351; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx00001101xx + stnp. */ + return 729; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 21) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx0xxxxxxx000101100xx + st1. */ + return 367; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx0xxxxxxx100101100xx + st2. */ + return 369; + } + } + else + { + if (((word >> 21) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx1xxxxxxx000101100xx + st3. */ + return 368; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx1xxxxxxx100101100xx + st4. */ + return 370; + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx00101101xx + stp. */ + return 733; + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 21) & 0x1) == 0) + { + if (((word >> 24) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx001001100xx + st4. */ + return 359; + } + else + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx0xxxxxxx001101100xx + st1. */ + return 379; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx1xxxxxxx001101100xx + st3. */ + return 380; + } + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx0xxxxxxx101x01100xx + st2. */ + return 381; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx1xxxxxxx101x01100xx + st4. */ + return 382; + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx01x01101xx + stp. */ + return 738; + } + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 24) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx10001100xx + ld4. */ + return 355; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx10001101xx + ldnp. */ + return 730; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 21) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx0xxxxxxx010101100xx + ld1. */ + return 371; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx0xxxxxxx110101100xx + ld2. */ + return 375; + } + } + else + { + if (((word >> 21) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx1xxxxxxx010101100xx + ld3. */ + return 372; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx1xxxxxxx110101100xx + ld4. */ + return 376; + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx10101101xx + ldp. */ + return 734; + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 21) & 0x1) == 0) + { + if (((word >> 24) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxx011001100xx + ld4. */ + return 363; + } + else + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx0xxxxxxx011101100xx + ld1. */ + return 383; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx1xxxxxxx011101100xx + ld3. */ + return 384; + } + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx0xxxxxxx111x01100xx + ld2. */ + return 387; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxx1xxxxxxx111x01100xx + ld4. */ + return 388; + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx11x01101xx + ldp. */ + return 739; + } + } + } + } + else + { + if (((word >> 24) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxxxx001110xx + ldr. */ + return 742; + } + else + { + if (((word >> 10) & 0x1) == 0) + { + if (((word >> 11) & 0x1) == 0) + { + if (((word >> 22) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxxx0x001111xx + stur. */ + return 687; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00xxxxxxxxxx1x001111xx + ldur. */ + return 688; + } + } + else + { + if (((word >> 22) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxxx0x001111xx + str. */ + return 663; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01xxxxxxxxxx1x001111xx + ldr. */ + return 664; + } + } + } + else + { + if (((word >> 22) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1xxxxxxxxxxx0x001111xx + str. */ + return 640; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1xxxxxxxxxxx1x001111xx + ldr. */ + return 641; + } + } + } + } + else + { + if (((word >> 22) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx0x10111xxx + str. */ + return 651; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxxxxxxxx1x10111xxx + ldr. */ + return 652; + } + } + } + } + else + { + if (((word >> 24) & 0x1) == 0) + { + if (((word >> 21) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 10) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 11) & 0x1) == 0) + { + if (((word >> 12) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000xxxxxxxx0xx011100xx + tbl. */ + return 337; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001xxxxxxxx0xx011100xx + tbx. */ + return 338; + } + } + else + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010x0xxxxxx0xx011100xx + trn1. */ + return 216; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010x1xxxxxx0xx011100xx + trn2. */ + return 219; + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01100xxxxxx0xx011100xx + uzp1. */ + return 215; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01101xxxxxx0xx011100xx + uzp2. */ + return 218; + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01110xxxxxx0xx011100xx + zip1. */ + return 217; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx01111xxxxxx0xx011100xx + zip2. */ + return 220; + } + } + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0xxxxxxxxxx0xx011101xx + ext. */ + return 119; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 11) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx10xxxxxxxxx0xx011100xx + dup. */ + return 135; + } + else + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1100xxxxxxx0xx011100xx + dup. */ + return 136; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1101xxxxxxx0xx011100xx + smov. */ + return 137; + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1110xxxxxxx0xx011100xx + ins. */ + return 140; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1111xxxxxxx0xx011100xx + umov. */ + return 138; + } + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1xxxxxxxxxx0xx011101xx + ins. */ + return 142; + } + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 17) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxx00xxx0xx01111x0x + fcvtzs. */ + return 586; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxx01xxx0xx01111x0x + scvtf. */ + return 584; + } + } + else + { + if (((word >> 17) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxx10xxx0xx01111x0x + fcvtzu. */ + return 587; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxxx11xxx0xx01111x0x + ucvtf. */ + return 585; + } + } + } + else + { + if (((word >> 10) & 0x1) == 0) + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x000xxxxxx0xx01111x1x + sha1c. */ + return 536; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x001xxxxxx0xx01111x1x + sha256h. */ + return 540; + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x010xxxxxx0xx01111x1x + sha1m. */ + return 538; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x011xxxxxx0xx01111x1x + sha256su1. */ + return 542; + } + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x100xxxxxx0xx01111x1x + sha1p. */ + return 537; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x101xxxxxx0xx01111x1x + sha256h2. */ + return 541; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x11xxxxxxx0xx01111x1x + sha1su0. */ + return 539; + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1xxxxxxxxxx0xx01111x1x + dup. */ + return 426; + } + } + } + } + else + { + if (((word >> 10) & 0x1) == 0) + { + if (((word >> 11) & 0x1) == 0) + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000xxxxx1xx0111000x + saddl. */ + return 38; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000xxxxx1xx0111001x + saddl2. */ + return 39; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000xxxxx1xx0111010x + uaddl. */ + return 70; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000xxxxx1xx0111011x + uaddl2. */ + return 71; + } + } + } + else + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 17) & 0x1) == 0) + { + if (((word >> 18) & 0x1) == 0) + { + if (((word >> 19) & 0x1) == 0) + { + if (((word >> 20) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000000001xx01111xxx + fcvtns. */ + return 588; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000000011xx01111xxx + fcvtms. */ + return 598; + } + } + else + { + if (((word >> 20) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000000101xx01111xxx + fcvtps. */ + return 596; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000000111xx01111xxx + fcvtzs. */ + return 600; + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000001xx1xx01111xxx + fcvtas. */ + return 592; + } + } + else + { + if (((word >> 18) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000010xx1xx01111xxx + scvtf. */ + return 590; + } + else + { + if (((word >> 19) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0000000110x1xx01111xxx + fmov. */ + return 594; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0000000111x1xx01111xxx + fmov. */ + return 602; + } + } + } + } + else + { + if (((word >> 17) & 0x1) == 0) + { + if (((word >> 18) & 0x1) == 0) + { + if (((word >> 19) & 0x1) == 0) + { + if (((word >> 20) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000100001xx01111xxx + fcvtnu. */ + return 589; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000100011xx01111xxx + fcvtmu. */ + return 599; + } + } + else + { + if (((word >> 20) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000100101xx01111xxx + fcvtpu. */ + return 597; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000100111xx01111xxx + fcvtzu. */ + return 601; + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000101xx1xx01111xxx + fcvtau. */ + return 593; + } + } + else + { + if (((word >> 18) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000000110xx1xx01111xxx + ucvtf. */ + return 591; + } + else + { + if (((word >> 19) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0000001110x1xx01111xxx + fmov. */ + return 595; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0000001111x1xx01111xxx + fmov. */ + return 603; + } + } + } + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000001xxxxx1xx0111x00x + smlal. */ + return 54; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000001xxxxx1xx0111x01x + smlal2. */ + return 55; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000001xxxxx1xx0111x10x + umlal. */ + return 86; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000001xxxxx1xx0111x11x + umlal2. */ + return 87; + } + } + } + } + else + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000010xxxxx1xx0111000x + addhn. */ + return 46; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000010xxxxx1xx0111001x + addhn2. */ + return 47; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000010xxxxx1xx0111010x + raddhn. */ + return 78; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000010xxxxx1xx0111011x + raddhn2. */ + return 79; + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000011xxxxx1xx0111000x + smull. */ + return 62; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000011xxxxx1xx0111001x + smull2. */ + return 63; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000011xxxxx1xx0111010x + umull. */ + return 90; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000011xxxxx1xx0111011x + umull2. */ + return 91; + } + } + } + } + else + { + if (((word >> 17) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 18) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000010000xx1xx01111xxx + fmov. */ + return 610; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000010001xx1xx01111xxx + frintn. */ + return 615; + } + } + else + { + if (((word >> 18) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000010100xx1xx01111xxx + fneg. */ + return 612; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000010101xx1xx01111xxx + frintm. */ + return 617; + } + } + } + else + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 18) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000011000xx1xx01111xxx + fabs. */ + return 611; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000011001xx1xx01111xxx + frintp. */ + return 616; + } + } + else + { + if (((word >> 18) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000011100xx1xx01111xxx + fsqrt. */ + return 613; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000011101xx1xx01111xxx + frintz. */ + return 618; + } + } + } + } + else + { + if (((word >> 18) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00001xx10xx1xx01111xxx + fcvt. */ + return 614; + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 16) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000010011xx1xx01111xxx + frinta. */ + return 619; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000010111xx1xx01111xxx + frintx. */ + return 620; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000011x11xx1xx01111xxx + frinti. */ + return 621; + } + } + } + } + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000100xxxxx1xx0111000x + ssubl. */ + return 42; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000100xxxxx1xx0111001x + ssubl2. */ + return 43; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000100xxxxx1xx0111010x + usubl. */ + return 74; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000100xxxxx1xx0111011x + usubl2. */ + return 75; + } + } + } + else + { + if (((word >> 3) & 0x1) == 0) + { + if (((word >> 4) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxx00xxxxx000100xxxxx1xx01111xxx + fcmp. */ + return 606; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxx01xxxxx000100xxxxx1xx01111xxx + fcmpe. */ + return 607; + } + } + else + { + if (((word >> 4) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxx10xxxxx000100xxxxx1xx01111xxx + fcmp. */ + return 608; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxx11xxxxx000100xxxxx1xx01111xxx + fcmpe. */ + return 609; + } + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000101xxxxx1xx0111x00x + smlsl. */ + return 58; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000101xxxxx1xx0111x01x + smlsl2. */ + return 59; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000101xxxxx1xx0111x10x + umlsl. */ + return 88; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000101xxxxx1xx0111x11x + umlsl2. */ + return 89; + } + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000110xxxxx1xx0111x00x + subhn. */ + return 50; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000110xxxxx1xx0111x01x + subhn2. */ + return 51; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000110xxxxx1xx0111x10x + rsubhn. */ + return 82; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000110xxxxx1xx0111x11x + rsubhn2. */ + return 83; + } + } + } + else + { + if (((word >> 22) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000111xxxxx10x0111xx0x + pmull. */ + return 66; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000111xxxxx10x0111xx1x + pmull2. */ + return 68; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000111xxxxx11x0111xx0x + pmull. */ + return 67; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx000111xxxxx11x0111xx1x + pmull2. */ + return 69; + } + } + } + } + } + } + else + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001000xxxxx1xx0111000x + saddw. */ + return 40; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001000xxxxx1xx0111001x + saddw2. */ + return 41; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001000xxxxx1xx0111010x + uaddw. */ + return 72; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001000xxxxx1xx0111011x + uaddw2. */ + return 73; + } + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001001xxxxx1xx01110x0x + sqdmlal. */ + return 56; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001001xxxxx1xx01110x1x + sqdmlal2. */ + return 57; + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001010xxxxx1xx0111000x + sabal. */ + return 48; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001010xxxxx1xx0111001x + sabal2. */ + return 49; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001010xxxxx1xx0111010x + uabal. */ + return 80; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001010xxxxx1xx0111011x + uabal2. */ + return 81; + } + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001011xxxxx1xx01110x0x + sqdmull. */ + return 64; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001011xxxxx1xx01110x1x + sqdmull2. */ + return 65; + } + } + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001100xxxxx1xx0111000x + ssubw. */ + return 44; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001100xxxxx1xx0111001x + ssubw2. */ + return 45; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001100xxxxx1xx0111010x + usubw. */ + return 76; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001100xxxxx1xx0111011x + usubw2. */ + return 77; + } + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001101xxxxx1xx01110x0x + sqdmlsl. */ + return 60; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001101xxxxx1xx01110x1x + sqdmlsl2. */ + return 61; + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00111xxxxxx1xx0111000x + sabdl. */ + return 52; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00111xxxxxx1xx0111001x + sabdl2. */ + return 53; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00111xxxxxx1xx0111010x + uabdl. */ + return 84; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00111xxxxxx1xx0111011x + uabdl2. */ + return 85; + } + } + } + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx001xxxxxxxx1xx01111x0x + fmov. */ + return 635; + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00100xxxxxx1xx01111x1x + sqdmlal. */ + return 339; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx00101xxxxxx1xx01111x1x + sqdmull. */ + return 341; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0011xxxxxxx1xx01111x1x + sqdmlsl. */ + return 340; + } + } + } + } + } + else + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010000xxxxx1xx011100xx + rev64. */ + return 144; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010000xxxxx1xx011101xx + rev32. */ + return 180; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010000xxxxx1xx01111x0x + fmul. */ + return 622; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010000xxxxx1xx01111x1x + sha1h. */ + return 533; + } + } + } + else + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100010xxxx1xx011100xx + cmgt. */ + return 152; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100010xxxx1xx011101xx + cmge. */ + return 186; + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100011xxxx1x0011100xx + frintn. */ + return 164; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100011xxxx1x0011101xx + frinta. */ + return 197; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100011xxxx1x101110xxx + frintp. */ + return 174; + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010001xxxxx1xx0111100x + fnmul. */ + return 630; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010001xxxxx1xx0111101x + cmgt. */ + return 393; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010001xxxxx1xx011111xx + cmge. */ + return 411; + } + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 19) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100100xx0x1xx011100xx + cls. */ + return 148; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100100xx0x1xx011101xx + clz. */ + return 183; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100100xx1x1xx01110xxx + aese. */ + return 529; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100101xxxx1xx0111000x + sqxtn. */ + return 158; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100101xxxx1xx0111001x + sqxtn2. */ + return 159; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100101xxxx1xx0111010x + uqxtn. */ + return 193; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100101xxxx1xx0111011x + uqxtn2. */ + return 194; + } + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010010xxxxx1xx0111100x + fmax. */ + return 626; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010010xxxxx1xx0111101x + sqxtn. */ + return 397; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010010xxxxx1xx011111xx + uqxtn. */ + return 415; + } + } + } + else + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 20) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100110xxx01xx011100xx + fcmgt. */ + return 170; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100110xxx01xx011101xx + fcmge. */ + return 206; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100110xxx01xx011110xx + fcmgt. */ + return 402; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100110xxx01xx011111xx + fcmge. */ + return 421; + } + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100110xxx11x001110xxx + fmaxnmv. */ + return 34; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100110xxx11x001111xxx + fmaxnmp. */ + return 429; + } + } + else + { + if (((word >> 28) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100110xxx11x101110xxx + fminnmv. */ + return 36; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100110xxx11x101111xxx + fminnmp. */ + return 432; + } + } + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100111xxxx1x0011100xx + fcvtas. */ + return 168; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100111xxxx1x0011101xx + fcvtau. */ + return 201; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100111xxxx1x0011110xx + fcvtas. */ + return 400; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100111xxxx1x0011111xx + fcvtau. */ + return 419; + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100111xxxx1x10111x0xx + urecpe. */ + return 178; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0100111xxxx1x10111x1xx + ursqrte. */ + return 212; + } + } + } + } + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101000xxxx1xx011100xx + saddlp. */ + return 146; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101000xxxx1xx011101xx + uaddlp. */ + return 181; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101001xxxx1xx0111000x + xtn. */ + return 156; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101001xxxx1xx0111001x + xtn2. */ + return 157; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101001xxxx1xx0111010x + sqxtun. */ + return 189; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101001xxxx1xx0111011x + sqxtun2. */ + return 190; + } + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010100xxxxx1xx0111100x + fadd. */ + return 624; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010100xxxxx1xx0111101x + sha256su0. */ + return 535; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010100xxxxx1xx011111xx + sqxtun. */ + return 414; + } + } + } + else + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 20) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101010xxx01xx01110xxx + cmlt. */ + return 154; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101010xxx01xx01111xxx + cmlt. */ + return 395; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101010xxx11xx0111x0xx + smaxv. */ + return 28; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101010xxx11xx0111x1xx + umaxv. */ + return 32; + } + } + } + else + { + if (((word >> 20) & 0x1) == 0) + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101011xxx01x0011100xx + fcvtns. */ + return 166; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101011xxx01x0011101xx + fcvtnu. */ + return 199; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101011xxx01x0011110xx + fcvtns. */ + return 398; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101011xxx01x0011111xx + fcvtnu. */ + return 417; + } + } + } + else + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101011xxx01x1011100xx + fcvtps. */ + return 176; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101011xxx01x1011101xx + fcvtpu. */ + return 210; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101011xxx01x1011110xx + fcvtps. */ + return 405; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101011xxx01x1011111xx + fcvtpu. */ + return 423; + } + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101011xxx11xx0111x0xx + sminv. */ + return 29; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101011xxx11xx0111x1xx + uminv. */ + return 33; + } + } + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 19) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101100xx0x1xx011100xx + sadalp. */ + return 150; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101100xx0x1xx011101xx + uadalp. */ + return 184; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101100xx1x1xx01110xxx + aesmc. */ + return 531; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101101xxxx1xx0111000x + fcvtn. */ + return 160; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101101xxxx1xx0111001x + fcvtn2. */ + return 161; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101101xxxx1xx0111010x + fcvtxn. */ + return 195; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0101101xxxx1xx0111011x + fcvtxn2. */ + return 196; + } + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010110xxxxx1xx011110xx + fmaxnm. */ + return 628; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010110xxxxx1xx011111xx + fcvtxn. */ + return 416; + } + } + } + else + { + if (((word >> 28) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010111xxxxx1xx01110xxx + fcmlt. */ + return 172; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx010111xxxxx1xx01111xxx + fcmlt. */ + return 404; + } + } + } + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx011000xxxxx1xx01110xxx + rev16. */ + return 145; + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx011000xxxxx1xx01111x0x + fdiv. */ + return 623; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx011000xxxxx1xx01111x1x + sha1su1. */ + return 534; + } + } + } + else + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110010xxxx1xx011100xx + cmeq. */ + return 153; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110010xxxx1xx011101xx + cmle. */ + return 187; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110010xxxx1xx011110xx + cmeq. */ + return 394; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110010xxxx1xx011111xx + cmle. */ + return 412; + } + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110011xxxx1x00111x0xx + frintm. */ + return 165; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110011xxxx1x00111x1xx + frintx. */ + return 198; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110011xxxx1x10111x0xx + frintz. */ + return 175; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110011xxxx1x10111x1xx + frinti. */ + return 209; + } + } + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 19) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx011010xxx0x1xx011100xx + cnt. */ + return 149; + } + else + { + if (((word >> 22) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx011010xxx0x10x011101xx + not. */ + return 203; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx011010xxx0x11x011101xx + rbit. */ + return 205; + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx011010xxx1x1xx01110xxx + aesd. */ + return 530; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx011010xxxxx1xx01111xxx + fmin. */ + return 627; + } + } + else + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 20) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110110xxx01xx011100xx + fcmeq. */ + return 171; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110110xxx01xx011101xx + fcmle. */ + return 207; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110110xxx01xx011110xx + fcmeq. */ + return 403; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110110xxx01xx011111xx + fcmle. */ + return 422; + } + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110110xxx11xx0111xxxx + faddp. */ + return 430; + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110111xxxx1x0011100xx + scvtf. */ + return 169; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110111xxxx1x0011101xx + ucvtf. */ + return 202; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110111xxxx1x0011110xx + scvtf. */ + return 401; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110111xxxx1x0011111xx + ucvtf. */ + return 420; + } + } + } + else + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110111xxxx1x1011100xx + frecpe. */ + return 179; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110111xxxx1x1011101xx + frsqrte. */ + return 213; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110111xxxx1x1011110xx + frecpe. */ + return 407; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0110111xxxx1x1011111xx + frsqrte. */ + return 425; + } + } + } + } + } + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 20) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111000xxx01xx011100xx + suqadd. */ + return 147; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111000xxx01xx011101xx + usqadd. */ + return 182; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111000xxx11xx011100xx + saddlv. */ + return 27; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111000xxx11xx011101xx + uaddlv. */ + return 31; + } + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111001xxxx1xx01110x0x + shll. */ + return 191; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111001xxxx1xx01110x1x + shll2. */ + return 192; + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx011100xxxxx1xx0111100x + fsub. */ + return 625; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx011100xxxxx1xx0111101x + suqadd. */ + return 391; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx011100xxxxx1xx011111xx + usqadd. */ + return 409; + } + } + } + else + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111010xxxx1xx011100xx + abs. */ + return 155; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111010xxxx1xx011101xx + neg. */ + return 188; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111010xxxx1xx011110xx + abs. */ + return 396; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111010xxxx1xx011111xx + neg. */ + return 413; + } + } + } + else + { + if (((word >> 20) & 0x1) == 0) + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111011xxx01x0011100xx + fcvtms. */ + return 167; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111011xxx01x0011101xx + fcvtmu. */ + return 200; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111011xxx01x0011110xx + fcvtms. */ + return 399; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111011xxx01x0011111xx + fcvtmu. */ + return 418; + } + } + } + else + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111011xxx01x1011100xx + fcvtzs. */ + return 177; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111011xxx01x1011101xx + fcvtzu. */ + return 211; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111011xxx01x1011110xx + fcvtzs. */ + return 406; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111011xxx01x1011111xx + fcvtzu. */ + return 424; + } + } + } + } + else + { + if (((word >> 28) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111011xxx11xx01110xxx + addv. */ + return 30; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111011xxx11xx01111xxx + addp. */ + return 428; + } + } + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 19) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111100xx0x1xx011100xx + sqabs. */ + return 151; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111100xx0x1xx011101xx + sqneg. */ + return 185; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111100xx1x1xx01110xxx + aesimc. */ + return 532; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111101xxxx1xx01110x0x + fcvtl. */ + return 162; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111101xxxx1xx01110x1x + fcvtl2. */ + return 163; + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx011110xxxxx1xx0111100x + fminnm. */ + return 629; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx011110xxxxx1xx0111101x + sqabs. */ + return 392; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx011110xxxxx1xx011111xx + sqneg. */ + return 410; + } + } + } + else + { + if (((word >> 16) & 0x1) == 0) + { + if (((word >> 20) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111110xxx01xx0111x0xx + fabs. */ + return 173; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111110xxx01xx0111x1xx + fneg. */ + return 208; + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111110xxx11x001110xxx + fmaxv. */ + return 35; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111110xxx11x001111xxx + fmaxp. */ + return 431; + } + } + else + { + if (((word >> 28) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111110xxx11x101110xxx + fminv. */ + return 37; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111110xxx11x101111xxx + fminp. */ + return 433; + } + } + } + } + else + { + if (((word >> 28) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111111xxxx1xx01110xxx + fsqrt. */ + return 214; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0111111xxxx1xx01111xxx + frecpx. */ + return 408; + } + } + } + } + } + } + } + } + else + { + if (((word >> 11) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100000xxxxx1xx011100xx + shadd. */ + return 221; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100000xxxxx1xx011101xx + uhadd. */ + return 261; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100001xxxxx1xx011100xx + add. */ + return 236; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100001xxxxx1xx011101xx + sub. */ + return 276; + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100010xxxxx1xx011100xx + sshl. */ + return 228; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100010xxxxx1xx011101xx + ushl. */ + return 268; + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100011xxxxx1x0011100xx + fmaxnm. */ + return 244; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100011xxxxx1x0011101xx + fmaxnmp. */ + return 283; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100011xxxxx1x1011100xx + fminnm. */ + return 253; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100011xxxxx1x1011101xx + fminnmp. */ + return 292; + } + } + } + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100100xxxxx1xx011100xx + shsub. */ + return 224; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100100xxxxx1xx011101xx + uhsub. */ + return 264; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100101xxxxx1xx011100xx + smaxp. */ + return 240; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100101xxxxx1xx011101xx + umaxp. */ + return 280; + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100110xxxxx1xx011100xx + smax. */ + return 232; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100110xxxxx1xx011101xx + umax. */ + return 272; + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100111xxxxx1x0011100xx + fcmeq. */ + return 248; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100111xxxxx1x0011101xx + fcmge. */ + return 286; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100111xxxxx1x101110xxx + fcmgt. */ + return 294; + } + } + } + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101000xxxxx1xx011100xx + srhadd. */ + return 223; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101000xxxxx1xx011101xx + urhadd. */ + return 263; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101001xxxxx1xx011100xx + mla. */ + return 238; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101001xxxxx1xx011101xx + mls. */ + return 278; + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101010xxxxx1xx011100xx + srshl. */ + return 230; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101010xxxxx1xx011101xx + urshl. */ + return 270; + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101011xxxxx1x0011100xx + fadd. */ + return 246; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101011xxxxx1x0011101xx + faddp. */ + return 284; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101011xxxxx1x1011100xx + fsub. */ + return 255; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101011xxxxx1x1011101xx + fabd. */ + return 293; + } + } + } + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101100xxxxx1xx011100xx + cmgt. */ + return 226; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101100xxxxx1xx011101xx + cmhi. */ + return 266; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101101xxxxx1xx011100xx + sqdmulh. */ + return 242; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101101xxxxx1xx011101xx + sqrdmulh. */ + return 282; + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101110xxxxx1xx011100xx + sabd. */ + return 234; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101110xxxxx1xx011101xx + uabd. */ + return 274; + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101111xxxxx1x0011100xx + fmax. */ + return 249; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101111xxxxx1x0011101xx + fmaxp. */ + return 288; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101111xxxxx1x1011100xx + fmin. */ + return 256; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101111xxxxx1x1011101xx + fminp. */ + return 296; + } + } + } + } + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + if (((word >> 4) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxx0xxxxx10xxxxxxxxx1xx0111100x + fccmp. */ + return 604; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxx1xxxxx10xxxxxxxxx1xx0111100x + fccmpe. */ + return 605; + } + } + else + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx10000xxxxxx1xx0111101x + add. */ + return 447; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx10001xxxxxx1xx0111101x + sshl. */ + return 445; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1001xxxxxxx1xx0111101x + fcmeq. */ + return 440; + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1010xxxxxxx1xx0111101x + srshl. */ + return 446; + } + else + { + if (((word >> 15) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1011x0xxxxx1xx0111101x + cmgt. */ + return 443; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1011x1xxxxx1xx0111101x + sqdmulh. */ + return 438; + } + } + } + } + } + else + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx10000xxxxxx1xx011111xx + sub. */ + return 463; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx10001xxxxxx1xx011111xx + ushl. */ + return 461; + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1001xxxxxxx1x0011111xx + fcmge. */ + return 454; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1001xxxxxxx1x1011111xx + fcmgt. */ + return 457; + } + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1010x0xxxxx1xx011111xx + urshl. */ + return 462; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1010x1xxxxx1xx011111xx + fabd. */ + return 456; + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1011x0xxxxx1xx011111xx + cmhi. */ + return 459; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1011x1xxxxx1xx011111xx + sqrdmulh. */ + return 453; + } + } + } + } + } + } + else + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110000xxxxx1xx011100xx + sqadd. */ + return 222; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110000xxxxx1xx011101xx + uqadd. */ + return 262; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110001xxxxx1xx011100xx + cmtst. */ + return 237; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110001xxxxx1xx011101xx + cmeq. */ + return 277; + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110010xxxxx1xx011100xx + sqshl. */ + return 229; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110010xxxxx1xx011101xx + uqshl. */ + return 269; + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110011xxxxx1x001110xxx + fmla. */ + return 245; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110011xxxxx1x101110xxx + fmls. */ + return 254; + } + } + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110100xxxxx1xx011100xx + sqsub. */ + return 225; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110100xxxxx1xx011101xx + uqsub. */ + return 265; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110101xxxxx1xx011100xx + sminp. */ + return 241; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110101xxxxx1xx011101xx + uminp. */ + return 281; + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110110xxxxx1xx011100xx + smin. */ + return 233; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110110xxxxx1xx011101xx + umin. */ + return 273; + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110111xxxxx1x001110xxx + facge. */ + return 287; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110111xxxxx1x101110xxx + facgt. */ + return 295; + } + } + } + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 22) & 0x1) == 0) + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111000xxxxx100011100xx + and. */ + return 251; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111000xxxxx100011101xx + eor. */ + return 290; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111000xxxxx101011100xx + orr. */ + return 258; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111000xxxxx101011101xx + bit. */ + return 297; + } + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111000xxxxx110011100xx + bic. */ + return 252; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111000xxxxx110011101xx + bsl. */ + return 291; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111000xxxxx111011100xx + orn. */ + return 260; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111000xxxxx111011101xx + bif. */ + return 298; + } + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111001xxxxx1xx011100xx + mul. */ + return 239; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111001xxxxx1xx011101xx + pmul. */ + return 279; + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111010xxxxx1xx011100xx + sqrshl. */ + return 231; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111010xxxxx1xx011101xx + uqrshl. */ + return 271; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111011xxxxx1xx011100xx + fmulx. */ + return 247; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111011xxxxx1xx011101xx + fmul. */ + return 285; + } + } + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111100xxxxx1xx011100xx + cmge. */ + return 227; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111100xxxxx1xx011101xx + cmhs. */ + return 267; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111101xxxxx1xx01110xxx + addp. */ + return 243; + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111110xxxxx1xx011100xx + saba. */ + return 235; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111110xxxxx1xx011101xx + uaba. */ + return 275; + } + } + else + { + if (((word >> 23) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111111xxxxx1x0011100xx + frecps. */ + return 250; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111111xxxxx1x0011101xx + fdiv. */ + return 289; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx111111xxxxx1x101110xxx + frsqrts. */ + return 257; + } + } + } + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx11xxxxxxxxx1xx0111100x + fcsel. */ + return 636; + } + else + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110000xxxxx1xx0111101x + sqadd. */ + return 434; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110001xxxxx1xx0111101x + cmtst. */ + return 448; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx11001xxxxxx1xx0111101x + sqshl. */ + return 436; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1101xxxxxxx1xx0111101x + sqsub. */ + return 435; + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1110x0xxxxx1xx0111101x + sqrshl. */ + return 437; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1110x1xxxxx1xx0111101x + fmulx. */ + return 439; + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx11110xxxxxx1xx0111101x + cmge. */ + return 444; + } + else + { + if (((word >> 23) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx11111xxxxxx1x00111101x + frecps. */ + return 441; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx11111xxxxxx1x10111101x + frsqrts. */ + return 442; + } + } + } + } + } + } + else + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 15) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110000xxxxx1xx011111xx + uqadd. */ + return 449; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110001xxxxx1xx011111xx + cmeq. */ + return 464; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx11001xxxxxx1xx011111xx + uqshl. */ + return 451; + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx11010xxxxxx1xx011111xx + uqsub. */ + return 450; + } + else + { + if (((word >> 23) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx11011xxxxxx1x0011111xx + facge. */ + return 455; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx11011xxxxxx1x1011111xx + facgt. */ + return 458; + } + } + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1110xxxxxxx1xx011111xx + uqrshl. */ + return 452; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1111xxxxxxx1xx011111xx + cmhs. */ + return 460; + } + } + } + } + } + } + } + } + else + { + if (((word >> 15) & 0x1) == 0) + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 10) & 0x1) == 0) + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x0000xxxxxxxx11110xxx + mla. */ + return 110; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x0010xxxxxxxx11110xxx + mls. */ + return 113; + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x0100xxxxxxxx1111000x + smlal. */ + return 92; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x0100xxxxxxxx1111001x + smlal2. */ + return 93; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x0100xxxxxxxx1111010x + umlal. */ + return 111; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x0100xxxxxxxx1111011x + umlal2. */ + return 112; + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x0110xxxxxxxx1111000x + smlsl. */ + return 96; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x0110xxxxxxxx1111001x + smlsl2. */ + return 97; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x0110xxxxxxxx1111010x + umlsl. */ + return 114; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x0110xxxxxxxx1111011x + umlsl2. */ + return 115; + } + } + } + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x1000xxxxxxxx11110xxx + fmla. */ + return 107; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x1010xxxxxxxx11110xxx + fmls. */ + return 108; + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x1100xxxxxxxx11110x0x + sqdmlal. */ + return 94; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x1100xxxxxxxx11110x1x + sqdmlal2. */ + return 95; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x1110xxxxxxxx11110x0x + sqdmlsl. */ + return 98; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x1110xxxxxxxx11110x1x + sqdmlsl2. */ + return 99; + } + } + } + } + } + else + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1x0xx0xxxxxxxx111100xx + movi. */ + return 120; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1x0xx0xxxxxxxx111101xx + mvni. */ + return 127; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1x1xx0xxxxxxxx111100xx + orr. */ + return 121; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1x1xx0xxxxxxxx111101xx + bic. */ + return 128; + } + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + if (((word >> 21) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx0xx1111100x + fmadd. */ + return 631; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx0xxxxx1xx1111100x + fnmadd. */ + return 633; + } + } + else + { + if (((word >> 10) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0xx000xxxxxxxx1111101x + fmla. */ + return 347; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0xx010xxxxxxxx1111101x + fmls. */ + return 348; + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0xx100xxxxxxxx1111101x + sqdmlal. */ + return 342; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0xx110xxxxxxxx1111101x + sqdmlsl. */ + return 343; + } + } + } + else + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1x00x0xxxxxxxx1111101x + sshr. */ + return 465; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1x01x0xxxxxxxx1111101x + srshr. */ + return 467; + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1x1000xxxxxxxx1111101x + ssra. */ + return 466; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1x1010xxxxxxxx1111101x + shl. */ + return 469; + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1x1100xxxxxxxx1111101x + srsra. */ + return 468; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1x1110xxxxxxxx1111101x + sqshl. */ + return 470; + } + } + } + } + } + } + else + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxx0000xxxxxxxx111111xx + ushr. */ + return 475; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxx0010xxxxxxxx111111xx + sri. */ + return 479; + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxx0100xxxxxxxx111111xx + urshr. */ + return 477; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxx0110xxxxxxxx111111xx + sqshlu. */ + return 481; + } + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxx1000xxxxxxxx111111xx + usra. */ + return 476; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxx1010xxxxxxxx111111xx + sli. */ + return 480; + } + } + else + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxx1100xxxxxxxx111111xx + ursra. */ + return 478; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxx1110xxxxxxxx111111xx + uqshl. */ + return 482; + } + } + } + } + } + } + else + { + if (((word >> 28) & 0x1) == 0) + { + if (((word >> 10) & 0x1) == 0) + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x0001xxxxxxxx11110xxx + mul. */ + return 100; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x0011xxxxxxxx11110xxx + sqdmulh. */ + return 105; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x01x1xxxxxxxx1111000x + smull. */ + return 101; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x01x1xxxxxxxx1111001x + smull2. */ + return 102; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x01x1xxxxxxxx1111010x + umull. */ + return 116; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x01x1xxxxxxxx1111011x + umull2. */ + return 117; + } + } + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x1001xxxxxxxx111100xx + fmul. */ + return 109; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x1001xxxxxxxx111101xx + fmulx. */ + return 118; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x1011xxxxxxxx11110xxx + sqrdmulh. */ + return 106; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x11x1xxxxxxxx11110x0x + sqdmull. */ + return 103; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x11x1xxxxxxxx11110x1x + sqdmull2. */ + return 104; + } + } + } + } + else + { + if (((word >> 11) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100x01xxxxxxxx111100xx + movi. */ + return 122; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100x01xxxxxxxx111101xx + mvni. */ + return 129; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101x01xxxxxxxx111100xx + orr. */ + return 123; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101x01xxxxxxxx111101xx + bic. */ + return 130; + } + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx10x011xxxxxxxx111100xx + movi. */ + return 124; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx10x011xxxxxxxx111101xx + mvni. */ + return 131; + } + } + else + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100111xxxxxxxx111100xx + movi. */ + return 125; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100111xxxxxxxx111101xx + movi. */ + return 132; + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101111xxxxxxxx111100xx + fmov. */ + return 126; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101111xxxxxxxx111101xx + fmov. */ + return 134; + } + } + } + } + } + else + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110xx1xxxxxxxx1111000x + rshrn. */ + return 307; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110xx1xxxxxxxx1111001x + rshrn2. */ + return 308; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110xx1xxxxxxxx1111010x + sqrshrun. */ + return 327; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110xx1xxxxxxxx1111011x + sqrshrun2. */ + return 328; + } + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1110x1xxxxxxxx1111000x + sqrshrn. */ + return 311; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1110x1xxxxxxxx1111001x + sqrshrn2. */ + return 312; + } + } + else + { + if (((word >> 30) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1110x1xxxxxxxx1111010x + uqrshrn. */ + return 331; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1110x1xxxxxxxx1111011x + uqrshrn2. */ + return 332; + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1111x1xxxxxxxx111100xx + fcvtzs. */ + return 316; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1111x1xxxxxxxx111101xx + fcvtzu. */ + return 336; + } + } + } + } + } + } + else + { + if (((word >> 29) & 0x1) == 0) + { + if (((word >> 30) & 0x1) == 0) + { + if (((word >> 21) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx1xxxxx0xx1111100x + fmsub. */ + return 632; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxxxxxxx1xxxxx1xx1111100x + fnmsub. */ + return 634; + } + } + else + { + if (((word >> 10) & 0x1) == 0) + { + if (((word >> 12) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x0xx1xxxxxxxx1111101x + sqdmulh. */ + return 345; + } + else + { + if (((word >> 13) & 0x1) == 0) + { + if (((word >> 14) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x1001xxxxxxxx1111101x + fmul. */ + return 349; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x1011xxxxxxxx1111101x + sqrdmulh. */ + return 346; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0x11x1xxxxxxxx1111101x + sqdmull. */ + return 344; + } + } + } + else + { + if (((word >> 11) & 0x1) == 0) + { + if (((word >> 12) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx100xx1xxxxxxxx1111101x + scvtf. */ + return 473; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101xx1xxxxxxxx1111101x + sqshrn. */ + return 471; + } + } + else + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx11x0x1xxxxxxxx1111101x + sqrshrn. */ + return 472; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx11x1x1xxxxxxxx1111101x + fcvtzs. */ + return 474; + } + } + } + } + } + else + { + if (((word >> 10) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx0xxxx1xxxxxxxx111111xx + fmulx. */ + return 350; + } + else + { + if (((word >> 11) & 0x1) == 0) + { + if (((word >> 12) & 0x1) == 0) + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1000x1xxxxxxxx111111xx + sqshrun. */ + return 483; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1001x1xxxxxxxx111111xx + ucvtf. */ + return 487; + } + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx101xx1xxxxxxxx111111xx + uqshrn. */ + return 485; + } + } + else + { + if (((word >> 12) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx110xx1xxxxxxxx111111xx + sqrshrun. */ + return 484; + } + else + { + if (((word >> 13) & 0x1) == 0) + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1110x1xxxxxxxx111111xx + uqrshrn. */ + return 486; + } + else + { + /* 33222222222211111111110000000000 + 10987654321098765432109876543210 + xxxxxxxxxx1111x1xxxxxxxx111111xx + fcvtzu. */ + return 488; + } + } + } + } + } + } + } + } + } + } + } +} + +/* Lookup opcode WORD in the opcode table. N.B. all alias + opcodes are ignored here. */ + +const aarch64_opcode * +aarch64_opcode_lookup (uint32_t word) +{ + return aarch64_opcode_table + aarch64_opcode_lookup_1 (word); +} + +const aarch64_opcode * +aarch64_find_next_opcode (const aarch64_opcode *opcode) +{ + /* Use the index as the key to locate the next opcode. */ + int key = opcode - aarch64_opcode_table; + int value; + switch (key) + { + case 727: value = 731; break; /* stnp --> stp. */ + case 731: return NULL; /* stp --> NULL. */ + case 728: value = 732; break; /* ldnp --> ldp. */ + case 732: return NULL; /* ldp --> NULL. */ + case 351: value = 352; break; /* st4 --> st1. */ + case 352: value = 353; break; /* st1 --> st2. */ + case 353: value = 354; break; /* st2 --> st3. */ + case 354: return NULL; /* st3 --> NULL. */ + case 359: value = 360; break; /* st4 --> st1. */ + case 360: value = 361; break; /* st1 --> st2. */ + case 361: value = 362; break; /* st2 --> st3. */ + case 362: return NULL; /* st3 --> NULL. */ + case 355: value = 356; break; /* ld4 --> ld1. */ + case 356: value = 357; break; /* ld1 --> ld2. */ + case 357: value = 358; break; /* ld2 --> ld3. */ + case 358: return NULL; /* ld3 --> NULL. */ + case 371: value = 373; break; /* ld1 --> ld1r. */ + case 373: return NULL; /* ld1r --> NULL. */ + case 375: value = 377; break; /* ld2 --> ld2r. */ + case 377: return NULL; /* ld2r --> NULL. */ + case 372: value = 374; break; /* ld3 --> ld3r. */ + case 374: return NULL; /* ld3r --> NULL. */ + case 376: value = 378; break; /* ld4 --> ld4r. */ + case 378: return NULL; /* ld4r --> NULL. */ + case 363: value = 364; break; /* ld4 --> ld1. */ + case 364: value = 365; break; /* ld1 --> ld2. */ + case 365: value = 366; break; /* ld2 --> ld3. */ + case 366: return NULL; /* ld3 --> NULL. */ + case 383: value = 385; break; /* ld1 --> ld1r. */ + case 385: return NULL; /* ld1r --> NULL. */ + case 384: value = 386; break; /* ld3 --> ld3r. */ + case 386: return NULL; /* ld3r --> NULL. */ + case 387: value = 389; break; /* ld2 --> ld2r. */ + case 389: return NULL; /* ld2r --> NULL. */ + case 388: value = 390; break; /* ld4 --> ld4r. */ + case 390: return NULL; /* ld4r --> NULL. */ + case 120: value = 299; break; /* movi --> sshr. */ + case 299: value = 301; break; /* sshr --> srshr. */ + case 301: return NULL; /* srshr --> NULL. */ + case 127: value = 317; break; /* mvni --> ushr. */ + case 317: value = 319; break; /* ushr --> urshr. */ + case 319: value = 321; break; /* urshr --> sri. */ + case 321: value = 323; break; /* sri --> sqshlu. */ + case 323: return NULL; /* sqshlu --> NULL. */ + case 121: value = 300; break; /* orr --> ssra. */ + case 300: value = 302; break; /* ssra --> srsra. */ + case 302: value = 303; break; /* srsra --> shl. */ + case 303: value = 304; break; /* shl --> sqshl. */ + case 304: return NULL; /* sqshl --> NULL. */ + case 128: value = 318; break; /* bic --> usra. */ + case 318: value = 320; break; /* usra --> ursra. */ + case 320: value = 322; break; /* ursra --> sli. */ + case 322: value = 324; break; /* sli --> uqshl. */ + case 324: return NULL; /* uqshl --> NULL. */ + case 122: value = 305; break; /* movi --> shrn. */ + case 305: value = 306; break; /* shrn --> shrn2. */ + case 306: value = 313; break; /* shrn2 --> sshll. */ + case 313: value = 314; break; /* sshll --> sshll2. */ + case 314: return NULL; /* sshll2 --> NULL. */ + case 129: value = 325; break; /* mvni --> sqshrun. */ + case 325: value = 326; break; /* sqshrun --> sqshrun2. */ + case 326: value = 333; break; /* sqshrun2 --> ushll. */ + case 333: value = 334; break; /* ushll --> ushll2. */ + case 334: return NULL; /* ushll2 --> NULL. */ + case 123: value = 309; break; /* orr --> sqshrn. */ + case 309: value = 310; break; /* sqshrn --> sqshrn2. */ + case 310: return NULL; /* sqshrn2 --> NULL. */ + case 130: value = 329; break; /* bic --> uqshrn. */ + case 329: value = 330; break; /* uqshrn --> uqshrn2. */ + case 330: return NULL; /* uqshrn2 --> NULL. */ + case 125: value = 315; break; /* movi --> scvtf. */ + case 315: return NULL; /* scvtf --> NULL. */ + case 132: value = 133; break; /* movi --> movi. */ + case 133: value = 335; break; /* movi --> ucvtf. */ + case 335: return NULL; /* ucvtf --> NULL. */ + default: return NULL; + } + + return aarch64_opcode_table + value; +} + +const aarch64_opcode * +aarch64_find_alias_opcode (const aarch64_opcode *opcode) +{ + /* Use the index as the key to locate the alias opcode. */ + int key = opcode - aarch64_opcode_table; + int value; + switch (key) + { + case 2: value = 3; break; /* sbc --> ngc. */ + case 4: value = 5; break; /* sbcs --> ngcs. */ + case 7: value = 8; break; /* adds --> cmn. */ + case 10: value = 11; break; /* subs --> cmp. */ + case 12: value = 13; break; /* add --> mov. */ + case 14: value = 15; break; /* adds --> cmn. */ + case 17: value = 18; break; /* subs --> cmp. */ + case 20: value = 21; break; /* adds --> cmn. */ + case 22: value = 23; break; /* sub --> neg. */ + case 24: value = 26; break; /* subs --> negs. */ + case 138: value = 139; break; /* umov --> mov. */ + case 140: value = 141; break; /* ins --> mov. */ + case 142: value = 143; break; /* ins --> mov. */ + case 203: value = 204; break; /* not --> mvn. */ + case 258: value = 259; break; /* orr --> mov. */ + case 426: value = 427; break; /* dup --> mov. */ + case 489: value = 494; break; /* sbfm --> sxtw. */ + case 496: value = 498; break; /* bfm --> bfxil. */ + case 499: value = 503; break; /* ubfm --> uxth. */ + case 521: value = 523; break; /* csinc --> cset. */ + case 524: value = 526; break; /* csinv --> csetm. */ + case 527: value = 528; break; /* csneg --> cneg. */ + case 552: value = 553; break; /* lslv --> lsl. */ + case 554: value = 555; break; /* lsrv --> lsr. */ + case 556: value = 557; break; /* asrv --> asr. */ + case 558: value = 559; break; /* rorv --> ror. */ + case 560: value = 561; break; /* madd --> mul. */ + case 562: value = 563; break; /* msub --> mneg. */ + case 564: value = 565; break; /* smaddl --> smull. */ + case 566: value = 567; break; /* smsubl --> smnegl. */ + case 569: value = 570; break; /* umaddl --> umull. */ + case 571: value = 572; break; /* umsubl --> umnegl. */ + case 582: value = 583; break; /* extr --> ror. */ + case 681: value = 683; break; /* sturb --> strb. */ + case 682: value = 684; break; /* ldurb --> ldrb. */ + case 685: value = 686; break; /* ldursb --> ldrsb. */ + case 687: value = 689; break; /* stur --> str. */ + case 688: value = 690; break; /* ldur --> ldr. */ + case 691: value = 693; break; /* sturh --> strh. */ + case 692: value = 694; break; /* ldurh --> ldrh. */ + case 695: value = 696; break; /* ldursh --> ldrsh. */ + case 697: value = 699; break; /* stur --> str. */ + case 698: value = 700; break; /* ldur --> ldr. */ + case 701: value = 702; break; /* ldursw --> ldrsw. */ + case 703: value = 704; break; /* prfum --> prfm. */ + case 745: value = 746; break; /* and --> bic. */ + case 747: value = 748; break; /* orr --> mov. */ + case 750: value = 751; break; /* ands --> tst. */ + case 754: value = 756; break; /* orr --> uxtw. */ + case 757: value = 758; break; /* orn --> mvn. */ + case 761: value = 762; break; /* ands --> tst. */ + case 764: value = 765; break; /* movn --> mov. */ + case 766: value = 767; break; /* movz --> mov. */ + case 772: value = 778; break; /* hint --> sevl. */ + case 783: value = 787; break; /* sys --> tlbi. */ + default: return NULL; + } + + return aarch64_opcode_table + value; +} + +const aarch64_opcode * +aarch64_find_next_alias_opcode (const aarch64_opcode *opcode) +{ + /* Use the index as the key to locate the next opcode. */ + int key = opcode - aarch64_opcode_table; + int value; + switch (key) + { + case 26: value = 25; break; /* negs --> cmp. */ + case 494: value = 493; break; /* sxtw --> sxth. */ + case 493: value = 492; break; /* sxth --> sxtb. */ + case 492: value = 495; break; /* sxtb --> asr. */ + case 495: value = 491; break; /* asr --> sbfx. */ + case 491: value = 490; break; /* sbfx --> sbfiz. */ + case 498: value = 497; break; /* bfxil --> bfi. */ + case 503: value = 502; break; /* uxth --> uxtb. */ + case 502: value = 505; break; /* uxtb --> lsr. */ + case 505: value = 504; break; /* lsr --> lsl. */ + case 504: value = 501; break; /* lsl --> ubfx. */ + case 501: value = 500; break; /* ubfx --> ubfiz. */ + case 523: value = 522; break; /* cset --> cinc. */ + case 526: value = 525; break; /* csetm --> cinv. */ + case 756: value = 755; break; /* uxtw --> mov. */ + case 778: value = 777; break; /* sevl --> sev. */ + case 777: value = 776; break; /* sev --> wfi. */ + case 776: value = 775; break; /* wfi --> wfe. */ + case 775: value = 774; break; /* wfe --> yield. */ + case 774: value = 773; break; /* yield --> nop. */ + case 787: value = 786; break; /* tlbi --> ic. */ + case 786: value = 785; break; /* ic --> dc. */ + case 785: value = 784; break; /* dc --> at. */ + default: return NULL; + } + + return aarch64_opcode_table + value; +} + +int +aarch64_extract_operand (const aarch64_operand *self, + aarch64_opnd_info *info, + aarch64_insn code, const aarch64_inst *inst) +{ + /* Use the index as the key. */ + int key = self - aarch64_operands; + switch (key) + { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 9: + case 10: + case 13: + case 14: + case 15: + case 16: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 34: + case 35: + return aarch64_ext_regno (self, info, code, inst); + case 8: + return aarch64_ext_regrt_sysins (self, info, code, inst); + case 11: + return aarch64_ext_reg_extended (self, info, code, inst); + case 12: + return aarch64_ext_reg_shifted (self, info, code, inst); + case 17: + return aarch64_ext_ft (self, info, code, inst); + case 27: + case 28: + case 29: + return aarch64_ext_reglane (self, info, code, inst); + case 30: + return aarch64_ext_reglist (self, info, code, inst); + case 31: + return aarch64_ext_ldst_reglist (self, info, code, inst); + case 32: + return aarch64_ext_ldst_reglist_r (self, info, code, inst); + case 33: + return aarch64_ext_ldst_elemlist (self, info, code, inst); + case 36: + case 45: + case 46: + case 47: + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case 64: + case 65: + case 66: + case 67: + case 68: + return aarch64_ext_imm (self, info, code, inst); + case 37: + case 38: + return aarch64_ext_advsimd_imm_shift (self, info, code, inst); + case 39: + case 40: + case 41: + return aarch64_ext_advsimd_imm_modified (self, info, code, inst); + case 42: + return aarch64_ext_shll_imm (self, info, code, inst); + case 58: + return aarch64_ext_limm (self, info, code, inst); + case 59: + return aarch64_ext_aimm (self, info, code, inst); + case 60: + return aarch64_ext_imm_half (self, info, code, inst); + case 61: + return aarch64_ext_fbits (self, info, code, inst); + case 63: + return aarch64_ext_cond (self, info, code, inst); + case 69: + case 75: + return aarch64_ext_addr_simple (self, info, code, inst); + case 70: + return aarch64_ext_addr_regoff (self, info, code, inst); + case 71: + case 72: + case 73: + return aarch64_ext_addr_simm (self, info, code, inst); + case 74: + return aarch64_ext_addr_uimm12 (self, info, code, inst); + case 76: + return aarch64_ext_simd_addr_post (self, info, code, inst); + case 77: + return aarch64_ext_sysreg (self, info, code, inst); + case 78: + return aarch64_ext_pstatefield (self, info, code, inst); + case 79: + case 80: + case 81: + case 82: + return aarch64_ext_sysins_op (self, info, code, inst); + case 83: + case 84: + return aarch64_ext_barrier (self, info, code, inst); + case 85: + return aarch64_ext_prfop (self, info, code, inst); + default: assert (0); abort (); + } +} diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c new file mode 100644 index 0000000..84b7b0a --- /dev/null +++ b/opcodes/aarch64-dis.c @@ -0,0 +1,2392 @@ +/* aarch64-dis.c -- AArch64 disassembler. + Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING3. If not, + see <http://www.gnu.org/licenses/>. */ + +#include "sysdep.h" +#include "bfd_stdint.h" +#include "dis-asm.h" +#include "libiberty.h" +#include "opintl.h" +#include "aarch64-dis.h" + +#if !defined(EMBEDDED_ENV) +#define SYMTAB_AVAILABLE 1 +#include "elf-bfd.h" +#include "elf/aarch64.h" +#endif + +#define ERR_OK 0 +#define ERR_UND -1 +#define ERR_UNP -3 +#define ERR_NYI -5 + +#define INSNLEN 4 + +/* Cached mapping symbol state. */ +enum map_type +{ + MAP_INSN, + MAP_DATA +}; + +static enum map_type last_type; +static int last_mapping_sym = -1; +static bfd_vma last_mapping_addr = 0; + +/* Other options */ +static int no_aliases = 0; /* If set disassemble as most general inst. */ + + +static void +set_default_aarch64_dis_options (struct disassemble_info *info ATTRIBUTE_UNUSED) +{ +} + +static void +parse_aarch64_dis_option (const char *option, unsigned int len ATTRIBUTE_UNUSED) +{ + /* Try to match options that are simple flags */ + if (CONST_STRNEQ (option, "no-aliases")) + { + no_aliases = 1; + return; + } + + if (CONST_STRNEQ (option, "aliases")) + { + no_aliases = 0; + return; + } + +#ifdef DEBUG_AARCH64 + if (CONST_STRNEQ (option, "debug_dump")) + { + debug_dump = 1; + return; + } +#endif /* DEBUG_AARCH64 */ + + /* Invalid option. */ + fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option); +} + +static void +parse_aarch64_dis_options (const char *options) +{ + const char *option_end; + + if (options == NULL) + return; + + while (*options != '\0') + { + /* Skip empty options. */ + if (*options == ',') + { + options++; + continue; + } + + /* We know that *options is neither NUL or a comma. */ + option_end = options + 1; + while (*option_end != ',' && *option_end != '\0') + option_end++; + + parse_aarch64_dis_option (options, option_end - options); + + /* Go on to the next one. If option_end points to a comma, it + will be skipped above. */ + options = option_end; + } +} + +/* Functions doing the instruction disassembling. */ + +/* The unnamed arguments consist of the number of fields and information about + these fields where the VALUE will be extracted from CODE and returned. + MASK can be zero or the base mask of the opcode. + + N.B. the fields are required to be in such an order than the most signficant + field for VALUE comes the first, e.g. the <index> in + SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>] + is encoded in H:L:M in some cases, the the fields H:L:M should be passed in + the order of H, L, M. */ + +static inline aarch64_insn +extract_fields (aarch64_insn code, aarch64_insn mask, ...) +{ + uint32_t num; + const aarch64_field *field; + enum aarch64_field_kind kind; + va_list va; + + va_start (va, mask); + num = va_arg (va, uint32_t); + assert (num <= 5); + aarch64_insn value = 0x0; + while (num--) + { + kind = va_arg (va, enum aarch64_field_kind); + field = &fields[kind]; + value <<= field->width; + value |= extract_field (kind, code, mask); + } + return value; +} + +/* Sign-extend bit I of VALUE. */ +static inline int32_t +sign_extend (aarch64_insn value, unsigned i) +{ + uint32_t ret = value; + + assert (i < 32); + if ((value >> i) & 0x1) + { + uint32_t val = (uint32_t)(-1) << i; + ret = ret | val; + } + return (int32_t) ret; +} + +/* N.B. the following inline helpfer functions create a dependency on the + order of operand qualifier enumerators. */ + +/* Given VALUE, return qualifier for a general purpose register. */ +static inline enum aarch64_opnd_qualifier +get_greg_qualifier_from_value (aarch64_insn value) +{ + enum aarch64_opnd_qualifier qualifier = AARCH64_OPND_QLF_W + value; + assert (value <= 0x1 + && aarch64_get_qualifier_standard_value (qualifier) == value); + return qualifier; +} + +/* Given VALUE, return qualifier for a vector register. */ +static inline enum aarch64_opnd_qualifier +get_vreg_qualifier_from_value (aarch64_insn value) +{ + enum aarch64_opnd_qualifier qualifier = AARCH64_OPND_QLF_V_8B + value; + + assert (value <= 0x8 + && aarch64_get_qualifier_standard_value (qualifier) == value); + return qualifier; +} + +/* Given VALUE, return qualifier for an FP or AdvSIMD scalar register. */ +static inline enum aarch64_opnd_qualifier +get_sreg_qualifier_from_value (aarch64_insn value) +{ + enum aarch64_opnd_qualifier qualifier = AARCH64_OPND_QLF_S_B + value; + + assert (value <= 0x4 + && aarch64_get_qualifier_standard_value (qualifier) == value); + return qualifier; +} + +/* Given the instruction in *INST which is probably half way through the + decoding and our caller wants to know the expected qualifier for operand + I. Return such a qualifier if we can establish it; otherwise return + AARCH64_OPND_QLF_NIL. */ + +static aarch64_opnd_qualifier_t +get_expected_qualifier (const aarch64_inst *inst, int i) +{ + aarch64_opnd_qualifier_seq_t qualifiers; + /* Should not be called if the qualifier is known. */ + assert (inst->operands[i].qualifier == AARCH64_OPND_QLF_NIL); + if (aarch64_find_best_match (inst, inst->opcode->qualifiers_list, + i, qualifiers)) + return qualifiers[i]; + else + return AARCH64_OPND_QLF_NIL; +} + +/* Operand extractors. */ + +int +aarch64_ext_regno (const aarch64_operand *self, aarch64_opnd_info *info, + const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + info->reg.regno = extract_field (self->fields[0], code, 0); + return 1; +} + +/* e.g. IC <ic_op>{, <Xt>}. */ +int +aarch64_ext_regrt_sysins (const aarch64_operand *self, aarch64_opnd_info *info, + const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + info->reg.regno = extract_field (self->fields[0], code, 0); + assert (info->idx == 1 + && (aarch64_get_operand_class (inst->operands[0].type) + == AARCH64_OPND_CLASS_SYSTEM)); + /* This will make the constraint checking happy and more importantly will + help the disassembler determine whether this operand is optional or + not. */ + info->present = inst->operands[0].sysins_op->has_xt; + + return 1; +} + +/* e.g. SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>]. */ +int +aarch64_ext_reglane (const aarch64_operand *self, aarch64_opnd_info *info, + const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* regno */ + info->reglane.regno = extract_field (self->fields[0], code, + inst->opcode->mask); + + /* Index and/or type. */ + if (inst->opcode->iclass == asisdone + || inst->opcode->iclass == asimdins) + { + if (info->type == AARCH64_OPND_En + && inst->opcode->operands[0] == AARCH64_OPND_Ed) + { + unsigned shift; + /* index2 for e.g. INS <Vd>.<Ts>[<index1>], <Vn>.<Ts>[<index2>]. */ + assert (info->idx == 1); /* Vn */ + aarch64_insn value = extract_field (FLD_imm4, code, 0); + /* Depend on AARCH64_OPND_Ed to determine the qualifier. */ + info->qualifier = get_expected_qualifier (inst, info->idx); + shift = get_logsz (aarch64_get_qualifier_esize (info->qualifier)); + info->reglane.index = value >> shift; + } + else + { + /* index and type for e.g. DUP <V><d>, <Vn>.<T>[<index>]. + imm5<3:0> <V> + 0000 RESERVED + xxx1 B + xx10 H + x100 S + 1000 D */ + int pos = -1; + aarch64_insn value = extract_field (FLD_imm5, code, 0); + while (++pos <= 3 && (value & 0x1) == 0) + value >>= 1; + if (pos > 3) + return 0; + info->qualifier = get_sreg_qualifier_from_value (pos); + info->reglane.index = (unsigned) (value >> 1); + } + } + else + { + /* Index only for e.g. SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>] + or SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>]. */ + + /* Need information in other operand(s) to help decoding. */ + info->qualifier = get_expected_qualifier (inst, info->idx); + switch (info->qualifier) + { + case AARCH64_OPND_QLF_S_H: + /* h:l:m */ + info->reglane.index = extract_fields (code, 0, 3, FLD_H, FLD_L, + FLD_M); + info->reglane.regno &= 0xf; + break; + case AARCH64_OPND_QLF_S_S: + /* h:l */ + info->reglane.index = extract_fields (code, 0, 2, FLD_H, FLD_L); + break; + case AARCH64_OPND_QLF_S_D: + /* H */ + info->reglane.index = extract_field (FLD_H, code, 0); + break; + default: + return 0; + } + } + + return 1; +} + +int +aarch64_ext_reglist (const aarch64_operand *self, aarch64_opnd_info *info, + const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* R */ + info->reglist.first_regno = extract_field (self->fields[0], code, 0); + /* len */ + info->reglist.num_regs = extract_field (FLD_len, code, 0) + 1; + return 1; +} + +/* Decode Rt and opcode fields of Vt in AdvSIMD load/store instructions. */ +int +aarch64_ext_ldst_reglist (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst) +{ + aarch64_insn value; + /* Number of elements in each structure to be loaded/stored. */ + unsigned expected_num = get_opcode_dependent_value (inst->opcode); + + struct + { + unsigned is_reserved; + unsigned num_regs; + unsigned num_elements; + } data [] = + { {0, 4, 4}, + {1, 4, 4}, + {0, 4, 1}, + {0, 4, 2}, + {0, 3, 3}, + {1, 3, 3}, + {0, 3, 1}, + {0, 1, 1}, + {0, 2, 2}, + {1, 2, 2}, + {0, 2, 1}, + }; + + /* Rt */ + info->reglist.first_regno = extract_field (FLD_Rt, code, 0); + /* opcode */ + value = extract_field (FLD_opcode, code, 0); + if (expected_num != data[value].num_elements || data[value].is_reserved) + return 0; + info->reglist.num_regs = data[value].num_regs; + + return 1; +} + +/* Decode Rt and S fields of Vt in AdvSIMD load single structure to all + lanes instructions. */ +int +aarch64_ext_ldst_reglist_r (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst) +{ + aarch64_insn value; + + /* Rt */ + info->reglist.first_regno = extract_field (FLD_Rt, code, 0); + /* S */ + value = extract_field (FLD_S, code, 0); + + /* Number of registers is equal to the number of elements in + each structure to be loaded/stored. */ + info->reglist.num_regs = get_opcode_dependent_value (inst->opcode); + assert (info->reglist.num_regs >= 1 && info->reglist.num_regs <= 4); + + /* Except when it is LD1R. */ + if (info->reglist.num_regs == 1 && value == (aarch64_insn) 1) + info->reglist.num_regs = 2; + + return 1; +} + +/* Decode Q, opcode<2:1>, S, size and Rt fields of Vt in AdvSIMD + load/store single element instructions. */ +int +aarch64_ext_ldst_elemlist (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + aarch64_field field = {0, 0}; + aarch64_insn QSsize; /* fields Q:S:size. */ + aarch64_insn opcodeh2; /* opcode<2:1> */ + + /* Rt */ + info->reglist.first_regno = extract_field (FLD_Rt, code, 0); + + /* Decode the index, opcode<2:1> and size. */ + gen_sub_field (FLD_asisdlso_opcode, 1, 2, &field); + opcodeh2 = extract_field_2 (&field, code, 0); + QSsize = extract_fields (code, 0, 3, FLD_Q, FLD_S, FLD_vldst_size); + switch (opcodeh2) + { + case 0x0: + info->qualifier = AARCH64_OPND_QLF_S_B; + /* Index encoded in "Q:S:size". */ + info->reglist.index = QSsize; + break; + case 0x1: + info->qualifier = AARCH64_OPND_QLF_S_H; + /* Index encoded in "Q:S:size<1>". */ + info->reglist.index = QSsize >> 1; + break; + case 0x2: + if ((QSsize & 0x1) == 0) + { + info->qualifier = AARCH64_OPND_QLF_S_S; + /* Index encoded in "Q:S". */ + info->reglist.index = QSsize >> 2; + } + else + { + info->qualifier = AARCH64_OPND_QLF_S_D; + /* Index encoded in "Q". */ + info->reglist.index = QSsize >> 3; + if (extract_field (FLD_S, code, 0)) + /* UND */ + return 0; + } + break; + default: + return 0; + } + + info->reglist.has_index = 1; + info->reglist.num_regs = 0; + /* Number of registers is equal to the number of elements in + each structure to be loaded/stored. */ + info->reglist.num_regs = get_opcode_dependent_value (inst->opcode); + assert (info->reglist.num_regs >= 1 && info->reglist.num_regs <= 4); + + return 1; +} + +/* Decode fields immh:immb and/or Q for e.g. + SSHR <Vd>.<T>, <Vn>.<T>, #<shift> + or SSHR <V><d>, <V><n>, #<shift>. */ + +int +aarch64_ext_advsimd_imm_shift (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst) +{ + int pos; + aarch64_insn Q, imm, immh; + enum aarch64_insn_class iclass = inst->opcode->iclass; + + immh = extract_field (FLD_immh, code, 0); + if (immh == 0) + return 0; + imm = extract_fields (code, 0, 2, FLD_immh, FLD_immb); + pos = 4; + /* Get highest set bit in immh. */ + while (--pos >= 0 && (immh & 0x8) == 0) + immh <<= 1; + + assert ((iclass == asimdshf || iclass == asisdshf) + && (info->type == AARCH64_OPND_IMM_VLSR + || info->type == AARCH64_OPND_IMM_VLSL)); + + if (iclass == asimdshf) + { + Q = extract_field (FLD_Q, code, 0); + /* immh Q <T> + 0000 x SEE AdvSIMD modified immediate + 0001 0 8B + 0001 1 16B + 001x 0 4H + 001x 1 8H + 01xx 0 2S + 01xx 1 4S + 1xxx 0 RESERVED + 1xxx 1 2D */ + info->qualifier = + get_vreg_qualifier_from_value ((pos << 1) | (int) Q); + } + else + info->qualifier = get_sreg_qualifier_from_value (pos); + + if (info->type == AARCH64_OPND_IMM_VLSR) + /* immh <shift> + 0000 SEE AdvSIMD modified immediate + 0001 (16-UInt(immh:immb)) + 001x (32-UInt(immh:immb)) + 01xx (64-UInt(immh:immb)) + 1xxx (128-UInt(immh:immb)) */ + info->imm.value = (16 << pos) - imm; + else + /* immh:immb + immh <shift> + 0000 SEE AdvSIMD modified immediate + 0001 (UInt(immh:immb)-8) + 001x (UInt(immh:immb)-16) + 01xx (UInt(immh:immb)-32) + 1xxx (UInt(immh:immb)-64) */ + info->imm.value = imm - (8 << pos); + + return 1; +} + +/* Decode shift immediate for e.g. sshr (imm). */ +int +aarch64_ext_shll_imm (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + int64_t imm; + aarch64_insn val; + val = extract_field (FLD_size, code, 0); + switch (val) + { + case 0: imm = 8; break; + case 1: imm = 16; break; + case 2: imm = 32; break; + default: return 0; + } + info->imm.value = imm; + return 1; +} + +/* Decode imm for e.g. BFM <Wd>, <Wn>, #<immr>, #<imms>. + value in the field(s) will be extracted as unsigned immediate value. */ +int +aarch64_ext_imm (const aarch64_operand *self, aarch64_opnd_info *info, + const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + int64_t imm; + /* Maximum of two fields to extract. */ + assert (self->fields[2] == FLD_NIL); + + if (self->fields[1] == FLD_NIL) + imm = extract_field (self->fields[0], code, 0); + else + /* e.g. TBZ b5:b40. */ + imm = extract_fields (code, 0, 2, self->fields[0], self->fields[1]); + + if (info->type == AARCH64_OPND_FPIMM) + info->imm.is_fp = 1; + + if (operand_need_sign_extension (self)) + imm = sign_extend (imm, get_operand_fields_width (self) - 1); + + if (operand_need_shift_by_two (self)) + imm <<= 2; + + if (info->type == AARCH64_OPND_ADDR_ADRP) + imm <<= 12; + + info->imm.value = imm; + return 1; +} + +/* Decode imm and its shifter for e.g. MOVZ <Wd>, #<imm16>{, LSL #<shift>}. */ +int +aarch64_ext_imm_half (const aarch64_operand *self, aarch64_opnd_info *info, + const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + aarch64_ext_imm (self, info, code, inst); + info->shifter.kind = AARCH64_MOD_LSL; + info->shifter.amount = extract_field (FLD_hw, code, 0) << 4; + return 1; +} + +/* Decode cmode and "a:b:c:d:e:f:g:h" for e.g. + MOVI <Vd>.<T>, #<imm8> {, LSL #<amount>}. */ +int +aarch64_ext_advsimd_imm_modified (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + uint64_t imm; + enum aarch64_opnd_qualifier opnd0_qualifier = inst->operands[0].qualifier; + aarch64_field field = {0, 0}; + + assert (info->idx == 1); + + if (info->type == AARCH64_OPND_SIMD_FPIMM) + info->imm.is_fp = 1; + + /* a:b:c:d:e:f:g:h */ + imm = extract_fields (code, 0, 2, FLD_abc, FLD_defgh); + if (!info->imm.is_fp && aarch64_get_qualifier_esize (opnd0_qualifier) == 8) + { + /* Either MOVI <Dd>, #<imm> + or MOVI <Vd>.2D, #<imm>. + <imm> is a 64-bit immediate + 'aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh', + encoded in "a:b:c:d:e:f:g:h". */ + int i; + unsigned abcdefgh = imm; + for (imm = 0ull, i = 0; i < 8; i++) + if (((abcdefgh >> i) & 0x1) != 0) + imm |= 0xffull << (8 * i); + } + info->imm.value = imm; + + /* cmode */ + info->qualifier = get_expected_qualifier (inst, info->idx); + switch (info->qualifier) + { + case AARCH64_OPND_QLF_NIL: + /* no shift */ + info->shifter.kind = AARCH64_MOD_NONE; + return 1; + case AARCH64_OPND_QLF_LSL: + /* shift zeros */ + info->shifter.kind = AARCH64_MOD_LSL; + switch (aarch64_get_qualifier_esize (opnd0_qualifier)) + { + case 4: gen_sub_field (FLD_cmode, 1, 2, &field); break; /* per word */ + case 2: gen_sub_field (FLD_cmode, 1, 1, &field); break; /* per half */ + default: assert (0); return 0; + } + /* 00: 0; 01: 8; 10:16; 11:24. */ + info->shifter.amount = extract_field_2 (&field, code, 0) << 3; + break; + case AARCH64_OPND_QLF_MSL: + /* shift ones */ + info->shifter.kind = AARCH64_MOD_MSL; + gen_sub_field (FLD_cmode, 0, 1, &field); /* per word */ + info->shifter.amount = extract_field_2 (&field, code, 0) ? 16 : 8; + break; + default: + assert (0); + return 0; + } + + return 1; +} + +/* Decode scale for e.g. SCVTF <Dd>, <Wn>, #<fbits>. */ +int +aarch64_ext_fbits (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + info->imm.value = 64- extract_field (FLD_scale, code, 0); + return 1; +} + +/* Decode arithmetic immediate for e.g. + SUBS <Wd>, <Wn|WSP>, #<imm> {, <shift>}. */ +int +aarch64_ext_aimm (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + aarch64_insn value; + + info->shifter.kind = AARCH64_MOD_LSL; + /* shift */ + value = extract_field (FLD_shift, code, 0); + if (value >= 2) + return 0; + info->shifter.amount = value ? 12 : 0; + /* imm12 (unsigned) */ + info->imm.value = extract_field (FLD_imm12, code, 0); + + return 1; +} + +/* Decode logical immediate for e.g. ORR <Wd|WSP>, <Wn>, #<imm>. */ + +int +aarch64_ext_limm (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + uint64_t imm, mask; + uint32_t sf; + uint32_t N, R, S; + unsigned simd_size; + aarch64_insn value; + + value = extract_fields (code, 0, 3, FLD_N, FLD_immr, FLD_imms); + assert (inst->operands[0].qualifier == AARCH64_OPND_QLF_W + || inst->operands[0].qualifier == AARCH64_OPND_QLF_X); + sf = aarch64_get_qualifier_esize (inst->operands[0].qualifier) != 4; + + /* value is N:immr:imms. */ + S = value & 0x3f; + R = (value >> 6) & 0x3f; + N = (value >> 12) & 0x1; + + if (sf == 0 && N == 1) + return 0; + + /* The immediate value is S+1 bits to 1, left rotated by SIMDsize - R + (in other words, right rotated by R), then replicated. */ + if (N != 0) + { + simd_size = 64; + mask = 0xffffffffffffffffull; + } + else + { + switch (S) + { + case 0x00 ... 0x1f: /* 0xxxxx */ simd_size = 32; break; + case 0x20 ... 0x2f: /* 10xxxx */ simd_size = 16; S &= 0xf; break; + case 0x30 ... 0x37: /* 110xxx */ simd_size = 8; S &= 0x7; break; + case 0x38 ... 0x3b: /* 1110xx */ simd_size = 4; S &= 0x3; break; + case 0x3c ... 0x3d: /* 11110x */ simd_size = 2; S &= 0x1; break; + default: return 0; + } + mask = (1ull << simd_size) - 1; + /* Top bits are IGNORED. */ + R &= simd_size - 1; + } + /* NOTE: if S = simd_size - 1 we get 0xf..f which is rejected. */ + if (S == simd_size - 1) + return 0; + /* S+1 consecutive bits to 1. */ + /* NOTE: S can't be 63 due to detection above. */ + imm = (1ull << (S + 1)) - 1; + /* Rotate to the left by simd_size - R. */ + if (R != 0) + imm = ((imm << (simd_size - R)) & mask) | (imm >> R); + /* Replicate the value according to SIMD size. */ + switch (simd_size) + { + case 2: imm = (imm << 2) | imm; + case 4: imm = (imm << 4) | imm; + case 8: imm = (imm << 8) | imm; + case 16: imm = (imm << 16) | imm; + case 32: imm = (imm << 32) | imm; + case 64: break; + default: assert (0); return 0; + } + + info->imm.value = sf ? imm : imm & 0xffffffff; + + return 1; +} + +/* Decode Ft for e.g. STR <Qt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}] + or LDP <Qt1>, <Qt2>, [<Xn|SP>], #<imm>. */ +int +aarch64_ext_ft (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + const aarch64_insn code, const aarch64_inst *inst) +{ + aarch64_insn value; + + /* Rt */ + info->reg.regno = extract_field (FLD_Rt, code, 0); + + /* size */ + value = extract_field (FLD_ldst_size, code, 0); + if (inst->opcode->iclass == ldstpair_indexed + || inst->opcode->iclass == ldstnapair_offs + || inst->opcode->iclass == ldstpair_off + || inst->opcode->iclass == loadlit) + { + enum aarch64_opnd_qualifier qualifier; + switch (value) + { + case 0: qualifier = AARCH64_OPND_QLF_S_S; break; + case 1: qualifier = AARCH64_OPND_QLF_S_D; break; + case 2: qualifier = AARCH64_OPND_QLF_S_Q; break; + default: return 0; + } + info->qualifier = qualifier; + } + else + { + /* opc1:size */ + value = extract_fields (code, 0, 2, FLD_opc1, FLD_ldst_size); + if (value > 0x4) + return 0; + info->qualifier = get_sreg_qualifier_from_value (value); + } + + return 1; +} + +/* Decode the address operand for e.g. STXRB <Ws>, <Wt>, [<Xn|SP>{,#0}]. */ +int +aarch64_ext_addr_simple (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* Rn */ + info->addr.base_regno = extract_field (FLD_Rn, code, 0); + return 1; +} + +/* Decode the address operand for e.g. + STR <Qt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */ +int +aarch64_ext_addr_regoff (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + aarch64_insn code, const aarch64_inst *inst) +{ + aarch64_insn S, value; + + /* Rn */ + info->addr.base_regno = extract_field (FLD_Rn, code, 0); + /* Rm */ + info->addr.offset.regno = extract_field (FLD_Rm, code, 0); + /* option */ + value = extract_field (FLD_option, code, 0); + info->shifter.kind = + aarch64_get_operand_modifier_from_value (value, TRUE /* extend_p */); + /* Fix-up the shifter kind; although the table-driven approach is + efficient, it is slightly inflexible, thus needing this fix-up. */ + if (info->shifter.kind == AARCH64_MOD_UXTX) + info->shifter.kind = AARCH64_MOD_LSL; + /* S */ + S = extract_field (FLD_S, code, 0); + if (S == 0) + { + info->shifter.amount = 0; + info->shifter.amount_present = 0; + } + else + { + int size; + /* Need information in other operand(s) to help achieve the decoding + from 'S' field. */ + info->qualifier = get_expected_qualifier (inst, info->idx); + /* Get the size of the data element that is accessed, which may be + different from that of the source register size, e.g. in strb/ldrb. */ + size = aarch64_get_qualifier_esize (info->qualifier); + info->shifter.amount = get_logsz (size); + info->shifter.amount_present = 1; + } + + return 1; +} + +/* Decode the address operand for e.g. LDRSW <Xt>, [<Xn|SP>], #<simm>. */ +int +aarch64_ext_addr_simm (const aarch64_operand *self, aarch64_opnd_info *info, + aarch64_insn code, const aarch64_inst *inst) +{ + aarch64_insn imm; + info->qualifier = get_expected_qualifier (inst, info->idx); + + /* Rn */ + info->addr.base_regno = extract_field (FLD_Rn, code, 0); + /* simm (imm9 or imm7) */ + imm = extract_field (self->fields[0], code, 0); + info->addr.offset.imm = sign_extend (imm, fields[self->fields[0]].width - 1); + if (self->fields[0] == FLD_imm7) + /* scaled immediate in ld/st pair instructions. */ + info->addr.offset.imm *= aarch64_get_qualifier_esize (info->qualifier); + /* qualifier */ + if (inst->opcode->iclass == ldst_unscaled + || inst->opcode->iclass == ldstnapair_offs + || inst->opcode->iclass == ldstpair_off + || inst->opcode->iclass == ldst_unpriv) + info->addr.writeback = 0; + else + { + /* pre/post- index */ + info->addr.writeback = 1; + if (extract_field (self->fields[1], code, 0) == 1) + info->addr.preind = 1; + else + info->addr.postind = 1; + } + + return 1; +} + +/* Decode the address operand for e.g. LDRSW <Xt>, [<Xn|SP>{, #<simm>}]. */ +int +aarch64_ext_addr_uimm12 (const aarch64_operand *self, aarch64_opnd_info *info, + aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + int shift; + info->qualifier = get_expected_qualifier (inst, info->idx); + shift = get_logsz (aarch64_get_qualifier_esize (info->qualifier)); + /* Rn */ + info->addr.base_regno = extract_field (self->fields[0], code, 0); + /* uimm12 */ + info->addr.offset.imm = extract_field (self->fields[1], code, 0) << shift; + return 1; +} + +/* Decode the address operand for e.g. + LD1 {<Vt>.<T>, <Vt2>.<T>, <Vt3>.<T>}, [<Xn|SP>], <Xm|#<amount>>. */ +int +aarch64_ext_simd_addr_post (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + aarch64_insn code, const aarch64_inst *inst) +{ + /* The opcode dependent area stores the number of elements in + each structure to be loaded/stored. */ + int is_ld1r = get_opcode_dependent_value (inst->opcode) == 1; + + /* Rn */ + info->addr.base_regno = extract_field (FLD_Rn, code, 0); + /* Rm | #<amount> */ + info->addr.offset.regno = extract_field (FLD_Rm, code, 0); + if (info->addr.offset.regno == 31) + { + if (inst->opcode->operands[0] == AARCH64_OPND_LVt_AL) + /* Special handling of loading single structure to all lane. */ + info->addr.offset.imm = (is_ld1r ? 1 + : inst->operands[0].reglist.num_regs) + * aarch64_get_qualifier_esize (inst->operands[0].qualifier); + else + info->addr.offset.imm = inst->operands[0].reglist.num_regs + * aarch64_get_qualifier_esize (inst->operands[0].qualifier) + * aarch64_get_qualifier_nelem (inst->operands[0].qualifier); + } + else + info->addr.offset.is_reg = 1; + info->addr.writeback = 1; + + return 1; +} + +/* Decode the condition operand for e.g. CSEL <Xd>, <Xn>, <Xm>, <cond>. */ +int +aarch64_ext_cond (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + aarch64_insn code, const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + aarch64_insn value; + /* cond */ + value = extract_field (FLD_cond, code, 0); + info->cond = get_cond_from_value (value); + return 1; +} + +/* Decode the system register operand for e.g. MRS <Xt>, <systemreg>. */ +int +aarch64_ext_sysreg (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* op0:op1:CRn:CRm:op2 */ + info->sysreg = extract_fields (code, 0, 5, FLD_op0, FLD_op1, FLD_CRn, + FLD_CRm, FLD_op2); + return 1; +} + +/* Decode the PSTATE field operand for e.g. MSR <pstatefield>, #<imm>. */ +int +aarch64_ext_pstatefield (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + int i; + /* op1:op2 */ + info->pstatefield = extract_fields (code, 0, 2, FLD_op1, FLD_op2); + for (i = 0; aarch64_pstatefields[i].name != NULL; ++i) + if (aarch64_pstatefields[i].value == (aarch64_insn)info->pstatefield) + return 1; + /* Reserved value in <pstatefield>. */ + return 0; +} + +/* Decode the system instruction op operand for e.g. AT <at_op>, <Xt>. */ +int +aarch64_ext_sysins_op (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + int i; + aarch64_insn value; + const aarch64_sys_ins_reg *sysins_ops; + /* op0:op1:CRn:CRm:op2 */ + value = extract_fields (code, 0, 5, + FLD_op0, FLD_op1, FLD_CRn, + FLD_CRm, FLD_op2); + + switch (info->type) + { + case AARCH64_OPND_SYSREG_AT: sysins_ops = aarch64_sys_regs_at; break; + case AARCH64_OPND_SYSREG_DC: sysins_ops = aarch64_sys_regs_dc; break; + case AARCH64_OPND_SYSREG_IC: sysins_ops = aarch64_sys_regs_ic; break; + case AARCH64_OPND_SYSREG_TLBI: sysins_ops = aarch64_sys_regs_tlbi; break; + default: assert (0); return 0; + } + + for (i = 0; sysins_ops[i].template != NULL; ++i) + if (sysins_ops[i].value == value) + { + info->sysins_op = sysins_ops + i; + DEBUG_TRACE ("%s found value: %x, has_xt: %d, i: %d.", + info->sysins_op->template, + (unsigned)info->sysins_op->value, + info->sysins_op->has_xt, i); + return 1; + } + + return 0; +} + +/* Decode the memory barrier option operand for e.g. DMB <option>|#<imm>. */ + +int +aarch64_ext_barrier (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* CRm */ + info->barrier = aarch64_barrier_options + extract_field (FLD_CRm, code, 0); + return 1; +} + +/* Decode the prefetch operation option operand for e.g. + PRFM <prfop>, [<Xn|SP>{, #<pimm>}]. */ + +int +aarch64_ext_prfop (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + aarch64_insn code, const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + /* prfop in Rt */ + info->prfop = aarch64_prfops + extract_field (FLD_Rt, code, 0); + return 1; +} + +/* Decode the extended register operand for e.g. + STR <Qt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */ +int +aarch64_ext_reg_extended (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + aarch64_insn value; + + /* Rm */ + info->reg.regno = extract_field (FLD_Rm, code, 0); + /* option */ + value = extract_field (FLD_option, code, 0); + info->shifter.kind = + aarch64_get_operand_modifier_from_value (value, TRUE /* extend_p */); + /* imm3 */ + info->shifter.amount = extract_field (FLD_imm3, code, 0); + + /* This makes the constraint checking happy. */ + info->shifter.operator_present = 1; + + /* Assume inst->operands[0].qualifier has been resolved. */ + assert (inst->operands[0].qualifier != AARCH64_OPND_QLF_NIL); + info->qualifier = AARCH64_OPND_QLF_W; + if (inst->operands[0].qualifier == AARCH64_OPND_QLF_X + && (info->shifter.kind == AARCH64_MOD_UXTX + || info->shifter.kind == AARCH64_MOD_SXTX)) + info->qualifier = AARCH64_OPND_QLF_X; + + return 1; +} + +/* Decode the shifted register operand for e.g. + SUBS <Xd>, <Xn>, <Xm> {, <shift> #<amount>}. */ +int +aarch64_ext_reg_shifted (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED) +{ + aarch64_insn value; + + /* Rm */ + info->reg.regno = extract_field (FLD_Rm, code, 0); + /* shift */ + value = extract_field (FLD_shift, code, 0); + info->shifter.kind = + aarch64_get_operand_modifier_from_value (value, FALSE /* extend_p */); + if (info->shifter.kind == AARCH64_MOD_ROR + && inst->opcode->iclass != log_shift) + /* ROR is not available for the shifted register operand in arithmetic + instructions. */ + return 0; + /* imm6 */ + info->shifter.amount = extract_field (FLD_imm6, code, 0); + + /* This makes the constraint checking happy. */ + info->shifter.operator_present = 1; + + return 1; +} + +/* Bitfields that are commonly used to encode certain operands' information + may be partially used as part of the base opcode in some instructions. + For example, the bit 1 of the field 'size' in + FCVTXN <Vb><d>, <Va><n> + is actually part of the base opcode, while only size<0> is available + for encoding the register type. Another example is the AdvSIMD + instruction ORR (register), in which the field 'size' is also used for + the base opcode, leaving only the field 'Q' available to encode the + vector register arrangement specifier '8B' or '16B'. + + This function tries to deduce the qualifier from the value of partially + constrained field(s). Given the VALUE of such a field or fields, the + qualifiers CANDIDATES and the MASK (indicating which bits are valid for + operand encoding), the function returns the matching qualifier or + AARCH64_OPND_QLF_NIL if nothing matches. + + N.B. CANDIDATES is a group of possible qualifiers that are valid for + one operand; it has a maximum of AARCH64_MAX_QLF_SEQ_NUM qualifiers and + may end with AARCH64_OPND_QLF_NIL. */ + +static enum aarch64_opnd_qualifier +get_qualifier_from_partial_encoding (aarch64_insn value, + const enum aarch64_opnd_qualifier* \ + candidates, + aarch64_insn mask) +{ + int i; + DEBUG_TRACE ("enter with value: %d, mask: %d", (int)value, (int)mask); + for (i = 0; i < AARCH64_MAX_QLF_SEQ_NUM; ++i) + { + aarch64_insn standard_value; + if (candidates[i] == AARCH64_OPND_QLF_NIL) + break; + standard_value = aarch64_get_qualifier_standard_value (candidates[i]); + if ((standard_value & mask) == (value & mask)) + return candidates[i]; + } + return AARCH64_OPND_QLF_NIL; +} + +/* Given a list of qualifier sequences, return all possible valid qualifiers + for operand IDX in QUALIFIERS. + Assume QUALIFIERS is an array whose length is large enough. */ + +static void +get_operand_possible_qualifiers (int idx, + const aarch64_opnd_qualifier_seq_t *list, + enum aarch64_opnd_qualifier *qualifiers) +{ + int i; + for (i = 0; i < AARCH64_MAX_QLF_SEQ_NUM; ++i) + if ((qualifiers[i] = list[i][idx]) == AARCH64_OPND_QLF_NIL) + break; +} + +/* Decode the size Q field for e.g. SHADD. + We tag one operand with the qualifer according to the code; + whether the qualifier is valid for this opcode or not, it is the + duty of the semantic checking. */ + +static int +decode_sizeq (aarch64_inst *inst) +{ + int idx; + enum aarch64_opnd_qualifier qualifier; + aarch64_insn code; + aarch64_insn value, mask; + enum aarch64_field_kind fld_sz; + enum aarch64_opnd_qualifier candidates[AARCH64_MAX_QLF_SEQ_NUM]; + + if (inst->opcode->iclass == asisdlse + || inst->opcode->iclass == asisdlsep + || inst->opcode->iclass == asisdlso + || inst->opcode->iclass == asisdlsop) + fld_sz = FLD_vldst_size; + else + fld_sz = FLD_size; + + code = inst->value; + value = extract_fields (code, inst->opcode->mask, 2, fld_sz, FLD_Q); + /* Obtain the info that which bits of fields Q and size are actually + available for operand encoding. Opcodes like FMAXNM and FMLA have + size[1] unavailable. */ + mask = extract_fields (~inst->opcode->mask, 0, 2, fld_sz, FLD_Q); + + /* The index of the operand we are going to tag a qualifier and the qualifer + itself are reasoned from the value of the size and Q fields and the + possible valid qualifier lists. */ + idx = aarch64_select_operand_for_sizeq_field_coding (inst->opcode); + DEBUG_TRACE ("key idx: %d", idx); + + /* For most related instruciton, size:Q are fully available for operand + encoding. */ + if (mask == 0x7) + { + inst->operands[idx].qualifier = get_vreg_qualifier_from_value (value); + return 1; + } + + get_operand_possible_qualifiers (idx, inst->opcode->qualifiers_list, + candidates); +#ifdef DEBUG_AARCH64 + if (debug_dump) + { + int i; + for (i = 0; candidates[i] != AARCH64_OPND_QLF_NIL + && i < AARCH64_MAX_QLF_SEQ_NUM; ++i) + DEBUG_TRACE ("qualifier %d: %s", i, + aarch64_get_qualifier_name(candidates[i])); + DEBUG_TRACE ("%d, %d", (int)value, (int)mask); + } +#endif /* DEBUG_AARCH64 */ + + qualifier = get_qualifier_from_partial_encoding (value, candidates, mask); + + if (qualifier == AARCH64_OPND_QLF_NIL) + return 0; + + inst->operands[idx].qualifier = qualifier; + return 1; +} + +/* Decode size[0]:Q, i.e. bit 22 and bit 30, for + e.g. FCVTN<Q> <Vd>.<Tb>, <Vn>.<Ta>. */ + +static int +decode_asimd_fcvt (aarch64_inst *inst) +{ + aarch64_field field = {0, 0}; + aarch64_insn value; + enum aarch64_opnd_qualifier qualifier; + + gen_sub_field (FLD_size, 0, 1, &field); + value = extract_field_2 (&field, inst->value, 0); + qualifier = value == 0 ? AARCH64_OPND_QLF_V_4S + : AARCH64_OPND_QLF_V_2D; + switch (inst->opcode->op) + { + case OP_FCVTN: + case OP_FCVTN2: + /* FCVTN<Q> <Vd>.<Tb>, <Vn>.<Ta>. */ + inst->operands[1].qualifier = qualifier; + break; + case OP_FCVTL: + case OP_FCVTL2: + /* FCVTL<Q> <Vd>.<Ta>, <Vn>.<Tb>. */ + inst->operands[0].qualifier = qualifier; + break; + default: + assert (0); + return 0; + } + + return 1; +} + +/* Decode size[0], i.e. bit 22, for + e.g. FCVTXN <Vb><d>, <Va><n>. */ + +static int +decode_asisd_fcvtxn (aarch64_inst *inst) +{ + aarch64_field field = {0, 0}; + gen_sub_field (FLD_size, 0, 1, &field); + if (!extract_field_2 (&field, inst->value, 0)) + return 0; + inst->operands[0].qualifier = AARCH64_OPND_QLF_S_S; + return 1; +} + +/* Decode the 'opc' field for e.g. FCVT <Dd>, <Sn>. */ +static int +decode_fcvt (aarch64_inst *inst) +{ + enum aarch64_opnd_qualifier qualifier; + aarch64_insn value; + const aarch64_field field = {15, 2}; + + /* opc dstsize */ + value = extract_field_2 (&field, inst->value, 0); + switch (value) + { + case 0: qualifier = AARCH64_OPND_QLF_S_S; break; + case 1: qualifier = AARCH64_OPND_QLF_S_D; break; + case 3: qualifier = AARCH64_OPND_QLF_S_H; break; + default: return 0; + } + inst->operands[0].qualifier = qualifier; + + return 1; +} + +/* Do miscellaneous decodings that are not common enough to be driven by + flags. */ + +static int +do_misc_decoding (aarch64_inst *inst) +{ + switch (inst->opcode->op) + { + case OP_FCVT: + return decode_fcvt (inst); + case OP_FCVTN: + case OP_FCVTN2: + case OP_FCVTL: + case OP_FCVTL2: + return decode_asimd_fcvt (inst); + case OP_FCVTXN_S: + return decode_asisd_fcvtxn (inst); + default: + return 0; + } +} + +/* Opcodes that have fields shared by multiple operands are usually flagged + with flags. In this function, we detect such flags, decode the related + field(s) and store the information in one of the related operands. The + 'one' operand is not any operand but one of the operands that can + accommadate all the information that has been decoded. */ + +static int +do_special_decoding (aarch64_inst *inst) +{ + int idx; + aarch64_insn value; + /* Condition for truly conditional executed instructions, e.g. b.cond. */ + if (inst->opcode->flags & F_COND) + { + value = extract_field (FLD_cond2, inst->value, 0); + inst->cond = get_cond_from_value (value); + } + /* 'sf' field. */ + if (inst->opcode->flags & F_SF) + { + idx = select_operand_for_sf_field_coding (inst->opcode); + value = extract_field (FLD_sf, inst->value, 0); + inst->operands[idx].qualifier = get_greg_qualifier_from_value (value); + if ((inst->opcode->flags & F_N) + && extract_field (FLD_N, inst->value, 0) != value) + return 0; + } + /* size:Q fields. */ + if (inst->opcode->flags & F_SIZEQ) + return decode_sizeq (inst); + + if (inst->opcode->flags & F_FPTYPE) + { + idx = select_operand_for_fptype_field_coding (inst->opcode); + value = extract_field (FLD_type, inst->value, 0); + switch (value) + { + case 0: inst->operands[idx].qualifier = AARCH64_OPND_QLF_S_S; break; + case 1: inst->operands[idx].qualifier = AARCH64_OPND_QLF_S_D; break; + case 3: inst->operands[idx].qualifier = AARCH64_OPND_QLF_S_H; break; + default: return 0; + } + } + + if (inst->opcode->flags & F_SSIZE) + { + /* N.B. some opcodes like FCMGT <V><d>, <V><n>, #0 have the size[1] as part + of the base opcode. */ + aarch64_insn mask; + enum aarch64_opnd_qualifier candidates[AARCH64_MAX_QLF_SEQ_NUM]; + idx = select_operand_for_scalar_size_field_coding (inst->opcode); + value = extract_field (FLD_size, inst->value, inst->opcode->mask); + mask = extract_field (FLD_size, ~inst->opcode->mask, 0); + /* For most related instruciton, the 'size' field is fully available for + operand encoding. */ + if (mask == 0x3) + inst->operands[idx].qualifier = get_sreg_qualifier_from_value (value); + else + { + get_operand_possible_qualifiers (idx, inst->opcode->qualifiers_list, + candidates); + inst->operands[idx].qualifier + = get_qualifier_from_partial_encoding (value, candidates, mask); + } + } + + if (inst->opcode->flags & F_T) + { + /* Num of consecutive '0's on the right side of imm5<3:0>. */ + int num = 0; + unsigned val, Q; + assert (aarch64_get_operand_class (inst->opcode->operands[0]) + == AARCH64_OPND_CLASS_SIMD_REG); + /* imm5<3:0> q <t> + 0000 x reserved + xxx1 0 8b + xxx1 1 16b + xx10 0 4h + xx10 1 8h + x100 0 2s + x100 1 4s + 1000 0 reserved + 1000 1 2d */ + val = extract_field (FLD_imm5, inst->value, 0); + while ((val & 0x1) == 0 && ++num <= 3) + val >>= 1; + if (num > 3) + return 0; + Q = (unsigned) extract_field (FLD_Q, inst->value, inst->opcode->mask); + inst->operands[0].qualifier = + get_vreg_qualifier_from_value ((num << 1) | Q); + } + + if (inst->opcode->flags & F_GPRSIZE_IN_Q) + { + /* Use Rt to encode in the case of e.g. + STXP <Ws>, <Xt1>, <Xt2>, [<Xn|SP>{,#0}]. */ + idx = aarch64_operand_index (inst->opcode->operands, AARCH64_OPND_Rt); + if (idx == -1) + { + /* Otherwise use the result operand, which has to be a integer + register. */ + assert (aarch64_get_operand_class (inst->opcode->operands[0]) + == AARCH64_OPND_CLASS_INT_REG); + idx = 0; + } + assert (idx == 0 || idx == 1); + value = extract_field (FLD_Q, inst->value, 0); + inst->operands[idx].qualifier = get_greg_qualifier_from_value (value); + } + + if (inst->opcode->flags & F_LDS_SIZE) + { + aarch64_field field = {0, 0}; + assert (aarch64_get_operand_class (inst->opcode->operands[0]) + == AARCH64_OPND_CLASS_INT_REG); + gen_sub_field (FLD_opc, 0, 1, &field); + value = extract_field_2 (&field, inst->value, 0); + inst->operands[0].qualifier + = value ? AARCH64_OPND_QLF_W : AARCH64_OPND_QLF_X; + } + + /* Miscellaneous decoding; done as the last step. */ + if (inst->opcode->flags & F_MISC) + return do_misc_decoding (inst); + + return 1; +} + +/* Converters converting a real opcode instruction to its alias form. */ + +/* ROR <Wd>, <Ws>, #<shift> + is equivalent to: + EXTR <Wd>, <Ws>, <Ws>, #<shift>. */ +static int +convert_extr_to_ror (aarch64_inst *inst) +{ + if (inst->operands[1].reg.regno == inst->operands[2].reg.regno) + { + copy_operand_info (inst, 2, 3); + inst->operands[3].type = AARCH64_OPND_NIL; + return 1; + } + return 0; +} + +/* Convert + UBFM <Xd>, <Xn>, #<shift>, #63. + to + LSR <Xd>, <Xn>, #<shift>. */ +static int +convert_bfm_to_sr (aarch64_inst *inst) +{ + int64_t imms, val; + + imms = inst->operands[3].imm.value; + val = inst->operands[2].qualifier == AARCH64_OPND_QLF_imm_0_31 ? 31 : 63; + if (imms == val) + { + inst->operands[3].type = AARCH64_OPND_NIL; + return 1; + } + + return 0; +} + +/* Convert MOV to ORR. */ +static int +convert_orr_to_mov (aarch64_inst *inst) +{ + /* MOV <Vd>.<T>, <Vn>.<T> + is equivalent to: + ORR <Vd>.<T>, <Vn>.<T>, <Vn>.<T>. */ + if (inst->operands[1].reg.regno == inst->operands[2].reg.regno) + { + inst->operands[2].type = AARCH64_OPND_NIL; + return 1; + } + return 0; +} + +/* When <imms> >= <immr>, the instruction written: + SBFX <Xd>, <Xn>, #<lsb>, #<width> + is equivalent to: + SBFM <Xd>, <Xn>, #<lsb>, #(<lsb>+<width>-1). */ + +static int +convert_bfm_to_bfx (aarch64_inst *inst) +{ + int64_t immr, imms; + + immr = inst->operands[2].imm.value; + imms = inst->operands[3].imm.value; + if (imms >= immr) + { + int64_t lsb = immr; + inst->operands[2].imm.value = lsb; + inst->operands[3].imm.value = imms + 1 - lsb; + /* The two opcodes have different qualifiers for + the immediate operands; reset to help the checking. */ + reset_operand_qualifier (inst, 2); + reset_operand_qualifier (inst, 3); + return 1; + } + + return 0; +} + +/* When <imms> < <immr>, the instruction written: + SBFIZ <Xd>, <Xn>, #<lsb>, #<width> + is equivalent to: + SBFM <Xd>, <Xn>, #((64-<lsb>)&0x3f), #(<width>-1). */ + +static int +convert_bfm_to_bfi (aarch64_inst *inst) +{ + int64_t immr, imms, val; + + immr = inst->operands[2].imm.value; + imms = inst->operands[3].imm.value; + val = inst->operands[2].qualifier == AARCH64_OPND_QLF_imm_0_31 ? 32 : 64; + if (imms < immr) + { + inst->operands[2].imm.value = (val - immr) & (val - 1); + inst->operands[3].imm.value = imms + 1; + /* The two opcodes have different qualifiers for + the immediate operands; reset to help the checking. */ + reset_operand_qualifier (inst, 2); + reset_operand_qualifier (inst, 3); + return 1; + } + + return 0; +} + +/* The instruction written: + LSL <Xd>, <Xn>, #<shift> + is equivalent to: + UBFM <Xd>, <Xn>, #((64-<shift>)&0x3f), #(63-<shift>). */ + +static int +convert_ubfm_to_lsl (aarch64_inst *inst) +{ + int64_t immr = inst->operands[2].imm.value; + int64_t imms = inst->operands[3].imm.value; + int64_t val + = inst->operands[2].qualifier == AARCH64_OPND_QLF_imm_0_31 ? 31 : 63; + + if ((immr == 0 && imms == val) || immr == imms + 1) + { + inst->operands[3].type = AARCH64_OPND_NIL; + inst->operands[2].imm.value = val - imms; + return 1; + } + + return 0; +} + +/* CINC <Wd>, <Wn>, <cond> + is equivalent to: + CSINC <Wd>, <Wn>, <Wn>, invert(<cond>). */ + +static int +convert_from_csel (aarch64_inst *inst) +{ + if (inst->operands[1].reg.regno == inst->operands[2].reg.regno) + { + copy_operand_info (inst, 2, 3); + inst->operands[2].cond = get_inverted_cond (inst->operands[3].cond); + inst->operands[3].type = AARCH64_OPND_NIL; + return 1; + } + return 0; +} + +/* CSET <Wd>, <cond> + is equivalent to: + CSINC <Wd>, WZR, WZR, invert(<cond>). */ + +static int +convert_csinc_to_cset (aarch64_inst *inst) +{ + if (inst->operands[1].reg.regno == 0x1f + && inst->operands[2].reg.regno == 0x1f) + { + copy_operand_info (inst, 1, 3); + inst->operands[1].cond = get_inverted_cond (inst->operands[3].cond); + inst->operands[3].type = AARCH64_OPND_NIL; + inst->operands[2].type = AARCH64_OPND_NIL; + return 1; + } + return 0; +} + +/* MOV <Wd>, #<imm> + is equivalent to: + MOVZ <Wd>, #<imm16>, LSL #<shift>. + + A disassembler may output ORR, MOVZ and MOVN as a MOV mnemonic, except when + ORR has an immediate that could be generated by a MOVZ or MOVN instruction, + or where a MOVN has an immediate that could be encoded by MOVZ, or where + MOVZ/MOVN #0 have a shift amount other than LSL #0, in which case the + machine-instruction mnemonic must be used. */ + +static int +convert_movewide_to_mov (aarch64_inst *inst) +{ + uint64_t value = inst->operands[1].imm.value; + /* MOVZ/MOVN #0 have a shift amount other than LSL #0. */ + if (value == 0 && inst->operands[1].shifter.amount != 0) + return 0; + inst->operands[1].type = AARCH64_OPND_IMM_MOV; + inst->operands[1].shifter.kind = AARCH64_MOD_NONE; + value <<= inst->operands[1].shifter.amount; + /* As an alias convertor, it has to be clear that the INST->OPCODE + is the opcode of the real instruction. */ + if (inst->opcode->op == OP_MOVN) + { + int is32 = inst->operands[0].qualifier == AARCH64_OPND_QLF_W; + value = ~value; + /* A MOVN has an immediate that could be encoded by MOVZ. */ + if (aarch64_wide_constant_p (value, is32, NULL) == TRUE) + return 0; + } + inst->operands[1].imm.value = value; + inst->operands[1].shifter.amount = 0; + return 1; +} + +/* MOV <Wd>, #<imm> + is equivalent to: + ORR <Wd>, WZR, #<imm>. + + A disassembler may output ORR, MOVZ and MOVN as a MOV mnemonic, except when + ORR has an immediate that could be generated by a MOVZ or MOVN instruction, + or where a MOVN has an immediate that could be encoded by MOVZ, or where + MOVZ/MOVN #0 have a shift amount other than LSL #0, in which case the + machine-instruction mnemonic must be used. */ + +static int +convert_movebitmask_to_mov (aarch64_inst *inst) +{ + int is32; + uint64_t value; + + /* Should have been assured by the base opcode value. */ + assert (inst->operands[1].reg.regno == 0x1f); + copy_operand_info (inst, 1, 2); + is32 = inst->operands[0].qualifier == AARCH64_OPND_QLF_W; + inst->operands[1].type = AARCH64_OPND_IMM_MOV; + value = inst->operands[1].imm.value; + /* ORR has an immediate that could be generated by a MOVZ or MOVN + instruction. */ + if (inst->operands[0].reg.regno != 0x1f + && (aarch64_wide_constant_p (value, is32, NULL) == TRUE + || aarch64_wide_constant_p (~value, is32, NULL) == TRUE)) + return 0; + + inst->operands[2].type = AARCH64_OPND_NIL; + return 1; +} + +/* Some alias opcodes are disassembled by being converted from their real-form. + N.B. INST->OPCODE is the real opcode rather than the alias. */ + +static int +convert_to_alias (aarch64_inst *inst, const aarch64_opcode *alias) +{ + switch (alias->op) + { + case OP_ASR_IMM: + case OP_LSR_IMM: + return convert_bfm_to_sr (inst); + case OP_LSL_IMM: + return convert_ubfm_to_lsl (inst); + case OP_CINC: + case OP_CINV: + case OP_CNEG: + return convert_from_csel (inst); + case OP_CSET: + case OP_CSETM: + return convert_csinc_to_cset (inst); + case OP_UBFX: + case OP_BFXIL: + case OP_SBFX: + return convert_bfm_to_bfx (inst); + case OP_SBFIZ: + case OP_BFI: + case OP_UBFIZ: + return convert_bfm_to_bfi (inst); + case OP_MOV_V: + return convert_orr_to_mov (inst); + case OP_MOV_IMM_WIDE: + case OP_MOV_IMM_WIDEN: + return convert_movewide_to_mov (inst); + case OP_MOV_IMM_LOG: + return convert_movebitmask_to_mov (inst); + case OP_ROR_IMM: + return convert_extr_to_ror (inst); + default: + return 0; + } +} + +static int aarch64_opcode_decode (const aarch64_opcode *, const aarch64_insn, + aarch64_inst *, int); + +/* Given the instruction information in *INST, check if the instruction has + any alias form that can be used to represent *INST. If the answer is yes, + update *INST to be in the form of the determined alias. */ + +/* In the opcode description table, the following flags are used in opcode + entries to help establish the relations between the real and alias opcodes: + + F_ALIAS: opcode is an alias + F_HAS_ALIAS: opcode has alias(es) + F_P1 + F_P2 + F_P3: Disassembly preference priority 1-3 (the larger the + higher). If nothing is specified, it is the priority + 0 by default, i.e. the lowest priority. + + Although the relation between the machine and the alias instructions are not + explicitly described, it can be easily determined from the base opcode + values, masks and the flags F_ALIAS and F_HAS_ALIAS in their opcode + description entries: + + The mask of an alias opcode must be equal to or a super-set (i.e. more + constrained) of that of the aliased opcode; so is the base opcode value. + + if (opcode_has_alias (real) && alias_opcode_p (opcode) + && (opcode->mask & real->mask) == real->mask + && (real->mask & opcode->opcode) == (real->mask & real->opcode)) + then OPCODE is an alias of, and only of, the REAL instruction + + The alias relationship is forced flat-structured to keep related algorithm + simple; an opcode entry cannot be flagged with both F_ALIAS and F_HAS_ALIAS. + + During the disassembling, the decoding decision tree (in + opcodes/aarch64-dis-2.c) always returns an machine instruction opcode entry; + if the decoding of such a machine instruction succeeds (and -Mno-aliases is + not specified), the disassembler will check whether there is any alias + instruction exists for this real instruction. If there is, the disassembler + will try to disassemble the 32-bit binary again using the alias's rule, or + try to convert the IR to the form of the alias. In the case of the multiple + aliases, the aliases are tried one by one from the highest priority + (currently the flag F_P3) to the lowest priority (no priority flag), and the + first succeeds first adopted. + + You may ask why there is a need for the conversion of IR from one form to + another in handling certain aliases. This is because on one hand it avoids + adding more operand code to handle unusual encoding/decoding; on other + hand, during the disassembling, the conversion is an effective approach to + check the condition of an alias (as an alias may be adopted only if certain + conditions are met). + + In order to speed up the alias opcode lookup, aarch64-gen has preprocessed + aarch64_opcode_table and generated aarch64_find_alias_opcode and + aarch64_find_next_alias_opcode (in opcodes/aarch64-dis-2.c) to help. */ + +static void +determine_disassembling_preference (struct aarch64_inst *inst) +{ + const aarch64_opcode *opcode; + const aarch64_opcode *alias; + + opcode = inst->opcode; + + /* This opcode does not have an alias, so use itself. */ + if (opcode_has_alias (opcode) == FALSE) + return; + + alias = aarch64_find_alias_opcode (opcode); + assert (alias); + +#ifdef DEBUG_AARCH64 + if (debug_dump) + { + const aarch64_opcode *tmp = alias; + printf ("#### LIST orderd: "); + while (tmp) + { + printf ("%s, ", tmp->name); + tmp = aarch64_find_next_alias_opcode (tmp); + } + printf ("\n"); + } +#endif /* DEBUG_AARCH64 */ + + for (; alias; alias = aarch64_find_next_alias_opcode (alias)) + { + DEBUG_TRACE ("try %s", alias->name); + assert (alias_opcode_p (alias)); + + /* An alias can be a pseudo opcode which will never be used in the + disassembly, e.g. BIC logical immediate is such a pseudo opcode + aliasing AND. */ + if (pseudo_opcode_p (alias)) + { + DEBUG_TRACE ("skip pseudo %s", alias->name); + continue; + } + + if ((inst->value & alias->mask) != alias->opcode) + { + DEBUG_TRACE ("skip %s as base opcode not match", alias->name); + continue; + } + /* No need to do any complicated transformation on operands, if the alias + opcode does not have any operand. */ + if (aarch64_num_of_operands (alias) == 0 && alias->opcode == inst->value) + { + DEBUG_TRACE ("succeed with 0-operand opcode %s", alias->name); + aarch64_replace_opcode (inst, alias); + return; + } + if (alias->flags & F_CONV) + { + aarch64_inst copy; + memcpy (©, inst, sizeof (aarch64_inst)); + /* ALIAS is the preference as long as the instruction can be + successfully converted to the form of ALIAS. */ + if (convert_to_alias (©, alias) == 1) + { + aarch64_replace_opcode (©, alias); + assert (aarch64_match_operands_constraint (©, NULL)); + DEBUG_TRACE ("succeed with %s via conversion", alias->name); + memcpy (inst, ©, sizeof (aarch64_inst)); + return; + } + } + else + { + /* Directly decode the alias opcode. */ + aarch64_inst temp; + memset (&temp, '\0', sizeof (aarch64_inst)); + if (aarch64_opcode_decode (alias, inst->value, &temp, 1) == 1) + { + DEBUG_TRACE ("succeed with %s via direct decoding", alias->name); + memcpy (inst, &temp, sizeof (aarch64_inst)); + return; + } + } + } +} + +/* Decode the CODE according to OPCODE; fill INST. Return 0 if the decoding + fails, which meanes that CODE is not an instruction of OPCODE; otherwise + return 1. + + If OPCODE has alias(es) and NOALIASES_P is 0, an alias opcode may be + determined and used to disassemble CODE; this is done just before the + return. */ + +static int +aarch64_opcode_decode (const aarch64_opcode *opcode, const aarch64_insn code, + aarch64_inst *inst, int noaliases_p) +{ + int i; + + DEBUG_TRACE ("enter with %s", opcode->name); + + assert (opcode && inst); + + /* Check the base opcode. */ + if ((code & opcode->mask) != (opcode->opcode & opcode->mask)) + { + DEBUG_TRACE ("base opcode match FAIL"); + goto decode_fail; + } + + /* Clear inst. */ + memset (inst, '\0', sizeof (aarch64_inst)); + + inst->opcode = opcode; + inst->value = code; + + /* Assign operand codes and indexes. */ + for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i) + { + if (opcode->operands[i] == AARCH64_OPND_NIL) + break; + inst->operands[i].type = opcode->operands[i]; + inst->operands[i].idx = i; + } + + /* Call the opcode decoder indicated by flags. */ + if (opcode_has_special_coder (opcode) && do_special_decoding (inst) == 0) + { + DEBUG_TRACE ("opcode flag-based decoder FAIL"); + goto decode_fail; + } + + /* Call operand decoders. */ + for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i) + { + const aarch64_operand *opnd; + enum aarch64_opnd type; + type = opcode->operands[i]; + if (type == AARCH64_OPND_NIL) + break; + opnd = &aarch64_operands[type]; + if (operand_has_extractor (opnd) + && (! aarch64_extract_operand (opnd, &inst->operands[i], code, inst))) + { + DEBUG_TRACE ("operand decoder FAIL at operand %d", i); + goto decode_fail; + } + } + + /* Match the qualifiers. */ + if (aarch64_match_operands_constraint (inst, NULL) == 1) + { + /* Arriving here, the CODE has been determined as a valid instruction + of OPCODE and *INST has been filled with information of this OPCODE + instruction. Before the return, check if the instruction has any + alias and should be disassembled in the form of its alias instead. + If the answer is yes, *INST will be updated. */ + if (!noaliases_p) + determine_disassembling_preference (inst); + DEBUG_TRACE ("SUCCESS"); + return 1; + } + else + { + DEBUG_TRACE ("constraint matching FAIL"); + } + +decode_fail: + return 0; +} + +/* This does some user-friendly fix-up to *INST. It is currently focus on + the adjustment of qualifiers to help the printed instruction + recognized/understood more easily. */ + +static void +user_friendly_fixup (aarch64_inst *inst) +{ + switch (inst->opcode->iclass) + { + case testbranch: + /* TBNZ Xn|Wn, #uimm6, label + Test and Branch Not Zero: conditionally jumps to label if bit number + uimm6 in register Xn is not zero. The bit number implies the width of + the register, which may be written and should be disassembled as Wn if + uimm is less than 32. Limited to a branch offset range of +/- 32KiB. + */ + if (inst->operands[1].imm.value < 32) + inst->operands[0].qualifier = AARCH64_OPND_QLF_W; + break; + default: break; + } +} + +/* Decode INSN and fill in *INST the instruction information. */ + +static int +disas_aarch64_insn (uint64_t pc ATTRIBUTE_UNUSED, uint32_t insn, + aarch64_inst *inst) +{ + const aarch64_opcode *opcode = aarch64_opcode_lookup (insn); + +#ifdef DEBUG_AARCH64 + if (debug_dump) + { + const aarch64_opcode *tmp = opcode; + printf ("\n"); + DEBUG_TRACE ("opcode lookup:"); + while (tmp != NULL) + { + aarch64_verbose (" %s", tmp->name); + tmp = aarch64_find_next_opcode (tmp); + } + } +#endif /* DEBUG_AARCH64 */ + + /* A list of opcodes may have been found, as aarch64_opcode_lookup cannot + distinguish some opcodes, e.g. SSHR and MOVI, which almost share the same + opcode field and value, apart from the difference that one of them has an + extra field as part of the opcode, but such a field is used for operand + encoding in other opcode(s) ('immh' in the case of the example). */ + while (opcode != NULL) + { + /* But only one opcode can be decoded successfully for, as the + decoding routine will check the constraint carefully. */ + if (aarch64_opcode_decode (opcode, insn, inst, no_aliases) == 1) + return ERR_OK; + opcode = aarch64_find_next_opcode (opcode); + } + + return ERR_UND; +} + +/* Print operands. */ + +static void +print_operands (bfd_vma pc, const aarch64_opcode *opcode, + const aarch64_opnd_info *opnds, struct disassemble_info *info) +{ + int i, pcrel_p, num_printed; + for (i = 0, num_printed = 0; i < AARCH64_MAX_OPND_NUM; ++i) + { + const size_t size = 128; + char str[size]; + /* We regard the opcode operand info more, however we also look into + the inst->operands to support the disassembling of the optional + operand. + The two operand code should be the same in all cases, apart from + when the operand can be optional. */ + if (opcode->operands[i] == AARCH64_OPND_NIL + || opnds[i].type == AARCH64_OPND_NIL) + break; + + /* Generate the operand string in STR. */ + aarch64_print_operand (str, size, pc, opcode, opnds, i, &pcrel_p, + &info->target); + + /* Print the delimiter (taking account of omitted operand(s)). */ + if (str[0] != '\0') + (*info->fprintf_func) (info->stream, "%s", + num_printed++ == 0 ? "\t" : ", "); + + /* Print the operand. */ + if (pcrel_p) + (*info->print_address_func) (info->target, info); + else + (*info->fprintf_func) (info->stream, "%s", str); + } +} + +/* Print the instruction mnemonic name. */ + +static void +print_mnemonic_name (const aarch64_inst *inst, struct disassemble_info *info) +{ + if (inst->opcode->flags & F_COND) + { + /* For instructions that are truly conditionally executed, e.g. b.cond, + prepare the full mnemonic name with the corresponding condition + suffix. */ + char name[8], *ptr; + size_t len; + + ptr = strchr (inst->opcode->name, '.'); + assert (ptr && inst->cond); + len = ptr - inst->opcode->name; + assert (len < 8); + strncpy (name, inst->opcode->name, len); + name [len] = '\0'; + (*info->fprintf_func) (info->stream, "%s.%s", name, inst->cond->names[0]); + } + else + (*info->fprintf_func) (info->stream, "%s", inst->opcode->name); +} + +/* Print the instruction according to *INST. */ + +static void +print_aarch64_insn (bfd_vma pc, const aarch64_inst *inst, + struct disassemble_info *info) +{ + print_mnemonic_name (inst, info); + print_operands (pc, inst->opcode, inst->operands, info); +} + +/* Entry-point of the instruction disassembler and printer. */ + +static void +print_insn_aarch64_word (bfd_vma pc, + uint32_t word, + struct disassemble_info *info) +{ + static const char *err_msg[6] = + { + [ERR_OK] = "_", + [-ERR_UND] = "undefined", + [-ERR_UNP] = "unpredictable", + [-ERR_NYI] = "NYI" + }; + + int ret; + aarch64_inst inst; + + info->insn_info_valid = 1; + info->branch_delay_insns = 0; + info->data_size = 0; + info->target = 0; + info->target2 = 0; + + if (info->flags & INSN_HAS_RELOC) + /* If the instruction has a reloc associated with it, then + the offset field in the instruction will actually be the + addend for the reloc. (If we are using REL type relocs). + In such cases, we can ignore the pc when computing + addresses, since the addend is not currently pc-relative. */ + pc = 0; + + ret = disas_aarch64_insn (pc, word, &inst); + + if (((word >> 21) & 0x3ff) == 1) + { + /* RESERVED for ALES. */ + assert (ret != ERR_OK); + ret = ERR_NYI; + } + + switch (ret) + { + case ERR_UND: + case ERR_UNP: + case ERR_NYI: + /* Handle undefined instructions. */ + info->insn_type = dis_noninsn; + (*info->fprintf_func) (info->stream,".inst\t0x%08x ; %s", + word, err_msg[-ret]); + break; + case ERR_OK: + user_friendly_fixup (&inst); + print_aarch64_insn (pc, &inst, info); + break; + default: + abort (); + } +} + +/* Disallow mapping symbols ($x, $d etc) from + being displayed in symbol relative addresses. */ + +bfd_boolean +aarch64_symbol_is_valid (asymbol * sym, + struct disassemble_info * info ATTRIBUTE_UNUSED) +{ + const char * name; + + if (sym == NULL) + return FALSE; + + name = bfd_asymbol_name (sym); + + return name + && (name[0] != '$' + || (name[1] != 'x' && name[1] != 'd') + || (name[2] != '\0' && name[2] != '.')); +} + +/* Print data bytes on INFO->STREAM. */ + +static void +print_insn_data (bfd_vma pc ATTRIBUTE_UNUSED, + uint32_t word, + struct disassemble_info *info) +{ + switch (info->bytes_per_chunk) + { + case 1: + info->fprintf_func (info->stream, ".byte\t0x%02x", word); + break; + case 2: + info->fprintf_func (info->stream, ".short\t0x%04x", word); + break; + case 4: + info->fprintf_func (info->stream, ".word\t0x%08x", word); + break; + default: + abort (); + } +} + +/* Try to infer the code or data type from a symbol. + Returns nonzero if *MAP_TYPE was set. */ + +static int +get_sym_code_type (struct disassemble_info *info, int n, + enum map_type *map_type) +{ + elf_symbol_type *es; + unsigned int type; + const char *name; + + es = *(elf_symbol_type **)(info->symtab + n); + type = ELF_ST_TYPE (es->internal_elf_sym.st_info); + + /* If the symbol has function type then use that. */ + if (type == STT_FUNC) + { + *map_type = MAP_INSN; + return TRUE; + } + + /* Check for mapping symbols. */ + name = bfd_asymbol_name(info->symtab[n]); + if (name[0] == '$' + && (name[1] == 'x' || name[1] == 'd') + && (name[2] == '\0' || name[2] == '.')) + { + *map_type = (name[1] == 'x' ? MAP_INSN : MAP_DATA); + return TRUE; + } + + return FALSE; +} + +/* Entry-point of the AArch64 disassembler. */ + +int +print_insn_aarch64 (bfd_vma pc, + struct disassemble_info *info) +{ + bfd_byte buffer[INSNLEN]; + int status; + void (*printer) (bfd_vma, uint32_t, struct disassemble_info *); + bfd_boolean found = FALSE; + unsigned int size = 4; + unsigned long data; + + if (info->disassembler_options) + { + set_default_aarch64_dis_options (info); + + parse_aarch64_dis_options (info->disassembler_options); + + /* To avoid repeated parsing of these options, we remove them here. */ + info->disassembler_options = NULL; + } + + /* Aarch64 instructions are always little-endian */ + info->endian_code = BFD_ENDIAN_LITTLE; + + /* First check the full symtab for a mapping symbol, even if there + are no usable non-mapping symbols for this address. */ + if (info->symtab_size != 0 + && bfd_asymbol_flavour (*info->symtab) == bfd_target_elf_flavour) + { + enum map_type type = MAP_INSN; + int last_sym = -1; + bfd_vma addr; + int n; + + if (pc <= last_mapping_addr) + last_mapping_sym = -1; + + /* Start scanning at the start of the function, or wherever + we finished last time. */ + n = info->symtab_pos + 1; + if (n < last_mapping_sym) + n = last_mapping_sym; + + /* Scan up to the location being disassembled. */ + for (; n < info->symtab_size; n++) + { + addr = bfd_asymbol_value (info->symtab[n]); + if (addr > pc) + break; + if ((info->section == NULL + || info->section == info->symtab[n]->section) + && get_sym_code_type (info, n, &type)) + { + last_sym = n; + found = TRUE; + } + } + + if (!found) + { + n = info->symtab_pos; + if (n < last_mapping_sym) + n = last_mapping_sym; + + /* No mapping symbol found at this address. Look backwards + for a preceeding one. */ + for (; n >= 0; n--) + { + if (get_sym_code_type (info, n, &type)) + { + last_sym = n; + found = TRUE; + break; + } + } + } + + last_mapping_sym = last_sym; + last_type = type; + + /* Look a little bit ahead to see if we should print out + less than four bytes of data. If there's a symbol, + mapping or otherwise, after two bytes then don't + print more. */ + if (last_type == MAP_DATA) + { + size = 4 - (pc & 3); + for (n = last_sym + 1; n < info->symtab_size; n++) + { + addr = bfd_asymbol_value (info->symtab[n]); + if (addr > pc) + { + if (addr - pc < size) + size = addr - pc; + break; + } + } + /* If the next symbol is after three bytes, we need to + print only part of the data, so that we can use either + .byte or .short. */ + if (size == 3) + size = (pc & 1) ? 1 : 2; + } + } + + if (last_type == MAP_DATA) + { + /* size was set above. */ + info->bytes_per_chunk = size; + info->display_endian = info->endian; + printer = print_insn_data; + } + else + { + info->bytes_per_chunk = size = INSNLEN; + info->display_endian = info->endian_code; + printer = print_insn_aarch64_word; + } + + status = (*info->read_memory_func) (pc, buffer, size, info); + if (status != 0) + { + (*info->memory_error_func) (status, pc, info); + return -1; + } + + data = bfd_get_bits (buffer, size * 8, + info->display_endian == BFD_ENDIAN_BIG); + + (*printer) (pc, data, info); + + return size; +} + +void +print_aarch64_disassembler_options (FILE *stream) +{ + fprintf (stream, _("\n\ +The following AARCH64 specific disassembler options are supported for use\n\ +with the -M switch (multiple options should be separated by commas):\n")); + + fprintf (stream, _("\n\ + no-aliases Don't print instruction aliases.\n")); + + fprintf (stream, _("\n\ + aliases Do print instruction aliases.\n")); + +#ifdef DEBUG_AARCH64 + fprintf (stream, _("\n\ + debug_dump Temp switch for debug trace.\n")); +#endif /* DEBUG_AARCH64 */ + + fprintf (stream, _("\n")); +} diff --git a/opcodes/aarch64-dis.h b/opcodes/aarch64-dis.h new file mode 100644 index 0000000..2fab319 --- /dev/null +++ b/opcodes/aarch64-dis.h @@ -0,0 +1,94 @@ +/* aarch64-dis.h -- Header file for aarch64-dis.c and aarch64-dis-2.c. + Copyright 2012 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING3. If not, + see <http://www.gnu.org/licenses/>. */ + +#ifndef OPCODES_AARCH64_DIS_H +#define OPCODES_AARCH64_DIS_H +#include "bfd_stdint.h" +#include "aarch64-opc.h" + +/* Lookup opcode WORD in the opcode table. + + In the case of multiple aarch64_opcode candidates, one of them will be + returned; for other candidate(s), call aarch64_find_next_opcode to + obtain. Note that aarch64_find_next_opcode finds the next + aarch64_opcode candidate in a way as if all related aarch64_opcode + entries were in a single-link list. + + N.B. all alias opcodes are ignored here. */ + +const aarch64_opcode* aarch64_opcode_lookup (uint32_t); +const aarch64_opcode* aarch64_find_next_opcode (const aarch64_opcode *); + +/* Given OPCODE, return its alias, e.g. given UBFM, return LSL. + + In the case of multiple alias candidates, the one of the highest priority + (or one of several aliases of the same highest priority) will be + returned; for the other candidate(s), call aarch64_find_next_alias_opcode + to obtain. Note that aarch64_find_next_alias_opcode finds the next + alias candidate in a way as if all related aliases were in a single-link + list with priority from the highest to the least. */ + +const aarch64_opcode* aarch64_find_alias_opcode (const aarch64_opcode *); +const aarch64_opcode* aarch64_find_next_alias_opcode (const aarch64_opcode *); + +/* Switch-table-based high-level operand extractor. */ + +int aarch64_extract_operand (const aarch64_operand *, aarch64_opnd_info *, + const aarch64_insn, const aarch64_inst *); + +/* Operand extractors. */ + +#define AARCH64_DECL_OPD_EXTRACTOR(x) \ + int aarch64_##x (const aarch64_operand *, aarch64_opnd_info *, \ + const aarch64_insn, const aarch64_inst *) + +AARCH64_DECL_OPD_EXTRACTOR (ext_regno); +AARCH64_DECL_OPD_EXTRACTOR (ext_regrt_sysins); +AARCH64_DECL_OPD_EXTRACTOR (ext_reglane); +AARCH64_DECL_OPD_EXTRACTOR (ext_reglist); +AARCH64_DECL_OPD_EXTRACTOR (ext_ldst_reglist); +AARCH64_DECL_OPD_EXTRACTOR (ext_ldst_reglist_r); +AARCH64_DECL_OPD_EXTRACTOR (ext_ldst_elemlist); +AARCH64_DECL_OPD_EXTRACTOR (ext_advsimd_imm_shift); +AARCH64_DECL_OPD_EXTRACTOR (ext_shll_imm); +AARCH64_DECL_OPD_EXTRACTOR (ext_imm); +AARCH64_DECL_OPD_EXTRACTOR (ext_imm_half); +AARCH64_DECL_OPD_EXTRACTOR (ext_advsimd_imm_modified); +AARCH64_DECL_OPD_EXTRACTOR (ext_fbits); +AARCH64_DECL_OPD_EXTRACTOR (ext_aimm); +AARCH64_DECL_OPD_EXTRACTOR (ext_limm); +AARCH64_DECL_OPD_EXTRACTOR (ext_ft); +AARCH64_DECL_OPD_EXTRACTOR (ext_addr_simple); +AARCH64_DECL_OPD_EXTRACTOR (ext_addr_regoff); +AARCH64_DECL_OPD_EXTRACTOR (ext_addr_simm); +AARCH64_DECL_OPD_EXTRACTOR (ext_addr_uimm12); +AARCH64_DECL_OPD_EXTRACTOR (ext_simd_addr_post); +AARCH64_DECL_OPD_EXTRACTOR (ext_cond); +AARCH64_DECL_OPD_EXTRACTOR (ext_sysreg); +AARCH64_DECL_OPD_EXTRACTOR (ext_pstatefield); +AARCH64_DECL_OPD_EXTRACTOR (ext_sysins_op); +AARCH64_DECL_OPD_EXTRACTOR (ext_barrier); +AARCH64_DECL_OPD_EXTRACTOR (ext_prfop); +AARCH64_DECL_OPD_EXTRACTOR (ext_reg_extended); +AARCH64_DECL_OPD_EXTRACTOR (ext_reg_shifted); + +#undef AARCH64_DECL_OPD_EXTRACTOR + +#endif /* OPCODES_AARCH64_DIS_H */ diff --git a/opcodes/aarch64-gen.c b/opcodes/aarch64-gen.c new file mode 100644 index 0000000..95bd016 --- /dev/null +++ b/opcodes/aarch64-gen.c @@ -0,0 +1,1317 @@ +/* aarch64-gen.c -- Generate tables and routines for opcode lookup and + instruction encoding and decoding. + Copyright 2012 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING3. If not, + see <http://www.gnu.org/licenses/>. */ + +#include "sysdep.h" +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +#include "libiberty.h" +#include "getopt.h" +#include "opcode/aarch64.h" + +#include "aarch64-tbl.h" + +static int debug = 0; + +/* Structure used in the decoding tree to group a list of aarch64_opcode + entries. */ + +struct opcode_node +{ + aarch64_insn opcode; + aarch64_insn mask; + /* Index of the entry in the original table; the top 2 bits help + determine the table. */ + unsigned int index; + struct opcode_node *next; +}; + +typedef struct opcode_node opcode_node; + +/* Head of the list of the opcode_node after read_table. */ +static opcode_node opcode_nodes_head; + +/* Node in the decoding tree. */ + +struct bittree +{ + unsigned int bitno; + /* 0, 1, and X (don't care). */ + struct bittree *bits[2]; + /* List of opcodes; only valid for the leaf node. */ + opcode_node *list; +}; + +/* Allocate and initialize an opcode_node. */ +static opcode_node* +new_opcode_node (void) +{ + opcode_node* ent = malloc (sizeof (opcode_node)); + + if (!ent) + abort (); + + ent->opcode = 0; + ent->mask = 0; + ent->index = -1; + ent->next = NULL; + + return ent; +} + +/* Multiple tables are supported, although currently only one table is + in use. N.B. there are still some functions have the table name + 'aarch64_opcode_table' hard-coded in, e.g. print_find_next_opcode; + therefore some amount of work needs to be done if the full support + for multiple tables needs to be enabled. */ +static const struct aarch64_opcode *aarch64_opcode_tables[] = +{aarch64_opcode_table}; + +/* Use top 2 bits to indiate which table. */ +static unsigned int +initialize_index (const struct aarch64_opcode* table) +{ + int i; + const int num_of_tables = sizeof (aarch64_opcode_tables) + / sizeof (struct aarch64_opcode *); + for (i = 0; i < num_of_tables; ++i) + if (table == aarch64_opcode_tables [i]) + break; + if (i == num_of_tables) + abort (); + return (unsigned int)i << 30; +} + +static inline const struct aarch64_opcode * +index2table (unsigned int index) +{ + return aarch64_opcode_tables[(index >> 30) & 0x3]; +} + +static inline unsigned int +real_index (unsigned int index) +{ + return index & ((1 << 30) - 1); +} + +/* Given OPCODE_NODE, return the corresponding aarch64_opcode*. */ +static const aarch64_opcode* +get_aarch64_opcode (const opcode_node *opcode_node) +{ + if (opcode_node == NULL) + return NULL; + return &index2table (opcode_node->index)[real_index (opcode_node->index)]; +} + +static void +read_table (const struct aarch64_opcode* table) +{ + const struct aarch64_opcode *ent = table; + opcode_node **new_ent; + unsigned int index = initialize_index (table); + + if (!ent->name) + return; + + new_ent = &opcode_nodes_head.next; + + while (*new_ent) + new_ent = &(*new_ent)->next; + + do + { + /* F_PSEUDO needs to be used together with F_ALIAS to indicate an alias + opcode is a programmer friendly pseudo instruction available only in + the assembly code (thus will not show up in the disassembly). */ + assert (pseudo_opcode_p (ent) == FALSE || alias_opcode_p (ent) == TRUE); + /* Skip alias (inc. pseudo) opcode. */ + if (alias_opcode_p (ent) == TRUE) + { + index++; + continue; + } + *new_ent = new_opcode_node (); + (*new_ent)->opcode = ent->opcode; + (*new_ent)->mask = ent->mask; + (*new_ent)->index = index++; + new_ent = &((*new_ent)->next); + } while ((++ent)->name); +} + +static inline void +print_one_opcode_node (opcode_node* ent) +{ + printf ("%s\t%08x\t%08x\t%d\n", get_aarch64_opcode (ent)->name, + get_aarch64_opcode (ent)->opcode, get_aarch64_opcode (ent)->mask, + (int)real_index (ent->index)); +} + +/* As an internal debugging utility, print out the list of nodes pointed + by opcode_nodes_head. */ +static void +print_opcode_nodes (void) +{ + opcode_node* ent = opcode_nodes_head.next; + printf ("print_opcode_nodes table:\n"); + while (ent) + { + print_one_opcode_node (ent); + ent = ent->next; + } +} + +static struct bittree* +new_bittree_node (void) +{ + struct bittree* node; + node = malloc (sizeof (struct bittree)); + if (!node) + abort (); + node->bitno = -1; + node->bits[0] = NULL; + node->bits[1] = NULL; + return node; +} + +/* The largest number of opcode entries that exist at a leaf node of the + decoding decision tree. The reason that there can be more than one + opcode entry is because some opcodes have shared field that is partially + constrained and thus cannot be fully isolated using the algorithm + here. */ +static int max_num_opcodes_at_leaf_node = 0; + +/* Given a list of opcodes headed by *OPCODE, try to establish one bit that + is shared by all the opcodes in the list as one of base opcode bits. If + such a bit is found, divide the list of the opcodes into two based on the + value of the bit. + + Store the bit number in BITTREE->BITNO if the division succeeds. If unable + to determine such a bit or there is only one opcode in the list, the list + is decided to be undividable and OPCODE will be assigned to BITTREE->LIST. + + The function recursively call itself until OPCODE is undividable. + + N.B. the nature of this algrithm determines that given any value in the + 32-bit space, the computed decision tree will always be able to find one or + more opcodes entries for it, regardless whether there is a valid instruction + defined for this value or not. In order to detect the undefined values, + when the caller obtains the opcode entry/entries, it should at least compare + the bit-wise AND result of the value and the mask with the base opcode + value; if the two are different, it means that the value is undefined + (although the value may be still undefined when the comparison is the same, + in which case call aarch64_opcode_decode to carry out further checks). */ + +static void +divide_table_1 (struct bittree *bittree, opcode_node *opcode) +{ + aarch64_insn mask_and; + opcode_node *ent; + unsigned int bitno; + aarch64_insn bitmask; + opcode_node list0, list1, **ptr0, **ptr1; + static int depth = 0; + + ++depth; + + if (debug) + printf ("Enter into depth %d\n", depth); + + assert (opcode != NULL); + + /* Succeed when there is only one opcode left. */ + if (!opcode->next) + { + if (debug) + { + printf ("opcode isolated:\n"); + print_one_opcode_node (opcode); + } + goto divide_table_1_finish; + } + +divide_table_1_try_again: + mask_and = -1; + ent = opcode; + while (ent) + { + mask_and &= ent->mask; + ent = ent->next; + } + + if (debug) + printf ("mask and result: %08x\n", (unsigned int)mask_and); + + /* If no more bit to look into, we have to accept the reality then. */ + if (!mask_and) + { + int i; + opcode_node *ptr; + if (debug) + { + ptr = opcode; + printf ("Isolated opcode group:\n"); + do { + print_one_opcode_node (ptr); + ptr = ptr->next; + } while (ptr); + } + /* Count the number of opcodes. */ + for (i = 0, ptr = opcode; ptr; ++i) + ptr = ptr->next; + if (i > max_num_opcodes_at_leaf_node) + max_num_opcodes_at_leaf_node = i; + goto divide_table_1_finish; + } + + /* Pick up the right most bit that is 1. */ + bitno = 0; + while (!(mask_and & (1 << bitno))) + ++bitno; + bitmask = (1 << bitno); + + if (debug) + printf ("use bit %d\n", bitno); + + /* Record in the bittree. */ + bittree->bitno = bitno; + + /* Get two new opcode lists; adjust their masks. */ + list0.next = NULL; + list1.next = NULL; + ptr0 = &list0.next; + ptr1 = &list1.next; + ent = opcode; + while (ent) + { + if (ent->opcode & bitmask) + { + ent->mask &= (~bitmask); + *ptr1 = ent; + ent = ent->next; + (*ptr1)->next = NULL; + ptr1 = &(*ptr1)->next; + } + else + { + ent->mask &= (~bitmask); + *ptr0 = ent; + ent = ent->next; + (*ptr0)->next = NULL; + ptr0 = &(*ptr0)->next; + } + } + + /* If BITNO can NOT divide the opcode group, try next bit. */ + if (list0.next == NULL) + { + opcode = list1.next; + goto divide_table_1_try_again; + } + else if (list1.next == NULL) + { + opcode = list0.next; + goto divide_table_1_try_again; + } + + /* Further divide. */ + bittree->bits[0] = new_bittree_node (); + bittree->bits[1] = new_bittree_node (); + divide_table_1 (bittree->bits[0], list0.next); + divide_table_1 (bittree->bits[1], list1.next); + +divide_table_1_finish: + if (debug) + printf ("Leave from depth %d\n", depth); + --depth; + + /* Record the opcode entries on this leaf node. */ + bittree->list = opcode; + + return; +} + +/* Call divide_table_1 to divide the all the opcodes and thus create the + decoding decision tree. */ +static struct bittree * +divide_table (void) +{ + struct bittree *bittree = new_bittree_node (); + divide_table_1 (bittree, opcode_nodes_head.next); + return bittree; +} + +/* Read in all of the tables, create the decoding decision tree and return + the tree root. */ +static struct bittree * +initialize_decoder_tree (void) +{ + int i; + const int num_of_tables = (sizeof (aarch64_opcode_tables) + / sizeof (struct aarch64_opcode *)); + for (i = 0; i < num_of_tables; ++i) + read_table (aarch64_opcode_tables [i]); + if (debug) + print_opcode_nodes (); + return divide_table (); +} + +static void __attribute__ ((format (printf, 2, 3))) +indented_print (unsigned int indent, const char *format, ...) +{ + /* 80 number of spaces pluc a NULL terminator. */ + static const char spaces[81] = + " "; + va_list ap; + va_start (ap, format); + assert (indent <= 80); + printf ("%s", &spaces[80 - indent]); + vprintf (format, ap); + va_end (ap); +} + +/* N.B. read the comment above divide_table_1 for the reason why the generated + decision tree function never returns NULL. */ + +static void +print_decision_tree_1 (unsigned int indent, struct bittree* bittree) +{ + /* PATTERN is only used to generate comment in the code. */ + static char pattern[33] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; + assert (bittree != NULL); + + /* Leaf node located. */ + if (bittree->bits[0] == NULL && bittree->bits[1] == NULL) + { + assert (bittree->list != NULL); + indented_print (indent, "/* 33222222222211111111110000000000\n"); + indented_print (indent, " 10987654321098765432109876543210\n"); + indented_print (indent, " %s\n", pattern); + indented_print (indent, " %s. */\n", + get_aarch64_opcode (bittree->list)->name); + indented_print (indent, "return %u;\n", + real_index (bittree->list->index)); + return; + } + + /* Walk down the decoder tree. */ + indented_print (indent, "if (((word >> %d) & 0x1) == 0)\n", bittree->bitno); + indented_print (indent, " {\n"); + pattern[bittree->bitno] = '0'; + print_decision_tree_1 (indent + 4, bittree->bits[0]); + indented_print (indent, " }\n"); + indented_print (indent, "else\n"); + indented_print (indent, " {\n"); + pattern[bittree->bitno] = '1'; + print_decision_tree_1 (indent + 4, bittree->bits[1]); + indented_print (indent, " }\n"); + pattern[bittree->bitno] = 'x'; +} + +/* Generate aarch64_opcode_lookup in C code to the standard output. */ + +static void +print_decision_tree (struct bittree* bittree) +{ + if (debug) + printf ("Enter print_decision_tree\n"); + + printf ("/* Called by aarch64_opcode_lookup. */\n\n"); + + printf ("static int\n"); + printf ("aarch64_opcode_lookup_1 (uint32_t word)\n"); + printf ("{\n"); + + print_decision_tree_1 (2, bittree); + + printf ("}\n\n"); + + + printf ("/* Lookup opcode WORD in the opcode table. N.B. all alias\n"); + printf (" opcodes are ignored here. */\n\n"); + + printf ("const aarch64_opcode *\n"); + printf ("aarch64_opcode_lookup (uint32_t word)\n"); + printf ("{\n"); + printf (" return aarch64_opcode_table + aarch64_opcode_lookup_1 (word);\n"); + printf ("}\n"); +} + +static void +print_find_next_opcode_1 (struct bittree* bittree) +{ + assert (bittree != NULL); + + /* Leaf node located. */ + if (bittree->bits[0] == NULL && bittree->bits[1] == NULL) + { + assert (bittree->list != NULL); + /* Find multiple opcode entries in one leaf node. */ + if (bittree->list->next != NULL) + { + opcode_node *list = bittree->list; + while (list != NULL) + { + const aarch64_opcode *curr = get_aarch64_opcode (list); + const aarch64_opcode *next = get_aarch64_opcode (list->next); + + printf (" case %u: ", + (unsigned int)(curr - aarch64_opcode_table)); + if (list->next != NULL) + { + printf ("value = %u; break;\t", real_index (list->next->index)); + printf ("/* %s --> %s. */\n", curr->name, next->name); + } + else + { + printf ("return NULL;\t\t"); + printf ("/* %s --> NULL. */\n", curr->name); + } + + list = list->next; + } + } + return; + } + + /* Walk down the decoder tree. */ + print_find_next_opcode_1 (bittree->bits[0]); + print_find_next_opcode_1 (bittree->bits[1]); +} + +/* Generate aarch64_find_next_opcode in C code to the standard output. */ + +static void +print_find_next_opcode (struct bittree* bittree) +{ + if (debug) + printf ("Enter print_find_next_opcode\n"); + + printf ("\n"); + printf ("const aarch64_opcode *\n"); + printf ("aarch64_find_next_opcode (const aarch64_opcode *opcode)\n"); + printf ("{\n"); + printf (" /* Use the index as the key to locate the next opcode. */\n"); + printf (" int key = opcode - aarch64_opcode_table;\n"); + printf (" int value;\n"); + printf (" switch (key)\n"); + printf (" {\n"); + + print_find_next_opcode_1 (bittree); + + printf (" default: return NULL;\n"); + printf (" }\n\n"); + + printf (" return aarch64_opcode_table + value;\n"); + printf ("}\n"); +} + +/* Release the dynamic memory resource allocated for the generation of the + decoder tree. */ + +static void +release_resource_decoder_tree (struct bittree* bittree) +{ + assert (bittree != NULL); + + /* Leaf node located. */ + if (bittree->bits[0] == NULL && bittree->bits[1] == NULL) + { + assert (bittree->list != NULL); + /* Free opcode_nodes. */ + opcode_node *list = bittree->list; + while (list != NULL) + { + opcode_node *next = list->next; + free (list); + list = next; + } + /* Free the tree node. */ + free (bittree); + return; + } + + /* Walk down the decoder tree. */ + release_resource_decoder_tree (bittree->bits[0]); + release_resource_decoder_tree (bittree->bits[1]); + + /* Free the tree node. */ + free (bittree); +} + +/* Generate aarch64_find_real_opcode in C code to the standard output. + TABLE points to the alias info table, while NUM indicates the number of + entries in the table. */ + +static void +print_find_real_opcode (const opcode_node *table, int num) +{ + int i; + + if (debug) + printf ("Enter print_find_real_opcode\n"); + + printf ("\n"); + printf ("const aarch64_opcode *\n"); + printf ("aarch64_find_real_opcode (const aarch64_opcode *opcode)\n"); + printf ("{\n"); + printf (" /* Use the index as the key to locate the real opcode. */\n"); + printf (" int key = opcode - aarch64_opcode_table;\n"); + printf (" int value;\n"); + printf (" switch (key)\n"); + printf (" {\n"); + + for (i = 0; i < num; ++i) + { + const opcode_node *real = table + i; + const opcode_node *alias = real->next; + for (; alias; alias = alias->next) + printf (" case %u:\t/* %s */\n", real_index (alias->index), + get_aarch64_opcode (alias)->name); + printf (" value = %u;\t/* --> %s. */\n", real_index (real->index), + get_aarch64_opcode (real)->name); + printf (" break;\n"); + } + + printf (" default: return NULL;\n"); + printf (" }\n\n"); + + printf (" return aarch64_opcode_table + value;\n"); + printf ("}\n"); +} + +/* Generate aarch64_find_alias_opcode in C code to the standard output. + TABLE points to the alias info table, while NUM indicates the number of + entries in the table. */ + +static void +print_find_alias_opcode (const opcode_node *table, int num) +{ + int i; + + if (debug) + printf ("Enter print_find_alias_opcode\n"); + + printf ("\n"); + printf ("const aarch64_opcode *\n"); + printf ("aarch64_find_alias_opcode (const aarch64_opcode *opcode)\n"); + printf ("{\n"); + printf (" /* Use the index as the key to locate the alias opcode. */\n"); + printf (" int key = opcode - aarch64_opcode_table;\n"); + printf (" int value;\n"); + printf (" switch (key)\n"); + printf (" {\n"); + + for (i = 0; i < num; ++i) + { + const opcode_node *node = table + i; + assert (node->next); + printf (" case %u: value = %u; break;", real_index (node->index), + real_index (node->next->index)); + printf ("\t/* %s --> %s. */\n", get_aarch64_opcode (node)->name, + get_aarch64_opcode (node->next)->name); + } + + printf (" default: return NULL;\n"); + printf (" }\n\n"); + + printf (" return aarch64_opcode_table + value;\n"); + printf ("}\n"); +} + +/* Generate aarch64_find_next_alias_opcode in C code to the standard output. + TABLE points to the alias info table, while NUM indicates the number of + entries in the table. */ + +static void +print_find_next_alias_opcode (const opcode_node *table, int num) +{ + int i; + + if (debug) + printf ("Enter print_find_next_alias_opcode\n"); + + printf ("\n"); + printf ("const aarch64_opcode *\n"); + printf ("aarch64_find_next_alias_opcode (const aarch64_opcode *opcode)\n"); + printf ("{\n"); + printf (" /* Use the index as the key to locate the next opcode. */\n"); + printf (" int key = opcode - aarch64_opcode_table;\n"); + printf (" int value;\n"); + printf (" switch (key)\n"); + printf (" {\n"); + + for (i = 0; i < num; ++i) + { + const opcode_node *node = table + i; + assert (node->next); + if (node->next->next == NULL) + continue; + while (node->next->next) + { + printf (" case %u: value = %u; break;", real_index (node->next->index), + real_index (node->next->next->index)); + printf ("\t/* %s --> %s. */\n", + get_aarch64_opcode (node->next)->name, + get_aarch64_opcode (node->next->next)->name); + node = node->next; + } + } + + printf (" default: return NULL;\n"); + printf (" }\n\n"); + + printf (" return aarch64_opcode_table + value;\n"); + printf ("}\n"); +} + +/* Given OPCODE, establish and return a link list of alias nodes in the + preferred order. */ + +opcode_node * +find_alias_opcode (const aarch64_opcode *opcode) +{ + int i; + /* Assume maximum of 8 disassemble preference candidates. */ + const int max_num_aliases = 8; + const aarch64_opcode *ent; + const aarch64_opcode *preferred[max_num_aliases]; + opcode_node head, **next; + + assert (opcode_has_alias (opcode)); + + i = 0; + ent = aarch64_opcode_table; + while (ent->name != NULL) + { + /* The mask of an alias opcode must be equal to or a super-set (i.e. + more constrained) of that of the aliased opcode; so is the base + opcode value. */ + if (alias_opcode_p (ent) == TRUE + && (ent->mask & opcode->mask) == opcode->mask + && (opcode->mask & ent->opcode) == (opcode->mask & opcode->opcode)) + { + assert (i < max_num_aliases); + preferred[i++] = ent; + if (debug) + printf ("found %s for %s.", ent->name, opcode->name); + } + ++ent; + } + + if (debug) + { + int m; + printf ("un-orderd list: "); + for (m = 0; m < i; ++m) + printf ("%s, ", preferred[m]->name); + printf ("\n"); + } + + /* There must be at least one alias. */ + assert (i >= 1); + + /* Sort preferred array according to the priority (from the lowest to the + highest. */ + if (i > 1) + { + int j, k; + for (j = 0; j < i - 1; ++j) + { + for (k = 0; k < i - 1 - j; ++k) + { + const aarch64_opcode *t; + t = preferred [k+1]; + if (opcode_priority (t) < opcode_priority (preferred [k])) + { + preferred [k+1] = preferred [k]; + preferred [k] = t; + } + } + } + } + + if (debug) + { + int m; + printf ("orderd list: "); + for (m = 0; m < i; ++m) + printf ("%s, ", preferred[m]->name); + printf ("\n"); + } + + /* Create a link-list of opcode_node with disassemble preference from + higher to lower. */ + next = &head.next; + --i; + while (i >= 0) + { + const aarch64_opcode *alias = preferred [i]; + opcode_node *node = new_opcode_node (); + + if (debug) + printf ("add %s.\n", alias->name); + + node->index = alias - aarch64_opcode_table; + *next = node; + next = &node->next; + + --i; + } + *next = NULL; + + return head.next; +} + +/* Create and return alias information. + Return the address of the created alias info table; return the number + of table entries in *NUM_PTR. */ + +opcode_node * +create_alias_info (int *num_ptr) +{ + int i, num; + opcode_node *ret; + const aarch64_opcode *ent; + + /* Calculate the total number of opcodes that have alias. */ + num = 0; + ent = aarch64_opcode_table; + while (ent->name != NULL) + { + if (opcode_has_alias (ent)) + { + /* Assert the alias relationship be flat-structured to keep + algorithms simple; not allow F_ALIAS and F_HAS_ALIAS both + specified. */ + assert (!alias_opcode_p (ent)); + ++num; + } + ++ent; + } + assert (num_ptr); + *num_ptr = num; + + /* The array of real opcodes that have alias(es). */ + ret = malloc (sizeof (opcode_node) * num); + + /* For each opcode, establish a list of alias nodes in a preferred + order. */ + for (i = 0, ent = aarch64_opcode_table; i < num; ++i, ++ent) + { + opcode_node *node = ret + i; + while (ent->name != NULL && !opcode_has_alias (ent)) + ++ent; + assert (ent->name != NULL); + node->index = ent - aarch64_opcode_table; + node->next = find_alias_opcode (ent); + assert (node->next); + } + assert (i == num); + + return ret; +} + +/* Release the dynamic memory resource allocated for the generation of the + alias information. */ + +void +release_resource_alias_info (opcode_node *alias_info, int num) +{ + int i = 0; + opcode_node *node = alias_info; + + /* Free opcode_node list. */ + for (; i < num; ++i, ++node) + { + opcode_node *list = node->next; + do + { + opcode_node *next = list->next; + free (list); + list = next; + } while (list != NULL); + } + + /* Free opcode_node array. */ + free (alias_info); +} + +/* As a debugging utility, print out the result of the table division, although + it is not doing much this moment. */ +static void +print_divide_result (const struct bittree *bittree ATTRIBUTE_UNUSED) +{ + printf ("max_num_opcodes_at_leaf_node: %d\n", max_num_opcodes_at_leaf_node); + return; +} + +/* Structure to help generate the operand table. */ +struct operand +{ + const char *class; + const char *inserter; + const char *extractor; + const char *str; + const char *flags; + const char *fields; + const char *desc; + unsigned processed : 1; + unsigned has_inserter : 1; + unsigned has_extractor : 1; +}; + +typedef struct operand operand; + +#ifdef X +#undef X +#endif + +#ifdef Y +#undef Y +#endif + +#ifdef F +#undef F +#endif + +/* Get the operand information in strings. */ + +static operand operands[] = +{ + {"NIL", "0", "0", "", "0", "{0}", "<none>", 0, 0, 0}, +#define F(...) #__VA_ARGS__ +#define X(a,b,c,d,e,f,g) \ + {#a, #b, #c, d, #e, "{"f"}", g, 0, 0, 0}, +#define Y(a,b,d,e,f,g) \ + {#a, "ins_"#b, "ext_"#b, d, #e, "{"f"}", g, 0, 0, 0}, + AARCH64_OPERANDS + {"NIL", "0", "0", "", "0", "{0}", "DUMMY", 0, 0, 0}, +}; + +#undef F +#undef X + +static void +process_operand_table (void) +{ + int i; + operand *opnd; + const int num = sizeof (operands) / sizeof (operand); + + for (i = 0, opnd = operands; i < num; ++i, ++opnd) + { + opnd->has_inserter = opnd->inserter[0] != '0'; + opnd->has_extractor = opnd->extractor[0] != '0'; + } +} + +/* Generate aarch64_operands in C to the standard output. */ + +static void +print_operand_table (void) +{ + int i; + operand *opnd; + const int num = sizeof (operands) / sizeof (operand); + + if (debug) + printf ("Enter print_operand_table\n"); + + printf ("\n"); + printf ("const struct aarch64_operand aarch64_operands[] =\n"); + printf ("{\n"); + + for (i = 0, opnd = operands; i < num; ++i, ++opnd) + { + char flags[256]; + flags[0] = '\0'; + if (opnd->flags[0] != '0') + sprintf (flags, "%s", opnd->flags); + if (opnd->has_inserter) + { + if (flags[0] != '\0') + strcat (flags, " | "); + strcat (flags, "OPD_F_HAS_INSERTER"); + } + if (opnd->has_extractor) + { + if (flags[0] != '\0') + strcat (flags, " | "); + strcat (flags, "OPD_F_HAS_EXTRACTOR"); + } + if (flags[0] == '\0') + { + flags[0] = '0'; + flags[1] = '\0'; + } + printf (" {AARCH64_OPND_CLASS_%s, \"%s\", %s, %s, \"%s\"},\n", + opnd->class, opnd->str, flags, opnd->fields, opnd->desc); + } + printf ("};\n"); +} + +/* Generate aarch64_insert_operand in C to the standard output. */ + +static void +print_operand_inserter (void) +{ + int i; + operand *opnd; + const int num = sizeof (operands) / sizeof (operand); + + if (debug) + printf ("Enter print_operand_inserter\n"); + + printf ("\n"); + printf ("const char*\n"); + printf ("aarch64_insert_operand (const aarch64_operand *self,\n\ + const aarch64_opnd_info *info,\n\ + aarch64_insn *code, const aarch64_inst *inst)\n"); + printf ("{\n"); + printf (" /* Use the index as the key. */\n"); + printf (" int key = self - aarch64_operands;\n"); + printf (" switch (key)\n"); + printf (" {\n"); + + for (i = 0, opnd = operands; i < num; ++i, ++opnd) + opnd->processed = 0; + + for (i = 0, opnd = operands; i < num; ++i, ++opnd) + { + if (!opnd->processed && opnd->has_inserter) + { + int j = i + 1; + const int len = strlen (opnd->inserter); + operand *opnd2 = opnd + 1; + printf (" case %u:\n", (unsigned int)(opnd - operands)); + opnd->processed = 1; + for (; j < num; ++j, ++opnd2) + { + if (!opnd2->processed + && opnd2->has_inserter + && len == strlen (opnd2->inserter) + && strncmp (opnd->inserter, opnd2->inserter, len) == 0) + { + printf (" case %u:\n", (unsigned int)(opnd2 - operands)); + opnd2->processed = 1; + } + } + printf (" return aarch64_%s (self, info, code, inst);\n", + opnd->inserter); + } + } + + printf (" default: assert (0); abort ();\n"); + printf (" }\n"); + printf ("}\n"); +} + +/* Generate aarch64_extract_operand in C to the standard output. */ + +static void +print_operand_extractor (void) +{ + int i; + operand *opnd; + const int num = sizeof (operands) / sizeof (operand); + + if (debug) + printf ("Enter print_operand_extractor\n"); + + printf ("\n"); + printf ("int\n"); + printf ("aarch64_extract_operand (const aarch64_operand *self,\n\ + aarch64_opnd_info *info,\n\ + aarch64_insn code, const aarch64_inst *inst)\n"); + printf ("{\n"); + printf (" /* Use the index as the key. */\n"); + printf (" int key = self - aarch64_operands;\n"); + printf (" switch (key)\n"); + printf (" {\n"); + + for (i = 0, opnd = operands; i < num; ++i, ++opnd) + opnd->processed = 0; + + for (i = 0, opnd = operands; i < num; ++i, ++opnd) + { + if (!opnd->processed && opnd->has_extractor) + { + int j = i + 1; + const int len = strlen (opnd->extractor); + operand *opnd2 = opnd + 1; + printf (" case %u:\n", (unsigned int)(opnd - operands)); + opnd->processed = 1; + for (; j < num; ++j, ++opnd2) + { + if (!opnd2->processed + && opnd2->has_extractor + && len == strlen (opnd2->extractor) + && strncmp (opnd->extractor, opnd2->extractor, len) == 0) + { + printf (" case %u:\n", (unsigned int)(opnd2 - operands)); + opnd2->processed = 1; + } + } + printf (" return aarch64_%s (self, info, code, inst);\n", + opnd->extractor); + } + } + + printf (" default: assert (0); abort ();\n"); + printf (" }\n"); + printf ("}\n"); +} + +/* Table indexed by opcode enumerator stores the index of the corresponding + opcode entry in aarch64_opcode_table. */ +static unsigned op_enum_table [OP_TOTAL_NUM]; + +/* Print out the routine which, given the opcode enumerator, returns the + corresponding opcode entry pointer. */ + +static void +print_get_opcode (void) +{ + int i; + const int num = OP_TOTAL_NUM; + const aarch64_opcode *opcode; + + if (debug) + printf ("Enter print_get_opcode\n"); + + /* Fill in the internal table. */ + opcode = aarch64_opcode_table; + while (opcode->name != NULL) + { + if (opcode->op != OP_NIL) + { + /* Assert opcode enumerator be unique, in other words, no shared by + different opcodes. */ + if (op_enum_table[opcode->op] != 0) + { + fprintf (stderr, "Opcode %u is shared by different %s and %s.\n", + opcode->op, + aarch64_opcode_table[op_enum_table[opcode->op]].name, + opcode->name); + assert (0); + abort (); + } + assert (opcode->op < OP_TOTAL_NUM); + op_enum_table[opcode->op] = opcode - aarch64_opcode_table; + } + ++opcode; + } + + /* Print the table. */ + printf ("\n"); + printf ("/* Indexed by an enum aarch64_op enumerator, the value is the offset of\n\ + the corresponding aarch64_opcode entry in the aarch64_opcode_table. */\n\n"); + printf ("static const unsigned op_enum_table [] =\n"); + printf ("{\n"); + for (i = 0; i < num; ++i) + printf (" %u,\n", op_enum_table[i]); + printf ("};\n"); + + /* Print the function. */ + printf ("\n"); + printf ("/* Given the opcode enumerator OP, return the pointer to the corresponding\n"); + printf (" opcode entry. */\n"); + printf ("\n"); + printf ("const aarch64_opcode *\n"); + printf ("aarch64_get_opcode (enum aarch64_op op)\n"); + printf ("{\n"); + printf (" return aarch64_opcode_table + op_enum_table[op];\n"); + printf ("}\n"); +} + +/* Print out the content of an opcode table (not in use). */ +static void ATTRIBUTE_UNUSED +print_table (struct aarch64_opcode* table) +{ + struct aarch64_opcode *ent = table; + do + { + printf ("%s\t%08x\t%08x\n", ent->name, (unsigned int)ent->opcode, + (unsigned int)ent->mask); + } while ((++ent)->name); +} + +static const char * program_name = NULL; + +/* Program options. */ +struct option long_options[] = +{ + {"debug", no_argument, NULL, 'd'}, + {"version", no_argument, NULL, 'V'}, + {"help", no_argument, NULL, 'h'}, + {"gen-opc", no_argument, NULL, 'c'}, + {"gen-asm", no_argument, NULL, 'a'}, + {"gen-dis", no_argument, NULL, 's'}, + {0, no_argument, NULL, 0} +}; + +static void +print_version (void) +{ + printf ("%s: version 1.0\n", program_name); + xexit (0); +} + +static void +usage (FILE * stream, int status) +{ + fprintf (stream, "Usage: %s [-V | --version] [-d | --debug] [--help]\n", + program_name); + fprintf (stream, "\t[ [-c | --gen-opc] | [-a | --gen-asm] | [-s | --gen-dis] ]\n"); + xexit (status); +} + +int +main (int argc, char **argv) +{ + extern int chdir (char *); + int c; + int gen_opcode_p = 0; + int gen_assembler_p = 0; + int gen_disassembler_p = 0; + + program_name = *argv; + xmalloc_set_program_name (program_name); + + while ((c = getopt_long (argc, argv, "vVdhacs", long_options, 0)) != EOF) + switch (c) + { + case 'V': + case 'v': + print_version (); + break; + case 'd': + debug = 1; + break; + case 'h': + case '?': + usage (stderr, 0); + break; + case 'c': + gen_opcode_p = 1; + break; + case 'a': + gen_assembler_p = 1; + break; + case 's': + gen_disassembler_p = 1; + break; + default: + case 0: + break; + } + + if (argc == 1 || optind != argc) + usage (stdout, 1); + + if (gen_opcode_p + gen_assembler_p + gen_disassembler_p > 1) + { + printf ("Please specify only one of the following options\n\ + [-c | --gen-opc] [-a | --gen-asm] [-s | --gen-dis]\n"); + xexit (2); + } + + struct bittree *decoder_tree; + + decoder_tree = initialize_decoder_tree (); + if (debug) + print_divide_result (decoder_tree); + + printf ("/* This file is automatically generated by aarch64-gen. Do not edit! */\n"); + printf ("/* Copyright 2012 Free Software Foundation, Inc.\n\ + Contributed by ARM Ltd.\n\ +\n\ + This file is part of the GNU opcodes library.\n\ +\n\ + This library is free software; you can redistribute it and/or modify\n\ + it under the terms of the GNU General Public License as published by\n\ + the Free Software Foundation; either version 3, or (at your option)\n\ + any later version.\n\ +\n\ + It is distributed in the hope that it will be useful, but WITHOUT\n\ + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n\ + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\n\ + License for more details.\n\ +\n\ + You should have received a copy of the GNU General Public License\n\ + along with this program; see the file COPYING3. If not,\n\ + see <http://www.gnu.org/licenses/>. */\n"); + + printf ("\n"); + printf ("#include \"sysdep.h\"\n"); + if (gen_opcode_p) + printf ("#include \"aarch64-opc.h\"\n"); + if (gen_assembler_p) + printf ("#include \"aarch64-asm.h\"\n"); + if (gen_disassembler_p) + printf ("#include \"aarch64-dis.h\"\n"); + printf ("\n"); + + /* Generate opcode entry lookup for the disassembler. */ + if (gen_disassembler_p) + { + print_decision_tree (decoder_tree); + print_find_next_opcode (decoder_tree); + release_resource_decoder_tree (decoder_tree); + } + + /* Generate alias opcode handling for the assembler or the disassembler. */ + if (gen_assembler_p || gen_disassembler_p) + { + int num; + opcode_node *alias_info = create_alias_info (&num); + + if (gen_assembler_p) + print_find_real_opcode (alias_info, num); + + if (gen_disassembler_p) + { + print_find_alias_opcode (alias_info, num); + print_find_next_alias_opcode (alias_info, num); + } + + release_resource_alias_info (alias_info, num); + } + + /* Generate operand table. */ + process_operand_table (); + + if (gen_assembler_p) + print_operand_inserter (); + + if (gen_disassembler_p) + print_operand_extractor (); + + if (gen_opcode_p) + print_operand_table (); + + /* Generate utility to return aarch64_opcode entry given an enumerator. */ + if (gen_opcode_p) + print_get_opcode (); + + exit (0); +} diff --git a/opcodes/aarch64-opc-2.c b/opcodes/aarch64-opc-2.c new file mode 100644 index 0000000..68681f6 --- /dev/null +++ b/opcodes/aarch64-opc-2.c @@ -0,0 +1,195 @@ +/* This file is automatically generated by aarch64-gen. Do not edit! */ +/* Copyright 2012 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING3. If not, + see <http://www.gnu.org/licenses/>. */ + +#include "sysdep.h" +#include "aarch64-opc.h" + + +const struct aarch64_operand aarch64_operands[] = +{ + {AARCH64_OPND_CLASS_NIL, "", 0, {0}, "<none>"}, + {AARCH64_OPND_CLASS_INT_REG, "Rd", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rd}, "an integer register"}, + {AARCH64_OPND_CLASS_INT_REG, "Rn", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn}, "an integer register"}, + {AARCH64_OPND_CLASS_INT_REG, "Rm", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rm}, "an integer register"}, + {AARCH64_OPND_CLASS_INT_REG, "Rt", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rt}, "an integer register"}, + {AARCH64_OPND_CLASS_INT_REG, "Rt2", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rt2}, "an integer register"}, + {AARCH64_OPND_CLASS_INT_REG, "Rs", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rs}, "an integer register"}, + {AARCH64_OPND_CLASS_INT_REG, "Ra", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Ra}, "an integer register"}, + {AARCH64_OPND_CLASS_INT_REG, "Rt_SYS", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rt}, "an integer register"}, + {AARCH64_OPND_CLASS_INT_REG, "Rd_SP", OPD_F_MAYBE_SP | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rd}, "an integer or stack pointer register"}, + {AARCH64_OPND_CLASS_INT_REG, "Rn_SP", OPD_F_MAYBE_SP | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn}, "an integer or stack pointer register"}, + {AARCH64_OPND_CLASS_MODIFIED_REG, "Rm_EXT", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "an integer register with optional extension"}, + {AARCH64_OPND_CLASS_MODIFIED_REG, "Rm_SFT", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "an integer register with optional shift"}, + {AARCH64_OPND_CLASS_FP_REG, "Fd", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rd}, "a floating-point register"}, + {AARCH64_OPND_CLASS_FP_REG, "Fn", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn}, "a floating-point register"}, + {AARCH64_OPND_CLASS_FP_REG, "Fm", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rm}, "a floating-point register"}, + {AARCH64_OPND_CLASS_FP_REG, "Fa", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Ra}, "a floating-point register"}, + {AARCH64_OPND_CLASS_FP_REG, "Ft", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rt}, "a floating-point register"}, + {AARCH64_OPND_CLASS_FP_REG, "Ft2", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rt2}, "a floating-point register"}, + {AARCH64_OPND_CLASS_SISD_REG, "Sd", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rd}, "a SIMD scalar register"}, + {AARCH64_OPND_CLASS_SISD_REG, "Sn", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn}, "a SIMD scalar register"}, + {AARCH64_OPND_CLASS_SISD_REG, "Sm", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rm}, "a SIMD scalar register"}, + {AARCH64_OPND_CLASS_SIMD_REG, "Vd", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rd}, "a SIMD vector register"}, + {AARCH64_OPND_CLASS_SIMD_REG, "Vn", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn}, "a SIMD vector register"}, + {AARCH64_OPND_CLASS_SIMD_REG, "Vm", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rm}, "a SIMD vector register"}, + {AARCH64_OPND_CLASS_FP_REG, "VdD1", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rd}, "the top half of a 128-bit FP/SIMD register"}, + {AARCH64_OPND_CLASS_FP_REG, "VnD1", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn}, "the top half of a 128-bit FP/SIMD register"}, + {AARCH64_OPND_CLASS_SIMD_ELEMENT, "Ed", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rd}, "a SIMD vector element"}, + {AARCH64_OPND_CLASS_SIMD_ELEMENT, "En", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn}, "a SIMD vector element"}, + {AARCH64_OPND_CLASS_SIMD_ELEMENT, "Em", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rm}, "a SIMD vector element"}, + {AARCH64_OPND_CLASS_SIMD_REGLIST, "LVn", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn}, "a SIMD vector register list"}, + {AARCH64_OPND_CLASS_SIMD_REGLIST, "LVt", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a SIMD vector register list"}, + {AARCH64_OPND_CLASS_SIMD_REGLIST, "LVt_AL", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a SIMD vector register list"}, + {AARCH64_OPND_CLASS_SIMD_REGLIST, "LEt", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a SIMD vector element list"}, + {AARCH64_OPND_CLASS_CP_REG, "Cn", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_CRn}, "a 4-bit opcode field named for historical reasons C0 - C15"}, + {AARCH64_OPND_CLASS_CP_REG, "Cm", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_CRm}, "a 4-bit opcode field named for historical reasons C0 - C15"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "IDX", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm4}, "an immediate as the index of the least significant byte"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "IMM_VLSL", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a left shift amount for an AdvSIMD register"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "IMM_VLSR", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a right shift amount for an AdvSIMD register"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "SIMD_IMM", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "an immediate"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "SIMD_IMM_SFT", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "an 8-bit unsigned immediate with optional shift"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "SIMD_FPIMM", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "an 8-bit floating-point constant"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "SHLL_IMM", OPD_F_HAS_EXTRACTOR, {}, "an immediate shift amount of 8, 16 or 32"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "IMM0", 0, {}, "0"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "FPIMM0", 0, {}, "0.0"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "FPIMM", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm8}, "an 8-bit floating-point constant"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "IMMR", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_immr}, "the right rotate amount"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "IMMS", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm6}, "the leftmost bit number to be moved from the source"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "WIDTH", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm6}, "the width of the bit-field"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "IMM", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm6}, "an immediate"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "UIMM3_OP1", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_op1}, "a 3-bit unsigned immediate"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "UIMM3_OP2", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_op2}, "a 3-bit unsigned immediate"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "UIMM4", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_CRm}, "a 4-bit unsigned immediate"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "UIMM7", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_CRm, FLD_op2}, "a 7-bit unsigned immediate"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "BIT_NUM", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_b5, FLD_b40}, "the bit number to be tested"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "EXCEPTION", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm16}, "a 16-bit unsigned immediate"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "CCMP_IMM", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm5}, "a 5-bit unsigned immediate"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "NZCV", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_nzcv}, "a flag bit specifier giving an alternative value for each flag"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "LIMM", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_N,FLD_immr,FLD_imms}, "Logical immediate"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "AIMM", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_shift,FLD_imm12}, "a 12-bit unsigned immediate with optional left shift of 12 bits"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "HALF", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm16}, "a 16-bit immediate with optional left shift"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "FBITS", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_scale}, "the number of bits after the binary point in the fixed-point value"}, + {AARCH64_OPND_CLASS_IMMEDIATE, "IMM_MOV", 0, {}, "an immediate"}, + {AARCH64_OPND_CLASS_NIL, "COND", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a condition"}, + {AARCH64_OPND_CLASS_ADDRESS, "ADDR_ADRP", OPD_F_SEXT | OPD_F_HAS_EXTRACTOR, {FLD_immhi, FLD_immlo}, "21-bit PC-relative address of a 4KB page"}, + {AARCH64_OPND_CLASS_ADDRESS, "ADDR_PCREL14", OPD_F_SEXT | OPD_F_SHIFT_BY_2 | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm14}, "14-bit PC-relative address"}, + {AARCH64_OPND_CLASS_ADDRESS, "ADDR_PCREL19", OPD_F_SEXT | OPD_F_SHIFT_BY_2 | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm19}, "19-bit PC-relative address"}, + {AARCH64_OPND_CLASS_ADDRESS, "ADDR_PCREL21", OPD_F_SEXT | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_immhi,FLD_immlo}, "21-bit PC-relative address"}, + {AARCH64_OPND_CLASS_ADDRESS, "ADDR_PCREL26", OPD_F_SEXT | OPD_F_SHIFT_BY_2 | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm26}, "26-bit PC-relative address"}, + {AARCH64_OPND_CLASS_ADDRESS, "ADDR_SIMPLE", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "an address with base register (no offset)"}, + {AARCH64_OPND_CLASS_ADDRESS, "ADDR_REGOFF", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "an address with register offset"}, + {AARCH64_OPND_CLASS_ADDRESS, "ADDR_SIMM7", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm7,FLD_index2}, "an address with 7-bit signed immediate offset"}, + {AARCH64_OPND_CLASS_ADDRESS, "ADDR_SIMM9", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm9,FLD_index}, "an address with 9-bit signed immediate offset"}, + {AARCH64_OPND_CLASS_ADDRESS, "ADDR_SIMM9_2", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm9,FLD_index}, "an address with 9-bit negative or unaligned immediate offset"}, + {AARCH64_OPND_CLASS_ADDRESS, "ADDR_UIMM12", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_imm12}, "an address with scaled, unsigned immediate offset"}, + {AARCH64_OPND_CLASS_ADDRESS, "SIMD_ADDR_SIMPLE", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "an address with base register (no offset)"}, + {AARCH64_OPND_CLASS_ADDRESS, "SIMD_ADDR_POST", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a post-indexed address with immediate or register increment"}, + {AARCH64_OPND_CLASS_SYSTEM, "SYSREG", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a system register"}, + {AARCH64_OPND_CLASS_SYSTEM, "PSTATEFIELD", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a PSTATE field name"}, + {AARCH64_OPND_CLASS_SYSTEM, "SYSREG_AT", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "an address translation operation specifier"}, + {AARCH64_OPND_CLASS_SYSTEM, "SYSREG_DC", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a data cache maintenance operation specifier"}, + {AARCH64_OPND_CLASS_SYSTEM, "SYSREG_IC", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "an instructin cache maintenance operation specifier"}, + {AARCH64_OPND_CLASS_SYSTEM, "SYSREG_TLBI", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a TBL invalidation operation specifier"}, + {AARCH64_OPND_CLASS_SYSTEM, "BARRIER", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a barrier option name"}, + {AARCH64_OPND_CLASS_SYSTEM, "BARRIER_ISB", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "the ISB option name SY or an optional 4-bit unsigned immediate"}, + {AARCH64_OPND_CLASS_SYSTEM, "PRFOP", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "an prefetch operation specifier"}, + {AARCH64_OPND_CLASS_NIL, "", 0, {0}, "DUMMY"}, +}; + +/* Indexed by an enum aarch64_op enumerator, the value is the offset of + the corresponding aarch64_opcode entry in the aarch64_opcode_table. */ + +static const unsigned op_enum_table [] = +{ + 0, + 648, + 649, + 650, + 653, + 654, + 655, + 656, + 657, + 651, + 652, + 658, + 659, + 681, + 682, + 685, + 691, + 692, + 695, + 697, + 698, + 687, + 688, + 701, + 703, + 741, + 742, + 743, + 744, + 12, + 506, + 507, + 764, + 766, + 768, + 748, + 767, + 765, + 259, + 495, + 505, + 504, + 746, + 501, + 498, + 491, + 490, + 497, + 500, + 502, + 503, + 756, + 125, + 522, + 525, + 528, + 523, + 526, + 614, + 160, + 161, + 162, + 163, + 416, + 583, +}; + +/* Given the opcode enumerator OP, return the pointer to the corresponding + opcode entry. */ + +const aarch64_opcode * +aarch64_get_opcode (enum aarch64_op op) +{ + return aarch64_opcode_table + op_enum_table[op]; +} diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c new file mode 100644 index 0000000..2d66a25 --- /dev/null +++ b/opcodes/aarch64-opc.c @@ -0,0 +1,3074 @@ +/* aarch64-opc.c -- AArch64 opcode support. + Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING3. If not, + see <http://www.gnu.org/licenses/>. */ + +#include "sysdep.h" +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <inttypes.h> + +#include "opintl.h" + +#include "aarch64-opc.h" + +#ifdef DEBUG_AARCH64 +int debug_dump = FALSE; +#endif /* DEBUG_AARCH64 */ + +/* Helper functions to determine which operand to be used to encode/decode + the size:Q fields for AdvSIMD instructions. */ + +static inline bfd_boolean +vector_qualifier_p (enum aarch64_opnd_qualifier qualifier) +{ + return ((qualifier >= AARCH64_OPND_QLF_V_8B + && qualifier <= AARCH64_OPND_QLF_V_1Q) ? TRUE + : FALSE); +} + +static inline bfd_boolean +fp_qualifier_p (enum aarch64_opnd_qualifier qualifier) +{ + return ((qualifier >= AARCH64_OPND_QLF_S_B + && qualifier <= AARCH64_OPND_QLF_S_Q) ? TRUE + : FALSE); +} + +enum data_pattern +{ + DP_UNKNOWN, + DP_VECTOR_3SAME, + DP_VECTOR_LONG, + DP_VECTOR_WIDE, + DP_VECTOR_ACROSS_LANES, +}; + +static const char significant_operand_index [] = +{ + 0, /* DP_UNKNOWN, by default using operand 0. */ + 0, /* DP_VECTOR_3SAME */ + 1, /* DP_VECTOR_LONG */ + 2, /* DP_VECTOR_WIDE */ + 1, /* DP_VECTOR_ACROSS_LANES */ +}; + +/* Given a sequence of qualifiers in QUALIFIERS, determine and return + the data pattern. + N.B. QUALIFIERS is a possible sequence of qualifiers each of which + corresponds to one of a sequence of operands. */ + +static enum data_pattern +get_data_pattern (const aarch64_opnd_qualifier_seq_t qualifiers) +{ + if (vector_qualifier_p (qualifiers[0]) == TRUE) + { + /* e.g. v.4s, v.4s, v.4s + or v.4h, v.4h, v.h[3]. */ + if (qualifiers[0] == qualifiers[1] + && vector_qualifier_p (qualifiers[2]) == TRUE + && (aarch64_get_qualifier_esize (qualifiers[0]) + == aarch64_get_qualifier_esize (qualifiers[1])) + && (aarch64_get_qualifier_esize (qualifiers[0]) + == aarch64_get_qualifier_esize (qualifiers[2]))) + return DP_VECTOR_3SAME; + /* e.g. v.8h, v.8b, v.8b. + or v.4s, v.4h, v.h[2]. + or v.8h, v.16b. */ + if (vector_qualifier_p (qualifiers[1]) == TRUE + && aarch64_get_qualifier_esize (qualifiers[0]) != 0 + && (aarch64_get_qualifier_esize (qualifiers[0]) + == aarch64_get_qualifier_esize (qualifiers[1]) << 1)) + return DP_VECTOR_LONG; + /* e.g. v.8h, v.8h, v.8b. */ + if (qualifiers[0] == qualifiers[1] + && vector_qualifier_p (qualifiers[2]) == TRUE + && aarch64_get_qualifier_esize (qualifiers[0]) != 0 + && (aarch64_get_qualifier_esize (qualifiers[0]) + == aarch64_get_qualifier_esize (qualifiers[2]) << 1) + && (aarch64_get_qualifier_esize (qualifiers[0]) + == aarch64_get_qualifier_esize (qualifiers[1]))) + return DP_VECTOR_WIDE; + } + else if (fp_qualifier_p (qualifiers[0]) == TRUE) + { + /* e.g. SADDLV <V><d>, <Vn>.<T>. */ + if (vector_qualifier_p (qualifiers[1]) == TRUE + && qualifiers[2] == AARCH64_OPND_QLF_NIL) + return DP_VECTOR_ACROSS_LANES; + } + + return DP_UNKNOWN; +} + +/* Select the operand to do the encoding/decoding of the 'size:Q' fields in + the AdvSIMD instructions. */ +/* N.B. it is possible to do some optimization that doesn't call + get_data_pattern each time when we need to select an operand. We can + either buffer the caculated the result or statically generate the data, + however, it is not obvious that the optimization will bring significant + benefit. */ + +int +aarch64_select_operand_for_sizeq_field_coding (const aarch64_opcode *opcode) +{ + return + significant_operand_index [get_data_pattern (opcode->qualifiers_list[0])]; +} + +const aarch64_field fields[] = +{ + { 0, 0 }, /* NIL. */ + { 0, 4 }, /* cond2: condition in truly conditional-executed inst. */ + { 0, 4 }, /* nzcv: flag bit specifier, encoded in the "nzcv" field. */ + { 5, 5 }, /* defgh: d:e:f:g:h bits in AdvSIMD modified immediate. */ + { 16, 3 }, /* abc: a:b:c bits in AdvSIMD modified immediate. */ + { 5, 19 }, /* imm19: e.g. in CBZ. */ + { 5, 19 }, /* immhi: e.g. in ADRP. */ + { 29, 2 }, /* immlo: e.g. in ADRP. */ + { 22, 2 }, /* size: in most AdvSIMD and floating-point instructions. */ + { 10, 2 }, /* vldst_size: size field in the AdvSIMD load/store inst. */ + { 29, 1 }, /* op: in AdvSIMD modified immediate instructions. */ + { 30, 1 }, /* Q: in most AdvSIMD instructions. */ + { 0, 5 }, /* Rt: in load/store instructions. */ + { 0, 5 }, /* Rd: in many integer instructions. */ + { 5, 5 }, /* Rn: in many integer instructions. */ + { 10, 5 }, /* Rt2: in load/store pair instructions. */ + { 10, 5 }, /* Ra: in fp instructions. */ + { 5, 3 }, /* op2: in the system instructions. */ + { 8, 4 }, /* CRm: in the system instructions. */ + { 12, 4 }, /* CRn: in the system instructions. */ + { 16, 3 }, /* op1: in the system instructions. */ + { 19, 2 }, /* op0: in the system instructions. */ + { 10, 3 }, /* imm3: in add/sub extended reg instructions. */ + { 12, 4 }, /* cond: condition flags as a source operand. */ + { 12, 4 }, /* opcode: in advsimd load/store instructions. */ + { 12, 4 }, /* cmode: in advsimd modified immediate instructions. */ + { 13, 3 }, /* asisdlso_opcode: opcode in advsimd ld/st single element. */ + { 13, 2 }, /* len: in advsimd tbl/tbx instructions. */ + { 16, 5 }, /* Rm: in ld/st reg offset and some integer inst. */ + { 16, 5 }, /* Rs: in load/store exclusive instructions. */ + { 13, 3 }, /* option: in ld/st reg offset + add/sub extended reg inst. */ + { 12, 1 }, /* S: in load/store reg offset instructions. */ + { 21, 2 }, /* hw: in move wide constant instructions. */ + { 22, 2 }, /* opc: in load/store reg offset instructions. */ + { 23, 1 }, /* opc1: in load/store reg offset instructions. */ + { 22, 2 }, /* shift: in add/sub reg/imm shifted instructions. */ + { 22, 2 }, /* type: floating point type field in fp data inst. */ + { 30, 2 }, /* ldst_size: size field in ld/st reg offset inst. */ + { 10, 6 }, /* imm6: in add/sub reg shifted instructions. */ + { 11, 4 }, /* imm4: in advsimd ext and advsimd ins instructions. */ + { 16, 5 }, /* imm5: in conditional compare (immediate) instructions. */ + { 15, 7 }, /* imm7: in load/store pair pre/post index instructions. */ + { 13, 8 }, /* imm8: in floating-point scalar move immediate inst. */ + { 12, 9 }, /* imm9: in load/store pre/post index instructions. */ + { 10, 12 }, /* imm12: in ld/st unsigned imm or add/sub shifted inst. */ + { 5, 14 }, /* imm14: in test bit and branch instructions. */ + { 5, 16 }, /* imm16: in exception instructions. */ + { 0, 26 }, /* imm26: in unconditional branch instructions. */ + { 10, 6 }, /* imms: in bitfield and logical immediate instructions. */ + { 16, 6 }, /* immr: in bitfield and logical immediate instructions. */ + { 16, 3 }, /* immb: in advsimd shift by immediate instructions. */ + { 19, 4 }, /* immh: in advsimd shift by immediate instructions. */ + { 22, 1 }, /* N: in logical (immediate) instructions. */ + { 11, 1 }, /* index: in ld/st inst deciding the pre/post-index. */ + { 24, 1 }, /* index2: in ld/st pair inst deciding the pre/post-index. */ + { 31, 1 }, /* sf: in integer data processing instructions. */ + { 11, 1 }, /* H: in advsimd scalar x indexed element instructions. */ + { 21, 1 }, /* L: in advsimd scalar x indexed element instructions. */ + { 20, 1 }, /* M: in advsimd scalar x indexed element instructions. */ + { 31, 1 }, /* b5: in the test bit and branch instructions. */ + { 19, 5 }, /* b40: in the test bit and branch instructions. */ + { 10, 6 }, /* scale: in the fixed-point scalar to fp converting inst. */ +}; + +enum aarch64_operand_class +aarch64_get_operand_class (enum aarch64_opnd type) +{ + return aarch64_operands[type].op_class; +} + +const char * +aarch64_get_operand_name (enum aarch64_opnd type) +{ + return aarch64_operands[type].name; +} + +/* Get operand description string. + This is usually for the diagnosis purpose. */ +const char * +aarch64_get_operand_desc (enum aarch64_opnd type) +{ + return aarch64_operands[type].desc; +} + +/* Table of all conditional affixes. */ +const aarch64_cond aarch64_conds[16] = +{ + {{"eq"}, 0x0}, + {{"ne"}, 0x1}, + {{"cs", "hs"}, 0x2}, + {{"cc", "lo", "ul"}, 0x3}, + {{"mi"}, 0x4}, + {{"pl"}, 0x5}, + {{"vs"}, 0x6}, + {{"vc"}, 0x7}, + {{"hi"}, 0x8}, + {{"ls"}, 0x9}, + {{"ge"}, 0xa}, + {{"lt"}, 0xb}, + {{"gt"}, 0xc}, + {{"le"}, 0xd}, + {{"al"}, 0xe}, + {{"nv"}, 0xf}, +}; + +const aarch64_cond * +get_cond_from_value (aarch64_insn value) +{ + assert (value < 16); + return &aarch64_conds[(unsigned int) value]; +} + +const aarch64_cond * +get_inverted_cond (const aarch64_cond *cond) +{ + return &aarch64_conds[cond->value ^ 0x1]; +} + +/* Table describing the operand extension/shifting operators; indexed by + enum aarch64_modifier_kind. + + The value column provides the most common values for encoding modifiers, + which enables table-driven encoding/decoding for the modifiers. */ +const struct aarch64_name_value_pair aarch64_operand_modifiers [] = +{ + {"none", 0x0}, + {"msl", 0x0}, + {"ror", 0x3}, + {"asr", 0x2}, + {"lsr", 0x1}, + {"lsl", 0x0}, + {"uxtb", 0x0}, + {"uxth", 0x1}, + {"uxtw", 0x2}, + {"uxtx", 0x3}, + {"sxtb", 0x4}, + {"sxth", 0x5}, + {"sxtw", 0x6}, + {"sxtx", 0x7}, + {NULL, 0}, +}; + +enum aarch64_modifier_kind +aarch64_get_operand_modifier (const struct aarch64_name_value_pair *desc) +{ + return desc - aarch64_operand_modifiers; +} + +aarch64_insn +aarch64_get_operand_modifier_value (enum aarch64_modifier_kind kind) +{ + return aarch64_operand_modifiers[kind].value; +} + +enum aarch64_modifier_kind +aarch64_get_operand_modifier_from_value (aarch64_insn value, + bfd_boolean extend_p) +{ + if (extend_p == TRUE) + return AARCH64_MOD_UXTB + value; + else + return AARCH64_MOD_LSL - value; +} + +bfd_boolean +aarch64_extend_operator_p (enum aarch64_modifier_kind kind) +{ + return (kind > AARCH64_MOD_LSL && kind <= AARCH64_MOD_SXTX) + ? TRUE : FALSE; +} + +static inline bfd_boolean +aarch64_shift_operator_p (enum aarch64_modifier_kind kind) +{ + return (kind >= AARCH64_MOD_ROR && kind <= AARCH64_MOD_LSL) + ? TRUE : FALSE; +} + +const struct aarch64_name_value_pair aarch64_barrier_options[16] = +{ + { "#0x00", 0x0 }, + { "oshld", 0x1 }, + { "oshst", 0x2 }, + { "osh", 0x3 }, + { "#0x04", 0x4 }, + { "nshld", 0x5 }, + { "nshst", 0x6 }, + { "nsh", 0x7 }, + { "#0x08", 0x8 }, + { "ishld", 0x9 }, + { "ishst", 0xa }, + { "ish", 0xb }, + { "#0x0c", 0xc }, + { "ld", 0xd }, + { "st", 0xe }, + { "sy", 0xf }, +}; + +/* op -> op: load = 0 store = 1 + l -> level: 1-3 + t -> temporal: temporal (retained) = 0 non-temporal (streaming) = 1 */ +#define B(op,l,t) ((((op) * 2) << 3) | (((l) - 1) << 1) | (t)) +const struct aarch64_name_value_pair aarch64_prfops[32] = +{ + { "pldl1keep", B(0, 1, 0) }, + { "pldl1strm", B(0, 1, 1) }, + { "pldl2keep", B(0, 2, 0) }, + { "pldl2strm", B(0, 2, 1) }, + { "pldl3keep", B(0, 3, 0) }, + { "pldl3strm", B(0, 3, 1) }, + { "#0x06", 0x06 }, + { "#0x07", 0x07 }, + { "#0x08", 0x08 }, + { "#0x09", 0x09 }, + { "#0x0a", 0x0a }, + { "#0x0b", 0x0b }, + { "#0x0c", 0x0c }, + { "#0x0d", 0x0d }, + { "#0x0e", 0x0e }, + { "#0x0f", 0x0f }, + { "pstl1keep", B(1, 1, 0) }, + { "pstl1strm", B(1, 1, 1) }, + { "pstl2keep", B(1, 2, 0) }, + { "pstl2strm", B(1, 2, 1) }, + { "pstl3keep", B(1, 3, 0) }, + { "pstl3strm", B(1, 3, 1) }, + { "#0x16", 0x16 }, + { "#0x17", 0x17 }, + { "#0x18", 0x18 }, + { "#0x19", 0x19 }, + { "#0x1a", 0x1a }, + { "#0x1b", 0x1b }, + { "#0x1c", 0x1c }, + { "#0x1d", 0x1d }, + { "#0x1e", 0x1e }, + { "#0x1f", 0x1f }, +}; +#undef B + +/* Utilities on value constraint. */ + +static inline int +value_in_range_p (int64_t value, int low, int high) +{ + return (value >= low && value <= high) ? 1 : 0; +} + +static inline int +value_aligned_p (int64_t value, int align) +{ + return ((value & (align - 1)) == 0) ? 1 : 0; +} + +/* A signed value fits in a field. */ +static inline int +value_fit_signed_field_p (int64_t value, unsigned width) +{ + assert (width < 32); + if (width < sizeof (value) * 8) + { + int64_t lim = (int64_t)1 << (width - 1); + if (value >= -lim && value < lim) + return 1; + } + return 0; +} + +/* An unsigned value fits in a field. */ +static inline int +value_fit_unsigned_field_p (int64_t value, unsigned width) +{ + assert (width < 32); + if (width < sizeof (value) * 8) + { + int64_t lim = (int64_t)1 << width; + if (value >= 0 && value < lim) + return 1; + } + return 0; +} + +/* Return 1 if OPERAND is SP or WSP. */ +int +aarch64_stack_pointer_p (const aarch64_opnd_info *operand) +{ + return ((aarch64_get_operand_class (operand->type) + == AARCH64_OPND_CLASS_INT_REG) + && operand_maybe_stack_pointer (aarch64_operands + operand->type) + && operand->reg.regno == 31); +} + +/* Return 1 if OPERAND is XZR or WZP. */ +int +aarch64_zero_register_p (const aarch64_opnd_info *operand) +{ + return ((aarch64_get_operand_class (operand->type) + == AARCH64_OPND_CLASS_INT_REG) + && !operand_maybe_stack_pointer (aarch64_operands + operand->type) + && operand->reg.regno == 31); +} + +/* Return true if the operand *OPERAND that has the operand code + OPERAND->TYPE and been qualified by OPERAND->QUALIFIER can be also + qualified by the qualifier TARGET. */ + +static inline int +operand_also_qualified_p (const struct aarch64_opnd_info *operand, + aarch64_opnd_qualifier_t target) +{ + switch (operand->qualifier) + { + case AARCH64_OPND_QLF_W: + if (target == AARCH64_OPND_QLF_WSP && aarch64_stack_pointer_p (operand)) + return 1; + break; + case AARCH64_OPND_QLF_X: + if (target == AARCH64_OPND_QLF_SP && aarch64_stack_pointer_p (operand)) + return 1; + break; + case AARCH64_OPND_QLF_WSP: + if (target == AARCH64_OPND_QLF_W + && operand_maybe_stack_pointer (aarch64_operands + operand->type)) + return 1; + break; + case AARCH64_OPND_QLF_SP: + if (target == AARCH64_OPND_QLF_X + && operand_maybe_stack_pointer (aarch64_operands + operand->type)) + return 1; + break; + default: + break; + } + + return 0; +} + +/* Given qualifier sequence list QSEQ_LIST and the known qualifier KNOWN_QLF + for operand KNOWN_IDX, return the expected qualifier for operand IDX. + + Return NIL if more than one expected qualifiers are found. */ + +aarch64_opnd_qualifier_t +aarch64_get_expected_qualifier (const aarch64_opnd_qualifier_seq_t *qseq_list, + int idx, + const aarch64_opnd_qualifier_t known_qlf, + int known_idx) +{ + int i, saved_i; + + /* Special case. + + When the known qualifier is NIL, we have to assume that there is only + one qualifier sequence in the *QSEQ_LIST and return the corresponding + qualifier directly. One scenario is that for instruction + PRFM <prfop>, [<Xn|SP>, #:lo12:<symbol>] + which has only one possible valid qualifier sequence + NIL, S_D + the caller may pass NIL in KNOWN_QLF to obtain S_D so that it can + determine the correct relocation type (i.e. LDST64_LO12) for PRFM. + + Because the qualifier NIL has dual roles in the qualifier sequence: + it can mean no qualifier for the operand, or the qualifer sequence is + not in use (when all qualifiers in the sequence are NILs), we have to + handle this special case here. */ + if (known_qlf == AARCH64_OPND_NIL) + { + assert (qseq_list[0][known_idx] == AARCH64_OPND_NIL); + return qseq_list[0][idx]; + } + + for (i = 0, saved_i = -1; i < AARCH64_MAX_QLF_SEQ_NUM; ++i) + { + if (qseq_list[i][known_idx] == known_qlf) + { + if (saved_i != -1) + /* More than one sequences are found to have KNOWN_QLF at + KNOWN_IDX. */ + return AARCH64_OPND_NIL; + saved_i = i; + } + } + + return qseq_list[saved_i][idx]; +} + +enum operand_qualifier_kind +{ + OQK_NIL, + OQK_OPD_VARIANT, + OQK_VALUE_IN_RANGE, + OQK_MISC, +}; + +/* Operand qualifier description. */ +struct operand_qualifier_data +{ + /* The usage of the three data fields depends on the qualifier kind. */ + int data0; + int data1; + int data2; + /* Description. */ + const char *desc; + /* Kind. */ + enum operand_qualifier_kind kind; +}; + +/* Indexed by the operand qualifier enumerators. */ +struct operand_qualifier_data aarch64_opnd_qualifiers[] = +{ + {0, 0, 0, "NIL", OQK_NIL}, + + /* Operand variant qualifiers. + First 3 fields: + element size, number of elements and common value for encoding. */ + + {4, 1, 0x0, "w", OQK_OPD_VARIANT}, + {8, 1, 0x1, "x", OQK_OPD_VARIANT}, + {4, 1, 0x0, "wsp", OQK_OPD_VARIANT}, + {8, 1, 0x1, "sp", OQK_OPD_VARIANT}, + + {1, 1, 0x0, "b", OQK_OPD_VARIANT}, + {2, 1, 0x1, "h", OQK_OPD_VARIANT}, + {4, 1, 0x2, "s", OQK_OPD_VARIANT}, + {8, 1, 0x3, "d", OQK_OPD_VARIANT}, + {16, 1, 0x4, "q", OQK_OPD_VARIANT}, + + {1, 8, 0x0, "8b", OQK_OPD_VARIANT}, + {1, 16, 0x1, "16b", OQK_OPD_VARIANT}, + {2, 4, 0x2, "4h", OQK_OPD_VARIANT}, + {2, 8, 0x3, "8h", OQK_OPD_VARIANT}, + {4, 2, 0x4, "2s", OQK_OPD_VARIANT}, + {4, 4, 0x5, "4s", OQK_OPD_VARIANT}, + {8, 1, 0x6, "1d", OQK_OPD_VARIANT}, + {8, 2, 0x7, "2d", OQK_OPD_VARIANT}, + {16, 1, 0x8, "1q", OQK_OPD_VARIANT}, + + /* Qualifiers constraining the value range. + First 3 fields: + Lower bound, higher bound, unused. */ + + {0, 7, 0, "imm_0_7" , OQK_VALUE_IN_RANGE}, + {0, 15, 0, "imm_0_15", OQK_VALUE_IN_RANGE}, + {0, 31, 0, "imm_0_31", OQK_VALUE_IN_RANGE}, + {0, 63, 0, "imm_0_63", OQK_VALUE_IN_RANGE}, + {1, 32, 0, "imm_1_32", OQK_VALUE_IN_RANGE}, + {1, 64, 0, "imm_1_64", OQK_VALUE_IN_RANGE}, + + /* Qualifiers for miscellaneous purpose. + First 3 fields: + unused, unused and unused. */ + + {0, 0, 0, "lsl", 0}, + {0, 0, 0, "msl", 0}, + + {0, 0, 0, "retrieving", 0}, +}; + +static inline bfd_boolean +operand_variant_qualifier_p (aarch64_opnd_qualifier_t qualifier) +{ + return (aarch64_opnd_qualifiers[qualifier].kind == OQK_OPD_VARIANT) + ? TRUE : FALSE; +} + +static inline bfd_boolean +qualifier_value_in_range_constraint_p (aarch64_opnd_qualifier_t qualifier) +{ + return (aarch64_opnd_qualifiers[qualifier].kind == OQK_VALUE_IN_RANGE) + ? TRUE : FALSE; +} + +const char* +aarch64_get_qualifier_name (aarch64_opnd_qualifier_t qualifier) +{ + return aarch64_opnd_qualifiers[qualifier].desc; +} + +/* Given an operand qualifier, return the expected data element size + of a qualified operand. */ +unsigned char +aarch64_get_qualifier_esize (aarch64_opnd_qualifier_t qualifier) +{ + assert (operand_variant_qualifier_p (qualifier) == TRUE); + return aarch64_opnd_qualifiers[qualifier].data0; +} + +unsigned char +aarch64_get_qualifier_nelem (aarch64_opnd_qualifier_t qualifier) +{ + assert (operand_variant_qualifier_p (qualifier) == TRUE); + return aarch64_opnd_qualifiers[qualifier].data1; +} + +aarch64_insn +aarch64_get_qualifier_standard_value (aarch64_opnd_qualifier_t qualifier) +{ + assert (operand_variant_qualifier_p (qualifier) == TRUE); + return aarch64_opnd_qualifiers[qualifier].data2; +} + +static int +get_lower_bound (aarch64_opnd_qualifier_t qualifier) +{ + assert (qualifier_value_in_range_constraint_p (qualifier) == TRUE); + return aarch64_opnd_qualifiers[qualifier].data0; +} + +static int +get_upper_bound (aarch64_opnd_qualifier_t qualifier) +{ + assert (qualifier_value_in_range_constraint_p (qualifier) == TRUE); + return aarch64_opnd_qualifiers[qualifier].data1; +} + +#ifdef DEBUG_AARCH64 +void +aarch64_verbose (const char *str, ...) +{ + va_list ap; + va_start (ap, str); + printf ("#### "); + vprintf (str, ap); + printf ("\n"); + va_end (ap); +} + +static inline void +dump_qualifier_sequence (const aarch64_opnd_qualifier_t *qualifier) +{ + int i; + printf ("#### \t"); + for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i, ++qualifier) + printf ("%s,", aarch64_get_qualifier_name (*qualifier)); + printf ("\n"); +} + +static void +dump_match_qualifiers (const struct aarch64_opnd_info *opnd, + const aarch64_opnd_qualifier_t *qualifier) +{ + int i; + aarch64_opnd_qualifier_t curr[AARCH64_MAX_OPND_NUM]; + + aarch64_verbose ("dump_match_qualifiers:"); + for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i) + curr[i] = opnd[i].qualifier; + dump_qualifier_sequence (curr); + aarch64_verbose ("against"); + dump_qualifier_sequence (qualifier); +} +#endif /* DEBUG_AARCH64 */ + +/* TODO improve this, we can have an extra field at the runtime to + store the number of operands rather than calculating it every time. */ + +int +aarch64_num_of_operands (const aarch64_opcode *opcode) +{ + int i = 0; + const enum aarch64_opnd *opnds = opcode->operands; + while (opnds[i++] != AARCH64_OPND_NIL) + ; + --i; + assert (i >= 0 && i <= AARCH64_MAX_OPND_NUM); + return i; +} + +/* Find the best matched qualifier sequence in *QUALIFIERS_LIST for INST. + If succeeds, fill the found sequence in *RET, return 1; otherwise return 0. + + N.B. on the entry, it is very likely that only some operands in *INST + have had their qualifiers been established. + + If STOP_AT is not -1, the function will only try to match + the qualifier sequence for operands before and including the operand + of index STOP_AT; and on success *RET will only be filled with the first + (STOP_AT+1) qualifiers. + + A couple examples of the matching algorithm: + + X,W,NIL should match + X,W,NIL + + NIL,NIL should match + X ,NIL + + Apart from serving the main encoding routine, this can also be called + during or after the operand decoding. */ + +int +aarch64_find_best_match (const aarch64_inst *inst, + const aarch64_opnd_qualifier_seq_t *qualifiers_list, + int stop_at, aarch64_opnd_qualifier_t *ret) +{ + int found = 0; + int i, num_opnds; + const aarch64_opnd_qualifier_t *qualifiers; + + num_opnds = aarch64_num_of_operands (inst->opcode); + if (num_opnds == 0) + { + DEBUG_TRACE ("SUCCEED: no operand"); + return 1; + } + + if (stop_at < 0 || stop_at >= num_opnds) + stop_at = num_opnds - 1; + + /* For each pattern. */ + for (i = 0; i < AARCH64_MAX_QLF_SEQ_NUM; ++i, ++qualifiers_list) + { + int j; + qualifiers = *qualifiers_list; + + /* Start as positive. */ + found = 1; + + DEBUG_TRACE ("%d", i); +#ifdef DEBUG_AARCH64 + if (debug_dump) + dump_match_qualifiers (inst->operands, qualifiers); +#endif + + /* Most opcodes has much fewer patterns in the list. + First NIL qualifier indicates the end in the list. */ + if (empty_qualifier_sequence_p (qualifiers) == TRUE) + { + DEBUG_TRACE_IF (i == 0, "SUCCEED: empty qualifier list"); + if (i) + found = 0; + break; + } + + for (j = 0; j < num_opnds && j <= stop_at; ++j, ++qualifiers) + { + if (inst->operands[j].qualifier == AARCH64_OPND_QLF_NIL) + { + /* Either the operand does not have qualifier, or the qualifier + for the operand needs to be deduced from the qualifier + sequence. + In the latter case, any constraint checking related with + the obtained qualifier should be done later in + operand_general_constraint_met_p. */ + continue; + } + else if (*qualifiers != inst->operands[j].qualifier) + { + /* Unless the target qualifier can also qualify the operand + (which has already had a non-nil qualifier), non-equal + qualifiers are generally un-matched. */ + if (operand_also_qualified_p (inst->operands + j, *qualifiers)) + continue; + else + { + found = 0; + break; + } + } + else + continue; /* Equal qualifiers are certainly matched. */ + } + + /* Qualifiers established. */ + if (found == 1) + break; + } + + if (found == 1) + { + /* Fill the result in *RET. */ + int j; + qualifiers = *qualifiers_list; + + DEBUG_TRACE ("complete qualifiers using list %d", i); +#ifdef DEBUG_AARCH64 + if (debug_dump) + dump_qualifier_sequence (qualifiers); +#endif + + for (j = 0; j <= stop_at; ++j, ++qualifiers) + ret[j] = *qualifiers; + for (; j < AARCH64_MAX_OPND_NUM; ++j) + ret[j] = AARCH64_OPND_QLF_NIL; + + DEBUG_TRACE ("SUCCESS"); + return 1; + } + + DEBUG_TRACE ("FAIL"); + return 0; +} + +/* Operand qualifier matching and resolving. + + Return 1 if the operand qualifier(s) in *INST match one of the qualifier + sequences in INST->OPCODE->qualifiers_list; otherwise return 0. + + if UPDATE_P == TRUE, update the qualifier(s) in *INST after the matching + succeeds. */ + +static int +match_operands_qualifier (aarch64_inst *inst, bfd_boolean update_p) +{ + int i; + aarch64_opnd_qualifier_seq_t qualifiers; + + if (!aarch64_find_best_match (inst, inst->opcode->qualifiers_list, -1, + qualifiers)) + { + DEBUG_TRACE ("matching FAIL"); + return 0; + } + + /* Update the qualifiers. */ + if (update_p == TRUE) + for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i) + { + if (inst->opcode->operands[i] == AARCH64_OPND_NIL) + break; + DEBUG_TRACE_IF (inst->operands[i].qualifier != qualifiers[i], + "update %s with %s for operand %d", + aarch64_get_qualifier_name (inst->operands[i].qualifier), + aarch64_get_qualifier_name (qualifiers[i]), i); + inst->operands[i].qualifier = qualifiers[i]; + } + + DEBUG_TRACE ("matching SUCCESS"); + return 1; +} + +/* Return TRUE if VALUE is a wide constant that can be moved into a general + register by MOVZ. + + IS32 indicates whether value is a 32-bit immediate or not. + If SHIFT_AMOUNT is not NULL, on the return of TRUE, the logical left shift + amount will be returned in *SHIFT_AMOUNT. */ + +bfd_boolean +aarch64_wide_constant_p (int64_t value, int is32, unsigned int *shift_amount) +{ + int amount; + + DEBUG_TRACE ("enter with 0x%" PRIx64 "(%" PRIi64 ")", value, value); + + if (is32) + { + /* Allow all zeros or all ones in top 32-bits, so that + 32-bit constant expressions like ~0x80000000 are + permitted. */ + uint64_t ext = value; + if (ext >> 32 != 0 && ext >> 32 != (uint64_t) 0xffffffff) + /* Immediate out of range. */ + return FALSE; + value &= (int64_t) 0xffffffff; + } + + /* first, try movz then movn */ + amount = -1; + if ((value & ((int64_t) 0xffff << 0)) == value) + amount = 0; + else if ((value & ((int64_t) 0xffff << 16)) == value) + amount = 16; + else if (!is32 && (value & ((int64_t) 0xffff << 32)) == value) + amount = 32; + else if (!is32 && (value & ((int64_t) 0xffff << 48)) == value) + amount = 48; + + if (amount == -1) + { + DEBUG_TRACE ("exit FALSE with 0x%" PRIx64 "(%" PRIi64 ")", value, value); + return FALSE; + } + + if (shift_amount != NULL) + *shift_amount = amount; + + DEBUG_TRACE ("exit TRUE with amount %d", amount); + + return TRUE; +} + +/* Build the accepted values for immediate logical SIMD instructions. + + The standard encodings of the immediate value are: + N imms immr SIMD size R S + 1 ssssss rrrrrr 64 UInt(rrrrrr) UInt(ssssss) + 0 0sssss 0rrrrr 32 UInt(rrrrr) UInt(sssss) + 0 10ssss 00rrrr 16 UInt(rrrr) UInt(ssss) + 0 110sss 000rrr 8 UInt(rrr) UInt(sss) + 0 1110ss 0000rr 4 UInt(rr) UInt(ss) + 0 11110s 00000r 2 UInt(r) UInt(s) + where all-ones value of S is reserved. + + Let's call E the SIMD size. + + The immediate value is: S+1 bits '1' rotated to the right by R. + + The total of valid encodings is 64*63 + 32*31 + ... + 2*1 = 5334 + (remember S != E - 1). */ + +#define TOTAL_IMM_NB 5334 + +typedef struct +{ + uint64_t imm; + aarch64_insn encoding; +} simd_imm_encoding; + +static simd_imm_encoding simd_immediates[TOTAL_IMM_NB]; + +static int +simd_imm_encoding_cmp(const void *i1, const void *i2) +{ + const simd_imm_encoding *imm1 = (const simd_imm_encoding *)i1; + const simd_imm_encoding *imm2 = (const simd_imm_encoding *)i2; + + if (imm1->imm < imm2->imm) + return -1; + if (imm1->imm > imm2->imm) + return +1; + return 0; +} + +/* immediate bitfield standard encoding + imm13<12> imm13<5:0> imm13<11:6> SIMD size R S + 1 ssssss rrrrrr 64 rrrrrr ssssss + 0 0sssss 0rrrrr 32 rrrrr sssss + 0 10ssss 00rrrr 16 rrrr ssss + 0 110sss 000rrr 8 rrr sss + 0 1110ss 0000rr 4 rr ss + 0 11110s 00000r 2 r s */ +static inline int +encode_immediate_bitfield (int is64, uint32_t s, uint32_t r) +{ + return (is64 << 12) | (r << 6) | s; +} + +static void +build_immediate_table (void) +{ + uint32_t log_e, e, s, r, s_mask; + uint64_t mask, imm; + int nb_imms; + int is64; + + nb_imms = 0; + for (log_e = 1; log_e <= 6; log_e++) + { + /* Get element size. */ + e = 1u << log_e; + if (log_e == 6) + { + is64 = 1; + mask = 0xffffffffffffffffull; + s_mask = 0; + } + else + { + is64 = 0; + mask = (1ull << e) - 1; + /* log_e s_mask + 1 ((1 << 4) - 1) << 2 = 111100 + 2 ((1 << 3) - 1) << 3 = 111000 + 3 ((1 << 2) - 1) << 4 = 110000 + 4 ((1 << 1) - 1) << 5 = 100000 + 5 ((1 << 0) - 1) << 6 = 000000 */ + s_mask = ((1u << (5 - log_e)) - 1) << (log_e + 1); + } + for (s = 0; s < e - 1; s++) + for (r = 0; r < e; r++) + { + /* s+1 consecutive bits to 1 (s < 63) */ + imm = (1ull << (s + 1)) - 1; + /* rotate right by r */ + if (r != 0) + imm = (imm >> r) | ((imm << (e - r)) & mask); + /* replicate the constant depending on SIMD size */ + switch (log_e) + { + case 1: imm = (imm << 2) | imm; + case 2: imm = (imm << 4) | imm; + case 3: imm = (imm << 8) | imm; + case 4: imm = (imm << 16) | imm; + case 5: imm = (imm << 32) | imm; + case 6: break; + default: abort (); + } + simd_immediates[nb_imms].imm = imm; + simd_immediates[nb_imms].encoding = + encode_immediate_bitfield(is64, s | s_mask, r); + nb_imms++; + } + } + assert (nb_imms == TOTAL_IMM_NB); + qsort(simd_immediates, nb_imms, + sizeof(simd_immediates[0]), simd_imm_encoding_cmp); +} + +/* Return TRUE if VALUE is a valid logical immediate, i.e. bitmask, that can + be accepted by logical (immediate) instructions + e.g. ORR <Xd|SP>, <Xn>, #<imm>. + + IS32 indicates whether or not VALUE is a 32-bit immediate. + If ENCODING is not NULL, on the return of TRUE, the standard encoding for + VALUE will be returned in *ENCODING. */ + +bfd_boolean +aarch64_logical_immediate_p (uint64_t value, int is32, aarch64_insn *encoding) +{ + simd_imm_encoding imm_enc; + const simd_imm_encoding *imm_encoding; + static bfd_boolean initialized = FALSE; + + DEBUG_TRACE ("enter with 0x%" PRIx64 "(%" PRIi64 "), is32: %d", value, + value, is32); + + if (initialized == FALSE) + { + build_immediate_table (); + initialized = TRUE; + } + + if (is32) + { + /* Allow all zeros or all ones in top 32-bits, so that + constant expressions like ~1 are permitted. */ + if (value >> 32 != 0 && value >> 32 != 0xffffffff) + return 0xffffffff; + /* Replicate the 32 lower bits to the 32 upper bits. */ + value &= 0xffffffff; + value |= value << 32; + } + + imm_enc.imm = value; + imm_encoding = (const simd_imm_encoding *) + bsearch(&imm_enc, simd_immediates, TOTAL_IMM_NB, + sizeof(simd_immediates[0]), simd_imm_encoding_cmp); + if (imm_encoding == NULL) + { + DEBUG_TRACE ("exit with FALSE"); + return FALSE; + } + if (encoding != NULL) + *encoding = imm_encoding->encoding; + DEBUG_TRACE ("exit with TRUE"); + return TRUE; +} + +/* If 64-bit immediate IMM is in the format of + "aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh", + where a, b, c, d, e, f, g and h are independently 0 or 1, return an integer + of value "abcdefgh". Otherwise return -1. */ +int +aarch64_shrink_expanded_imm8 (uint64_t imm) +{ + int i, ret; + uint32_t byte; + + ret = 0; + for (i = 0; i < 8; i++) + { + byte = (imm >> (8 * i)) & 0xff; + if (byte == 0xff) + ret |= 1 << i; + else if (byte != 0x00) + return -1; + } + return ret; +} + +/* Utility inline functions for operand_general_constraint_met_p. */ + +static inline void +set_error (aarch64_operand_error *mismatch_detail, + enum aarch64_operand_error_kind kind, int idx, + const char* error) +{ + if (mismatch_detail == NULL) + return; + mismatch_detail->kind = kind; + mismatch_detail->index = idx; + mismatch_detail->error = error; +} + +static inline void +set_out_of_range_error (aarch64_operand_error *mismatch_detail, + int idx, int lower_bound, int upper_bound, + const char* error) +{ + if (mismatch_detail == NULL) + return; + set_error (mismatch_detail, AARCH64_OPDE_OUT_OF_RANGE, idx, error); + mismatch_detail->data[0] = lower_bound; + mismatch_detail->data[1] = upper_bound; +} + +static inline void +set_imm_out_of_range_error (aarch64_operand_error *mismatch_detail, + int idx, int lower_bound, int upper_bound) +{ + if (mismatch_detail == NULL) + return; + set_out_of_range_error (mismatch_detail, idx, lower_bound, upper_bound, + _("immediate value")); +} + +static inline void +set_offset_out_of_range_error (aarch64_operand_error *mismatch_detail, + int idx, int lower_bound, int upper_bound) +{ + if (mismatch_detail == NULL) + return; + set_out_of_range_error (mismatch_detail, idx, lower_bound, upper_bound, + _("immediate offset")); +} + +static inline void +set_regno_out_of_range_error (aarch64_operand_error *mismatch_detail, + int idx, int lower_bound, int upper_bound) +{ + if (mismatch_detail == NULL) + return; + set_out_of_range_error (mismatch_detail, idx, lower_bound, upper_bound, + _("register number")); +} + +static inline void +set_elem_idx_out_of_range_error (aarch64_operand_error *mismatch_detail, + int idx, int lower_bound, int upper_bound) +{ + if (mismatch_detail == NULL) + return; + set_out_of_range_error (mismatch_detail, idx, lower_bound, upper_bound, + _("register element index")); +} + +static inline void +set_sft_amount_out_of_range_error (aarch64_operand_error *mismatch_detail, + int idx, int lower_bound, int upper_bound) +{ + if (mismatch_detail == NULL) + return; + set_out_of_range_error (mismatch_detail, idx, lower_bound, upper_bound, + _("shift amount")); +} + +static inline void +set_unaligned_error (aarch64_operand_error *mismatch_detail, int idx, + int alignment) +{ + if (mismatch_detail == NULL) + return; + set_error (mismatch_detail, AARCH64_OPDE_UNALIGNED, idx, NULL); + mismatch_detail->data[0] = alignment; +} + +static inline void +set_reg_list_error (aarch64_operand_error *mismatch_detail, int idx, + int expected_num) +{ + if (mismatch_detail == NULL) + return; + set_error (mismatch_detail, AARCH64_OPDE_REG_LIST, idx, NULL); + mismatch_detail->data[0] = expected_num; +} + +static inline void +set_other_error (aarch64_operand_error *mismatch_detail, int idx, + const char* error) +{ + if (mismatch_detail == NULL) + return; + set_error (mismatch_detail, AARCH64_OPDE_OTHER_ERROR, idx, error); +} + +/* General constraint checking based on operand code. + + Return 1 if OPNDS[IDX] meets the general constraint of operand code TYPE + as the IDXth operand of opcode OPCODE. Otherwise return 0. + + This function has to be called after the qualifiers for all operands + have been resolved. + + Mismatching error message is returned in *MISMATCH_DETAIL upon request, + i.e. when MISMATCH_DETAIL is non-NULL. This avoids the generation + of error message during the disassembling where error message is not + wanted. We avoid the dynamic construction of strings of error messages + here (i.e. in libopcodes), as it is costly and complicated; instead, we + use a combination of error code, static string and some integer data to + represent an error. */ + +static int +operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx, + enum aarch64_opnd type, + const aarch64_opcode *opcode, + aarch64_operand_error *mismatch_detail) +{ + unsigned num; + unsigned char size; + int64_t imm; + const aarch64_opnd_info *opnd = opnds + idx; + aarch64_opnd_qualifier_t qualifier = opnd->qualifier; + + assert (opcode->operands[idx] == opnd->type && opnd->type == type); + + switch (aarch64_operands[type].op_class) + { + case AARCH64_OPND_CLASS_INT_REG: + /* <Xt> may be optional in some IC and TLBI instructions. */ + if (type == AARCH64_OPND_Rt_SYS) + { + assert (idx == 1 && (aarch64_get_operand_class (opnds[0].type) + == AARCH64_OPND_CLASS_SYSTEM)); + if (opnds[1].present && !opnds[0].sysins_op->has_xt) + { + set_other_error (mismatch_detail, idx, _("extraneous register")); + return 0; + } + if (!opnds[1].present && opnds[0].sysins_op->has_xt) + { + set_other_error (mismatch_detail, idx, _("missing register")); + return 0; + } + } + switch (qualifier) + { + case AARCH64_OPND_QLF_WSP: + case AARCH64_OPND_QLF_SP: + if (!aarch64_stack_pointer_p (opnd)) + { + set_other_error (mismatch_detail, idx, + _("stack pointer register expected")); + return 0; + } + break; + default: + break; + } + break; + + case AARCH64_OPND_CLASS_ADDRESS: + /* Check writeback. */ + switch (opcode->iclass) + { + case ldst_pos: + case ldst_unscaled: + case ldstnapair_offs: + case ldstpair_off: + case ldst_unpriv: + if (opnd->addr.writeback == 1) + { + set_other_error (mismatch_detail, idx, + _("unexpected address writeback")); + return 0; + } + break; + case ldst_imm9: + case ldstpair_indexed: + case asisdlsep: + case asisdlsop: + if (opnd->addr.writeback == 0) + { + set_other_error (mismatch_detail, idx, + _("address writeback expected")); + return 0; + } + break; + default: + assert (opnd->addr.writeback == 0); + break; + } + switch (type) + { + case AARCH64_OPND_ADDR_SIMM7: + /* Scaled signed 7 bits immediate offset. */ + /* Get the size of the data element that is accessed, which may be + different from that of the source register size, + e.g. in strb/ldrb. */ + size = aarch64_get_qualifier_esize (opnd->qualifier); + if (!value_in_range_p (opnd->addr.offset.imm, -64 * size, 63 * size)) + { + set_offset_out_of_range_error (mismatch_detail, idx, + -64 * size, 63 * size); + return 0; + } + if (!value_aligned_p (opnd->addr.offset.imm, size)) + { + set_unaligned_error (mismatch_detail, idx, size); + return 0; + } + break; + case AARCH64_OPND_ADDR_SIMM9: + /* Unscaled signed 9 bits immediate offset. */ + if (!value_in_range_p (opnd->addr.offset.imm, -256, 255)) + { + set_offset_out_of_range_error (mismatch_detail, idx, -256, 255); + return 0; + } + break; + + case AARCH64_OPND_ADDR_SIMM9_2: + /* Unscaled signed 9 bits immediate offset, which has to be negative + or unaligned. */ + size = aarch64_get_qualifier_esize (qualifier); + if ((value_in_range_p (opnd->addr.offset.imm, 0, 255) + && !value_aligned_p (opnd->addr.offset.imm, size)) + || value_in_range_p (opnd->addr.offset.imm, -256, -1)) + return 1; + set_other_error (mismatch_detail, idx, + _("negative or unaligned offset expected")); + return 0; + + case AARCH64_OPND_SIMD_ADDR_POST: + /* AdvSIMD load/store multiple structures, post-index. */ + assert (idx == 1); + if (opnd->addr.offset.is_reg) + { + if (value_in_range_p (opnd->addr.offset.regno, 0, 30)) + return 1; + else + { + set_other_error (mismatch_detail, idx, + _("invalid register offset")); + return 0; + } + } + else + { + const aarch64_opnd_info *prev = &opnds[idx-1]; + unsigned num_bytes; /* total number of bytes transferred. */ + /* The opcode dependent area stores the number of elements in + each structure to be loaded/stored. */ + int is_ld1r = get_opcode_dependent_value (opcode) == 1; + if (opcode->operands[0] == AARCH64_OPND_LVt_AL) + /* Special handling of loading single structure to all lane. */ + num_bytes = (is_ld1r ? 1 : prev->reglist.num_regs) + * aarch64_get_qualifier_esize (prev->qualifier); + else + num_bytes = prev->reglist.num_regs + * aarch64_get_qualifier_esize (prev->qualifier) + * aarch64_get_qualifier_nelem (prev->qualifier); + if ((int) num_bytes != opnd->addr.offset.imm) + { + set_other_error (mismatch_detail, idx, + _("invalid post-increment amount")); + return 0; + } + } + break; + + case AARCH64_OPND_ADDR_REGOFF: + /* Get the size of the data element that is accessed, which may be + different from that of the source register size, + e.g. in strb/ldrb. */ + size = aarch64_get_qualifier_esize (opnd->qualifier); + /* It is either no shift or shift by the binary logarithm of SIZE. */ + if (opnd->shifter.amount != 0 + && opnd->shifter.amount != (int)get_logsz (size)) + { + set_other_error (mismatch_detail, idx, + _("invalid shift amount")); + return 0; + } + /* Only UXTW, LSL, SXTW and SXTX are the accepted extending + operators. */ + switch (opnd->shifter.kind) + { + case AARCH64_MOD_UXTW: + case AARCH64_MOD_LSL: + case AARCH64_MOD_SXTW: + case AARCH64_MOD_SXTX: break; + default: + set_other_error (mismatch_detail, idx, + _("invalid extend/shift operator")); + return 0; + } + break; + + case AARCH64_OPND_ADDR_UIMM12: + imm = opnd->addr.offset.imm; + /* Get the size of the data element that is accessed, which may be + different from that of the source register size, + e.g. in strb/ldrb. */ + size = aarch64_get_qualifier_esize (qualifier); + if (!value_in_range_p (opnd->addr.offset.imm, 0, 4095 * size)) + { + set_offset_out_of_range_error (mismatch_detail, idx, + 0, 4095 * size); + return 0; + } + if (!value_aligned_p (opnd->shifter.amount, size)) + { + set_unaligned_error (mismatch_detail, idx, size); + return 0; + } + break; + + case AARCH64_OPND_ADDR_PCREL14: + case AARCH64_OPND_ADDR_PCREL19: + case AARCH64_OPND_ADDR_PCREL21: + case AARCH64_OPND_ADDR_PCREL26: + imm = opnd->imm.value; + if (operand_need_shift_by_two (get_operand_from_code (type))) + { + /* The offset value in a PC-relative branch instruction is alway + 4-byte aligned and is encoded without the lowest 2 bits. */ + if (!value_aligned_p (imm, 4)) + { + set_unaligned_error (mismatch_detail, idx, 4); + return 0; + } + /* Right shift by 2 so that we can carry out the following check + canonically. */ + imm >>= 2; + } + size = get_operand_fields_width (get_operand_from_code (type)); + if (!value_fit_signed_field_p (imm, size)) + { + set_other_error (mismatch_detail, idx, + _("immediate out of range")); + return 0; + } + break; + + default: + break; + } + break; + + case AARCH64_OPND_CLASS_SIMD_REGLIST: + /* The opcode dependent area stores the number of elements in + each structure to be loaded/stored. */ + num = get_opcode_dependent_value (opcode); + switch (type) + { + case AARCH64_OPND_LVt: + assert (num >= 1 && num <= 4); + /* Unless LD1/ST1, the number of registers should be equal to that + of the structure elements. */ + if (num != 1 && opnd->reglist.num_regs != num) + { + set_reg_list_error (mismatch_detail, idx, num); + return 0; + } + break; + case AARCH64_OPND_LVt_AL: + case AARCH64_OPND_LEt: + assert (num >= 1 && num <= 4); + /* The number of registers should be equal to that of the structure + elements. */ + if (opnd->reglist.num_regs != num) + { + set_reg_list_error (mismatch_detail, idx, num); + return 0; + } + break; + default: + break; + } + break; + + case AARCH64_OPND_CLASS_IMMEDIATE: + /* Constraint check on immediate operand. */ + imm = opnd->imm.value; + /* E.g. imm_0_31 constrains value to be 0..31. */ + if (qualifier_value_in_range_constraint_p (qualifier) + && !value_in_range_p (imm, get_lower_bound (qualifier), + get_upper_bound (qualifier))) + { + set_imm_out_of_range_error (mismatch_detail, idx, + get_lower_bound (qualifier), + get_upper_bound (qualifier)); + return 0; + } + + switch (type) + { + case AARCH64_OPND_AIMM: + if (opnd->shifter.kind != AARCH64_MOD_LSL) + { + set_other_error (mismatch_detail, idx, + _("invalid shift operator")); + return 0; + } + if (opnd->shifter.amount != 0 && opnd->shifter.amount != 12) + { + set_other_error (mismatch_detail, idx, + _("shift amount expected to be 0 or 12")); + return 0; + } + if (!value_fit_unsigned_field_p (opnd->imm.value, 12)) + { + set_other_error (mismatch_detail, idx, + _("immediate out of range")); + return 0; + } + break; + + case AARCH64_OPND_HALF: + assert (idx == 1 && opnds[0].type == AARCH64_OPND_Rd); + if (opnd->shifter.kind != AARCH64_MOD_LSL) + { + set_other_error (mismatch_detail, idx, + _("invalid shift operator")); + return 0; + } + size = aarch64_get_qualifier_esize (opnds[0].qualifier); + if (!value_aligned_p (opnd->shifter.amount, 16)) + { + set_other_error (mismatch_detail, idx, + _("shift amount should be a multiple of 16")); + return 0; + } + if (!value_in_range_p (opnd->shifter.amount, 0, size * 8 - 16)) + { + set_sft_amount_out_of_range_error (mismatch_detail, idx, + 0, size * 8 - 16); + return 0; + } + if (opnd->imm.value < 0) + { + set_other_error (mismatch_detail, idx, + _("negative immediate value not allowed")); + return 0; + } + if (!value_fit_unsigned_field_p (opnd->imm.value, 16)) + { + set_other_error (mismatch_detail, idx, + _("immediate out of range")); + return 0; + } + break; + + case AARCH64_OPND_IMM_MOV: + { + int is32 = aarch64_get_qualifier_esize (opnds[0].qualifier) == 4; + imm = opnd->imm.value; + assert (idx == 1); + switch (opcode->op) + { + case OP_MOV_IMM_WIDEN: + imm = ~imm; + /* Fall through... */ + case OP_MOV_IMM_WIDE: + if (!aarch64_wide_constant_p (imm, is32, NULL)) + { + set_other_error (mismatch_detail, idx, + _("immediate out of range")); + return 0; + } + break; + case OP_MOV_IMM_LOG: + if (!aarch64_logical_immediate_p (imm, is32, NULL)) + { + set_other_error (mismatch_detail, idx, + _("immediate out of range")); + return 0; + } + break; + default: + assert (0); + return 0; + } + } + break; + + case AARCH64_OPND_NZCV: + case AARCH64_OPND_CCMP_IMM: + case AARCH64_OPND_EXCEPTION: + case AARCH64_OPND_UIMM4: + case AARCH64_OPND_UIMM7: + case AARCH64_OPND_UIMM3_OP1: + case AARCH64_OPND_UIMM3_OP2: + size = get_operand_fields_width (get_operand_from_code (type)); + assert (size < 32); + if (!value_fit_unsigned_field_p (opnd->imm.value, size)) + { + set_imm_out_of_range_error (mismatch_detail, idx, 0, + (1 << size) - 1); + return 0; + } + break; + + case AARCH64_OPND_WIDTH: + assert (idx == 3 && opnds[idx-1].type == AARCH64_OPND_IMM + && opnds[0].type == AARCH64_OPND_Rd); + size = get_upper_bound (qualifier); + if (opnd->imm.value + opnds[idx-1].imm.value > size) + /* lsb+width <= reg.size */ + { + set_imm_out_of_range_error (mismatch_detail, idx, 1, + size - opnds[idx-1].imm.value); + return 0; + } + break; + + case AARCH64_OPND_LIMM: + { + int is32 = opnds[0].qualifier == AARCH64_OPND_QLF_W; + uint64_t uimm = opnd->imm.value; + if (opcode->op == OP_BIC) + uimm = ~uimm; + if (aarch64_logical_immediate_p (uimm, is32, NULL) == FALSE) + { + set_other_error (mismatch_detail, idx, + _("immediate out of range")); + return 0; + } + } + break; + + case AARCH64_OPND_IMM0: + case AARCH64_OPND_FPIMM0: + if (opnd->imm.value != 0) + { + set_other_error (mismatch_detail, idx, + _("immediate zero expected")); + return 0; + } + break; + + case AARCH64_OPND_SHLL_IMM: + assert (idx == 2); + size = 8 * aarch64_get_qualifier_esize (opnds[idx - 1].qualifier); + if (opnd->imm.value != size) + { + set_other_error (mismatch_detail, idx, + _("invalid shift amount")); + return 0; + } + break; + + case AARCH64_OPND_IMM_VLSL: + size = aarch64_get_qualifier_esize (qualifier); + if (!value_in_range_p (opnd->imm.value, 0, size * 8 - 1)) + { + set_imm_out_of_range_error (mismatch_detail, idx, 0, + size * 8 - 1); + return 0; + } + break; + + case AARCH64_OPND_IMM_VLSR: + size = aarch64_get_qualifier_esize (qualifier); + if (!value_in_range_p (opnd->imm.value, 1, size * 8)) + { + set_imm_out_of_range_error (mismatch_detail, idx, 1, size * 8); + return 0; + } + break; + + case AARCH64_OPND_SIMD_IMM: + case AARCH64_OPND_SIMD_IMM_SFT: + /* Qualifier check. */ + switch (qualifier) + { + case AARCH64_OPND_QLF_LSL: + if (opnd->shifter.kind != AARCH64_MOD_LSL) + { + set_other_error (mismatch_detail, idx, + _("invalid shift operator")); + return 0; + } + break; + case AARCH64_OPND_QLF_MSL: + if (opnd->shifter.kind != AARCH64_MOD_MSL) + { + set_other_error (mismatch_detail, idx, + _("invalid shift operator")); + return 0; + } + break; + case AARCH64_OPND_QLF_NIL: + if (opnd->shifter.kind != AARCH64_MOD_NONE) + { + set_other_error (mismatch_detail, idx, + _("shift is not permitted")); + return 0; + } + break; + default: + assert (0); + return 0; + } + /* Is the immediate valid? */ + assert (idx == 1); + if (aarch64_get_qualifier_esize (opnds[0].qualifier) != 8) + { + /* uimm8 */ + if (!value_in_range_p (opnd->imm.value, 0, 255)) + { + set_imm_out_of_range_error (mismatch_detail, idx, 0, 255); + return 0; + } + } + else if (aarch64_shrink_expanded_imm8 (opnd->imm.value) < 0) + { + /* uimm64 is not + 'aaaaaaaabbbbbbbbccccccccddddddddeeeeeeee + ffffffffgggggggghhhhhhhh'. */ + set_other_error (mismatch_detail, idx, + _("invalid value for immediate")); + return 0; + } + /* Is the shift amount valid? */ + switch (opnd->shifter.kind) + { + case AARCH64_MOD_LSL: + size = aarch64_get_qualifier_esize (opnds[0].qualifier); + if (!value_aligned_p (opnd->shifter.amount, 8)) + { + set_unaligned_error (mismatch_detail, idx, 8); + return 0; + } + if (!value_in_range_p (opnd->shifter.amount, 0, (size - 1) * 8)) + { + set_imm_out_of_range_error (mismatch_detail, idx, 0, + (size - 1) * 8); + return 0; + } + break; + case AARCH64_MOD_MSL: + /* Only 8 and 16 are valid shift amount. */ + if (opnd->shifter.amount != 8 && opnd->shifter.amount != 16) + { + set_other_error (mismatch_detail, idx, + _("shift amount expected to be 0 or 16")); + return 0; + } + break; + default: + if (opnd->shifter.kind != AARCH64_MOD_NONE) + { + set_other_error (mismatch_detail, idx, + _("invalid shift operator")); + return 0; + } + break; + } + break; + + case AARCH64_OPND_FPIMM: + case AARCH64_OPND_SIMD_FPIMM: + if (opnd->imm.is_fp == 0) + { + set_other_error (mismatch_detail, idx, + _("floating-point immediate expected")); + return 0; + } + /* The value is expected to be an 8-bit floating-point constant with + sign, 3-bit exponent and normalized 4 bits of precision, encoded + in "a:b:c:d:e:f:g:h" or FLD_imm8 (depending on the type of the + instruction). */ + if (!value_in_range_p (opnd->imm.value, 0, 255)) + { + set_other_error (mismatch_detail, idx, + _("immediate out of range")); + return 0; + } + if (opnd->shifter.kind != AARCH64_MOD_NONE) + { + set_other_error (mismatch_detail, idx, + _("invalid shift operator")); + return 0; + } + break; + + default: + break; + } + break; + + case AARCH64_OPND_CLASS_CP_REG: + /* Cn or Cm: 4-bit opcode field named for historical reasons. + valid range: C0 - C15. */ + if (opnd->reg.regno > 15) + { + set_regno_out_of_range_error (mismatch_detail, idx, 0, 15); + return 0; + } + break; + + case AARCH64_OPND_CLASS_SYSTEM: + switch (type) + { + case AARCH64_OPND_PSTATEFIELD: + assert (idx == 0 && opnds[1].type == AARCH64_OPND_UIMM4); + /* MSR SPSel, #uimm4 + Uses uimm4 as a control value to select the stack pointer: if + bit 0 is set it selects the current exception level's stack + pointer, if bit 0 is clear it selects shared EL0 stack pointer. + Bits 1 to 3 of uimm4 are reserved and should be zero. */ + if (opnd->pstatefield == 0x05 /* spsel */ && opnds[1].imm.value > 1) + { + set_imm_out_of_range_error (mismatch_detail, idx, 0, 1); + return 0; + } + break; + default: + break; + } + break; + + case AARCH64_OPND_CLASS_SIMD_ELEMENT: + /* Get the upper bound for the element index. */ + num = 16 / aarch64_get_qualifier_esize (qualifier) - 1; + /* Index out-of-range. */ + if (!value_in_range_p (opnd->reglane.index, 0, num)) + { + set_elem_idx_out_of_range_error (mismatch_detail, idx, 0, num); + return 0; + } + /* SMLAL<Q> <Vd>.<Ta>, <Vn>.<Tb>, <Vm>.<Ts>[<index>]. + <Vm> Is the vector register (V0-V31) or (V0-V15), whose + number is encoded in "size:M:Rm": + size <Vm> + 00 RESERVED + 01 0:Rm + 10 M:Rm + 11 RESERVED */ + if (type == AARCH64_OPND_Em && qualifier == AARCH64_OPND_QLF_S_H + && !value_in_range_p (opnd->reglane.regno, 0, 15)) + { + set_regno_out_of_range_error (mismatch_detail, idx, 0, 15); + return 0; + } + break; + + case AARCH64_OPND_CLASS_MODIFIED_REG: + assert (idx == 1 || idx == 2); + switch (type) + { + case AARCH64_OPND_Rm_EXT: + if (aarch64_extend_operator_p (opnd->shifter.kind) == FALSE + && opnd->shifter.kind != AARCH64_MOD_LSL) + { + set_other_error (mismatch_detail, idx, + _("extend operator expected")); + return 0; + } + /* It is not optional unless at least one of "Rd" or "Rn" is '11111' + (i.e. SP), in which case it defaults to LSL. The LSL alias is + only valid when "Rd" or "Rn" is '11111', and is preferred in that + case. */ + if (!aarch64_stack_pointer_p (opnds + 0) + && (idx != 2 || !aarch64_stack_pointer_p (opnds + 1))) + { + if (!opnd->shifter.operator_present) + { + set_other_error (mismatch_detail, idx, + _("missing extend operator")); + return 0; + } + else if (opnd->shifter.kind == AARCH64_MOD_LSL) + { + set_other_error (mismatch_detail, idx, + _("'LSL' operator not allowed")); + return 0; + } + } + assert (opnd->shifter.operator_present /* Default to LSL. */ + || opnd->shifter.kind == AARCH64_MOD_LSL); + if (!value_in_range_p (opnd->shifter.amount, 0, 4)) + { + set_sft_amount_out_of_range_error (mismatch_detail, idx, 0, 4); + return 0; + } + /* In the 64-bit form, the final register operand is written as Wm + for all but the (possibly omitted) UXTX/LSL and SXTX + operators. + N.B. GAS allows X register to be used with any operator as a + programming convenience. */ + if (qualifier == AARCH64_OPND_QLF_X + && opnd->shifter.kind != AARCH64_MOD_LSL + && opnd->shifter.kind != AARCH64_MOD_UXTX + && opnd->shifter.kind != AARCH64_MOD_SXTX) + { + set_other_error (mismatch_detail, idx, _("W register expected")); + return 0; + } + break; + + case AARCH64_OPND_Rm_SFT: + /* ROR is not available to the shifted register operand in + arithmetic instructions. */ + if (aarch64_shift_operator_p (opnd->shifter.kind) == FALSE) + { + set_other_error (mismatch_detail, idx, + _("shift operator expected")); + return 0; + } + if (opnd->shifter.kind == AARCH64_MOD_ROR + && opcode->iclass != log_shift) + { + set_other_error (mismatch_detail, idx, + _("'ROR' operator not allowed")); + return 0; + } + num = qualifier == AARCH64_OPND_QLF_W ? 31 : 63; + if (!value_in_range_p (opnd->shifter.amount, 0, num)) + { + set_sft_amount_out_of_range_error (mismatch_detail, idx, 0, num); + return 0; + } + break; + + default: + break; + } + break; + + default: + break; + } + + return 1; +} + +/* Main entrypoint for the operand constraint checking. + + Return 1 if operands of *INST meet the constraint applied by the operand + codes and operand qualifiers; otherwise return 0 and if MISMATCH_DETAIL is + not NULL, return the detail of the error in *MISMATCH_DETAIL. N.B. when + adding more constraint checking, make sure MISMATCH_DETAIL->KIND is set + with a proper error kind rather than AARCH64_OPDE_NIL (GAS asserts non-NIL + error kind when it is notified that an instruction does not pass the check). + + Un-determined operand qualifiers may get established during the process. */ + +int +aarch64_match_operands_constraint (aarch64_inst *inst, + aarch64_operand_error *mismatch_detail) +{ + int i; + + DEBUG_TRACE ("enter"); + + /* Match operands' qualifier. + *INST has already had qualifier establish for some, if not all, of + its operands; we need to find out whether these established + qualifiers match one of the qualifier sequence in + INST->OPCODE->QUALIFIERS_LIST. If yes, we will assign each operand + with the corresponding qualifier in such a sequence. + Only basic operand constraint checking is done here; the more thorough + constraint checking will carried out by operand_general_constraint_met_p, + which has be to called after this in order to get all of the operands' + qualifiers established. */ + if (match_operands_qualifier (inst, TRUE /* update_p */) == 0) + { + DEBUG_TRACE ("FAIL on operand qualifier matching"); + if (mismatch_detail) + { + /* Return an error type to indicate that it is the qualifier + matching failure; we don't care about which operand as there + are enough information in the opcode table to reproduce it. */ + mismatch_detail->kind = AARCH64_OPDE_INVALID_VARIANT; + mismatch_detail->index = -1; + mismatch_detail->error = NULL; + } + return 0; + } + + /* Match operands' constraint. */ + for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i) + { + enum aarch64_opnd type = inst->opcode->operands[i]; + if (type == AARCH64_OPND_NIL) + break; + if (inst->operands[i].skip) + { + DEBUG_TRACE ("skip the incomplete operand %d", i); + continue; + } + if (operand_general_constraint_met_p (inst->operands, i, type, + inst->opcode, mismatch_detail) == 0) + { + DEBUG_TRACE ("FAIL on operand %d", i); + return 0; + } + } + + DEBUG_TRACE ("PASS"); + + return 1; +} + +/* Replace INST->OPCODE with OPCODE and return the replaced OPCODE. + Also updates the TYPE of each INST->OPERANDS with the corresponding + value of OPCODE->OPERANDS. + + Note that some operand qualifiers may need to be manually cleared by + the caller before it further calls the aarch64_opcode_encode; by + doing this, it helps the qualifier matching facilities work + properly. */ + +const aarch64_opcode* +aarch64_replace_opcode (aarch64_inst *inst, const aarch64_opcode *opcode) +{ + int i; + const aarch64_opcode *old = inst->opcode; + + inst->opcode = opcode; + + /* Update the operand types. */ + for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i) + { + inst->operands[i].type = opcode->operands[i]; + if (opcode->operands[i] == AARCH64_OPND_NIL) + break; + } + + DEBUG_TRACE ("replace %s with %s", old->name, opcode->name); + + return old; +} + +int +aarch64_operand_index (const enum aarch64_opnd *operands, enum aarch64_opnd operand) +{ + int i; + for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i) + if (operands[i] == operand) + return i; + else if (operands[i] == AARCH64_OPND_NIL) + break; + return -1; +} + +/* [0][0] 32-bit integer regs with sp Wn + [0][1] 64-bit integer regs with sp Xn sf=1 + [1][0] 32-bit integer regs with #0 Wn + [1][1] 64-bit integer regs with #0 Xn sf=1 */ +static const char *int_reg[2][2][32] = { +#define R32 "w" +#define R64 "x" + { { R32 "0", R32 "1", R32 "2", R32 "3", R32 "4", R32 "5", R32 "6", R32 "7", + R32 "8", R32 "9", R32 "10", R32 "11", R32 "12", R32 "13", R32 "14", R32 "15", + R32 "16", R32 "17", R32 "18", R32 "19", R32 "20", R32 "21", R32 "22", R32 "23", + R32 "24", R32 "25", R32 "26", R32 "27", R32 "28", R32 "29", R32 "30", "wsp" }, + { R64 "0", R64 "1", R64 "2", R64 "3", R64 "4", R64 "5", R64 "6", R64 "7", + R64 "8", R64 "9", R64 "10", R64 "11", R64 "12", R64 "13", R64 "14", R64 "15", + R64 "16", R64 "17", R64 "18", R64 "19", R64 "20", R64 "21", R64 "22", R64 "23", + R64 "24", R64 "25", R64 "26", R64 "27", R64 "28", R64 "29", R64 "30", "sp" } }, + { { R32 "0", R32 "1", R32 "2", R32 "3", R32 "4", R32 "5", R32 "6", R32 "7", + R32 "8", R32 "9", R32 "10", R32 "11", R32 "12", R32 "13", R32 "14", R32 "15", + R32 "16", R32 "17", R32 "18", R32 "19", R32 "20", R32 "21", R32 "22", R32 "23", + R32 "24", R32 "25", R32 "26", R32 "27", R32 "28", R32 "29", R32 "30", R32 "zr" }, + { R64 "0", R64 "1", R64 "2", R64 "3", R64 "4", R64 "5", R64 "6", R64 "7", + R64 "8", R64 "9", R64 "10", R64 "11", R64 "12", R64 "13", R64 "14", R64 "15", + R64 "16", R64 "17", R64 "18", R64 "19", R64 "20", R64 "21", R64 "22", R64 "23", + R64 "24", R64 "25", R64 "26", R64 "27", R64 "28", R64 "29", R64 "30", R64 "zr" } } +#undef R64 +#undef R32 +}; + +/* Return the integer register name. + if SP_REG_P is not 0, R31 is an SP reg, other R31 is the zero reg. */ + +static inline const char * +get_int_reg_name (int regno, aarch64_opnd_qualifier_t qualifier, int sp_reg_p) +{ + const int has_zr = sp_reg_p ? 0 : 1; + const int is_64 = aarch64_get_qualifier_esize (qualifier) == 4 ? 0 : 1; + return int_reg[has_zr][is_64][regno]; +} + +/* Like get_int_reg_name, but IS_64 is always 1. */ + +static inline const char * +get_64bit_int_reg_name (int regno, int sp_reg_p) +{ + const int has_zr = sp_reg_p ? 0 : 1; + return int_reg[has_zr][1][regno]; +} + +/* Types for expanding an encoded 8-bit value to a floating-point value. */ + +typedef union +{ + uint64_t i; + double d; +} double_conv_t; + +typedef union +{ + uint32_t i; + float f; +} single_conv_t; + +/* IMM8 is an 8-bit floating-point constant with sign, 3-bit exponent and + normalized 4 bits of precision, encoded in "a:b:c:d:e:f:g:h" or FLD_imm8 + (depending on the type of the instruction). IMM8 will be expanded to a + single-precision floating-point value (IS_DP == 0) or a double-precision + floating-point value (IS_DP == 1). The expanded value is returned. */ + +static uint64_t +expand_fp_imm (int is_dp, uint32_t imm8) +{ + uint64_t imm; + uint32_t imm8_7, imm8_6_0, imm8_6, imm8_6_repl4; + + imm8_7 = (imm8 >> 7) & 0x01; /* imm8<7> */ + imm8_6_0 = imm8 & 0x7f; /* imm8<6:0> */ + imm8_6 = imm8_6_0 >> 6; /* imm8<6> */ + imm8_6_repl4 = (imm8_6 << 3) | (imm8_6 << 2) + | (imm8_6 << 1) | imm8_6; /* Replicate(imm8<6>,4) */ + if (is_dp) + { + imm = (imm8_7 << (63-32)) /* imm8<7> */ + | ((imm8_6 ^ 1) << (62-32)) /* NOT(imm8<6) */ + | (imm8_6_repl4 << (58-32)) | (imm8_6 << (57-32)) + | (imm8_6 << (56-32)) | (imm8_6 << (55-32)) /* Replicate(imm8<6>,7) */ + | (imm8_6_0 << (48-32)); /* imm8<6>:imm8<5:0> */ + imm <<= 32; + } + else + { + imm = (imm8_7 << 31) /* imm8<7> */ + | ((imm8_6 ^ 1) << 30) /* NOT(imm8<6>) */ + | (imm8_6_repl4 << 26) /* Replicate(imm8<6>,4) */ + | (imm8_6_0 << 19); /* imm8<6>:imm8<5:0> */ + } + + return imm; +} + +/* Produce the string representation of the register list operand *OPND + in the buffer pointed by BUF of size SIZE. */ +static void +print_register_list (char *buf, size_t size, const aarch64_opnd_info *opnd) +{ + const int num_regs = opnd->reglist.num_regs; + const int first_reg = opnd->reglist.first_regno; + const int last_reg = (first_reg + num_regs - 1) & 0x1f; + const char *qlf_name = aarch64_get_qualifier_name (opnd->qualifier); + char tb[8]; /* Temporary buffer. */ + + assert (opnd->type != AARCH64_OPND_LEt || opnd->reglist.has_index); + assert (num_regs >= 1 && num_regs <= 4); + + /* Prepare the index if any. */ + if (opnd->reglist.has_index) + snprintf (tb, 8, "[%d]", opnd->reglist.index); + else + tb[0] = '\0'; + + /* The hyphenated form is preferred for disassembly if there are + more than two registers in the list, and the register numbers + are monotonically increasing in increments of one. */ + if (num_regs > 2 && last_reg > first_reg) + snprintf (buf, size, "{v%d.%s-v%d.%s}%s", first_reg, qlf_name, + last_reg, qlf_name, tb); + else + { + const int reg0 = first_reg; + const int reg1 = (first_reg + 1) & 0x1f; + const int reg2 = (first_reg + 2) & 0x1f; + const int reg3 = (first_reg + 3) & 0x1f; + + switch (num_regs) + { + case 1: + snprintf (buf, size, "{v%d.%s}%s", reg0, qlf_name, tb); + break; + case 2: + snprintf (buf, size, "{v%d.%s, v%d.%s}%s", reg0, qlf_name, + reg1, qlf_name, tb); + break; + case 3: + snprintf (buf, size, "{v%d.%s, v%d.%s, v%d.%s}%s", reg0, qlf_name, + reg1, qlf_name, reg2, qlf_name, tb); + break; + case 4: + snprintf (buf, size, "{v%d.%s, v%d.%s, v%d.%s, v%d.%s}%s", + reg0, qlf_name, reg1, qlf_name, reg2, qlf_name, + reg3, qlf_name, tb); + break; + } + } +} + +/* Produce the string representation of the register offset address operand + *OPND in the buffer pointed by BUF of size SIZE. */ +static void +print_register_offset_address (char *buf, size_t size, + const aarch64_opnd_info *opnd) +{ + const size_t tblen = 16; + char tb[tblen]; /* Temporary buffer. */ + bfd_boolean lsl_p = FALSE; /* Is LSL shift operator? */ + bfd_boolean wm_p = FALSE; /* Should Rm be Wm? */ + bfd_boolean print_extend_p = TRUE; + bfd_boolean print_amount_p = TRUE; + const char *shift_name = aarch64_operand_modifiers[opnd->shifter.kind].name; + + switch (opnd->shifter.kind) + { + case AARCH64_MOD_UXTW: wm_p = TRUE; break; + case AARCH64_MOD_LSL : lsl_p = TRUE; break; + case AARCH64_MOD_SXTW: wm_p = TRUE; break; + case AARCH64_MOD_SXTX: break; + default: assert (0); + } + + if (!opnd->shifter.amount && (opnd->qualifier != AARCH64_OPND_QLF_S_B + || !opnd->shifter.amount_present)) + { + /* Not print the shift/extend amount when the amount is zero and + when it is not the special case of 8-bit load/store instruction. */ + print_amount_p = FALSE; + /* Likewise, no need to print the shift operator LSL in such a + situation. */ + if (lsl_p) + print_extend_p = FALSE; + } + + /* Prepare for the extend/shift. */ + if (print_extend_p) + { + if (print_amount_p) + snprintf (tb, tblen, ",%s #%d", shift_name, opnd->shifter.amount); + else + snprintf (tb, tblen, ",%s", shift_name); + } + else + tb[0] = '\0'; + + snprintf (buf, size, "[%s,%c%d%s]", + get_64bit_int_reg_name (opnd->addr.base_regno, 1), + wm_p ? 'w' : 'x', opnd->addr.offset.regno, tb); +} + +/* Generate the string representation of the operand OPNDS[IDX] for OPCODE + in *BUF. The caller should pass in the maximum size of *BUF in SIZE. + PC, PCREL_P and ADDRESS are used to pass in and return information about + the PC-relative address calculation, where the PC value is passed in + PC. If the operand is pc-relative related, *PCREL_P (if PCREL_P non-NULL) + will return 1 and *ADDRESS (if ADDRESS non-NULL) will return the + calculated address; otherwise, *PCREL_P (if PCREL_P non-NULL) returns 0. + + The function serves both the disassembler and the assembler diagnostics + issuer, which is the reason why it lives in this file. */ + +void +aarch64_print_operand (char *buf, size_t size, bfd_vma pc, + const aarch64_opcode *opcode, + const aarch64_opnd_info *opnds, int idx, int *pcrel_p, + bfd_vma *address) +{ + int i; + const char *name = NULL; + const aarch64_opnd_info *opnd = opnds + idx; + enum aarch64_modifier_kind kind; + uint64_t addr; + + buf[0] = '\0'; + if (pcrel_p) + *pcrel_p = 0; + + switch (opnd->type) + { + case AARCH64_OPND_Rd: + case AARCH64_OPND_Rn: + case AARCH64_OPND_Rm: + case AARCH64_OPND_Rt: + case AARCH64_OPND_Rt2: + case AARCH64_OPND_Rs: + case AARCH64_OPND_Ra: + case AARCH64_OPND_Rt_SYS: + /* The optional-ness of <Xt> in e.g. IC <ic_op>{, <Xt>} is determined by + the <ic_op>, therefore we we use opnd->present to override the + generic optional-ness information. */ + if (opnd->type == AARCH64_OPND_Rt_SYS && !opnd->present) + break; + /* Omit the operand, e.g. RET. */ + if (optional_operand_p (opcode, idx) + && opnd->reg.regno == get_optional_operand_default_value (opcode)) + break; + assert (opnd->qualifier == AARCH64_OPND_QLF_W + || opnd->qualifier == AARCH64_OPND_QLF_X); + snprintf (buf, size, "%s", + get_int_reg_name (opnd->reg.regno, opnd->qualifier, 0)); + break; + + case AARCH64_OPND_Rd_SP: + case AARCH64_OPND_Rn_SP: + assert (opnd->qualifier == AARCH64_OPND_QLF_W + || opnd->qualifier == AARCH64_OPND_QLF_WSP + || opnd->qualifier == AARCH64_OPND_QLF_X + || opnd->qualifier == AARCH64_OPND_QLF_SP); + snprintf (buf, size, "%s", + get_int_reg_name (opnd->reg.regno, opnd->qualifier, 1)); + break; + + case AARCH64_OPND_Rm_EXT: + kind = opnd->shifter.kind; + assert (idx == 1 || idx == 2); + if ((aarch64_stack_pointer_p (opnds) + || (idx == 2 && aarch64_stack_pointer_p (opnds + 1))) + && ((opnd->qualifier == AARCH64_OPND_QLF_W + && opnds[0].qualifier == AARCH64_OPND_QLF_W + && kind == AARCH64_MOD_UXTW) + || (opnd->qualifier == AARCH64_OPND_QLF_X + && kind == AARCH64_MOD_UXTX))) + { + /* 'LSL' is the preferred form in this case. */ + kind = AARCH64_MOD_LSL; + if (opnd->shifter.amount == 0) + { + /* Shifter omitted. */ + snprintf (buf, size, "%s", + get_int_reg_name (opnd->reg.regno, opnd->qualifier, 0)); + break; + } + } + if (opnd->shifter.amount) + snprintf (buf, size, "%s, %s #%d", + get_int_reg_name (opnd->reg.regno, opnd->qualifier, 0), + aarch64_operand_modifiers[kind].name, + opnd->shifter.amount); + else + snprintf (buf, size, "%s, %s", + get_int_reg_name (opnd->reg.regno, opnd->qualifier, 0), + aarch64_operand_modifiers[kind].name); + break; + + case AARCH64_OPND_Rm_SFT: + assert (opnd->qualifier == AARCH64_OPND_QLF_W + || opnd->qualifier == AARCH64_OPND_QLF_X); + if (opnd->shifter.amount == 0 && opnd->shifter.kind == AARCH64_MOD_LSL) + snprintf (buf, size, "%s", + get_int_reg_name (opnd->reg.regno, opnd->qualifier, 0)); + else + snprintf (buf, size, "%s, %s #%d", + get_int_reg_name (opnd->reg.regno, opnd->qualifier, 0), + aarch64_operand_modifiers[opnd->shifter.kind].name, + opnd->shifter.amount); + break; + + case AARCH64_OPND_Fd: + case AARCH64_OPND_Fn: + case AARCH64_OPND_Fm: + case AARCH64_OPND_Fa: + case AARCH64_OPND_Ft: + case AARCH64_OPND_Ft2: + case AARCH64_OPND_Sd: + case AARCH64_OPND_Sn: + case AARCH64_OPND_Sm: + snprintf (buf, size, "%s%d", aarch64_get_qualifier_name (opnd->qualifier), + opnd->reg.regno); + break; + + case AARCH64_OPND_Vd: + case AARCH64_OPND_Vn: + case AARCH64_OPND_Vm: + snprintf (buf, size, "v%d.%s", opnd->reg.regno, + aarch64_get_qualifier_name (opnd->qualifier)); + break; + + case AARCH64_OPND_Ed: + case AARCH64_OPND_En: + case AARCH64_OPND_Em: + snprintf (buf, size, "v%d.%s[%d]", opnd->reglane.regno, + aarch64_get_qualifier_name (opnd->qualifier), + opnd->reglane.index); + break; + + case AARCH64_OPND_VdD1: + case AARCH64_OPND_VnD1: + snprintf (buf, size, "v%d.d[1]", opnd->reg.regno); + break; + + case AARCH64_OPND_LVn: + case AARCH64_OPND_LVt: + case AARCH64_OPND_LVt_AL: + case AARCH64_OPND_LEt: + print_register_list (buf, size, opnd); + break; + + case AARCH64_OPND_Cn: + case AARCH64_OPND_Cm: + snprintf (buf, size, "C%d", opnd->reg.regno); + break; + + case AARCH64_OPND_IDX: + case AARCH64_OPND_IMM: + case AARCH64_OPND_WIDTH: + case AARCH64_OPND_UIMM3_OP1: + case AARCH64_OPND_UIMM3_OP2: + case AARCH64_OPND_BIT_NUM: + case AARCH64_OPND_IMM_VLSL: + case AARCH64_OPND_IMM_VLSR: + case AARCH64_OPND_SHLL_IMM: + case AARCH64_OPND_IMM0: + case AARCH64_OPND_IMMR: + case AARCH64_OPND_IMMS: + case AARCH64_OPND_FBITS: + case AARCH64_OPND_IMM_MOV: + snprintf (buf, size, "#%" PRIi64, opnd->imm.value); + break; + + case AARCH64_OPND_FPIMM0: + snprintf (buf, size, "#0.0"); + break; + + case AARCH64_OPND_LIMM: + case AARCH64_OPND_AIMM: + case AARCH64_OPND_HALF: + if (opnd->shifter.amount) + snprintf (buf, size, "#0x%" PRIx64 ", lsl #%d", opnd->imm.value, + opnd->shifter.amount); + else + snprintf (buf, size, "#0x%" PRIx64, opnd->imm.value); + break; + + case AARCH64_OPND_SIMD_IMM: + case AARCH64_OPND_SIMD_IMM_SFT: + if ((! opnd->shifter.amount && opnd->shifter.kind == AARCH64_MOD_LSL) + || opnd->shifter.kind == AARCH64_MOD_NONE) + snprintf (buf, size, "#0x%" PRIx64, opnd->imm.value); + else + snprintf (buf, size, "#0x%" PRIx64 ", %s #%d", opnd->imm.value, + aarch64_operand_modifiers[opnd->shifter.kind].name, + opnd->shifter.amount); + break; + + case AARCH64_OPND_FPIMM: + case AARCH64_OPND_SIMD_FPIMM: + switch (aarch64_get_qualifier_esize (opnds[0].qualifier)) + { + case 4: /* e.g. FMOV <Vd>.4S, #<imm>. */ + { + single_conv_t c; + c.i = expand_fp_imm (0, opnd->imm.value); + snprintf (buf, size, "#%.18e", c.f); + } + break; + case 8: /* e.g. FMOV <Sd>, #<imm>. */ + { + double_conv_t c; + c.i = expand_fp_imm (1, opnd->imm.value); + snprintf (buf, size, "#%.18e", c.d); + } + break; + default: assert (0); + } + break; + + case AARCH64_OPND_CCMP_IMM: + case AARCH64_OPND_NZCV: + case AARCH64_OPND_EXCEPTION: + case AARCH64_OPND_UIMM4: + case AARCH64_OPND_UIMM7: + if (optional_operand_p (opcode, idx) == TRUE + && (opnd->imm.value == + (int64_t) get_optional_operand_default_value (opcode))) + /* Omit the operand, e.g. DCPS1. */ + break; + snprintf (buf, size, "#0x%x", (unsigned int)opnd->imm.value); + break; + + case AARCH64_OPND_COND: + snprintf (buf, size, "%s", opnd->cond->names[0]); + break; + + case AARCH64_OPND_ADDR_ADRP: + addr = ((pc + AARCH64_PCREL_OFFSET) & ~(uint64_t)0xfff) + + opnd->imm.value; + if (pcrel_p) + *pcrel_p = 1; + if (address) + *address = addr; + /* This is not necessary during the disassembling, as print_address_func + in the disassemble_info will take care of the printing. But some + other callers may be still interested in getting the string in *STR, + so here we do snprintf regardless. */ + snprintf (buf, size, "#0x%" PRIx64, addr); + break; + + case AARCH64_OPND_ADDR_PCREL14: + case AARCH64_OPND_ADDR_PCREL19: + case AARCH64_OPND_ADDR_PCREL21: + case AARCH64_OPND_ADDR_PCREL26: + addr = pc + AARCH64_PCREL_OFFSET + opnd->imm.value; + if (pcrel_p) + *pcrel_p = 1; + if (address) + *address = addr; + /* This is not necessary during the disassembling, as print_address_func + in the disassemble_info will take care of the printing. But some + other callers may be still interested in getting the string in *STR, + so here we do snprintf regardless. */ + snprintf (buf, size, "#0x%" PRIx64, addr); + break; + + case AARCH64_OPND_ADDR_SIMPLE: + case AARCH64_OPND_SIMD_ADDR_SIMPLE: + case AARCH64_OPND_SIMD_ADDR_POST: + name = get_64bit_int_reg_name (opnd->addr.base_regno, 1); + if (opnd->type == AARCH64_OPND_SIMD_ADDR_POST) + { + if (opnd->addr.offset.is_reg) + snprintf (buf, size, "[%s], x%d", name, opnd->addr.offset.regno); + else + snprintf (buf, size, "[%s], #%d", name, opnd->addr.offset.imm); + } + else + snprintf (buf, size, "[%s]", name); + break; + + case AARCH64_OPND_ADDR_REGOFF: + print_register_offset_address (buf, size, opnd); + break; + + case AARCH64_OPND_ADDR_SIMM7: + case AARCH64_OPND_ADDR_SIMM9: + case AARCH64_OPND_ADDR_SIMM9_2: + name = get_64bit_int_reg_name (opnd->addr.base_regno, 1); + if (opnd->addr.writeback) + { + if (opnd->addr.preind) + snprintf (buf, size, "[%s,#%d]!", name, opnd->addr.offset.imm); + else + snprintf (buf, size, "[%s],#%d", name, opnd->addr.offset.imm); + } + else + { + if (opnd->addr.offset.imm) + snprintf (buf, size, "[%s,#%d]", name, opnd->addr.offset.imm); + else + snprintf (buf, size, "[%s]", name); + } + break; + + case AARCH64_OPND_ADDR_UIMM12: + name = get_64bit_int_reg_name (opnd->addr.base_regno, 1); + if (opnd->addr.offset.imm) + snprintf (buf, size, "[%s,#%d]", name, opnd->addr.offset.imm); + else + snprintf (buf, size, "[%s]", name); + break; + + case AARCH64_OPND_SYSREG: + for (i = 0; aarch64_sys_regs[i].name; ++i) + if (aarch64_sys_regs[i].value == opnd->sysreg) + break; + if (aarch64_sys_regs[i].name) + snprintf (buf, size, "%s", aarch64_sys_regs[i].name); + else + { + /* Implementation defined system register. */ + unsigned int value = opnd->sysreg; + snprintf (buf, size, "s%u_%u_c%u_c%u_%u", (value >> 14) & 0x3, + (value >> 11) & 0x7, (value >> 7) & 0xf, (value >> 3) & 0xf, + value & 0x7); + } + break; + + case AARCH64_OPND_PSTATEFIELD: + for (i = 0; aarch64_pstatefields[i].name; ++i) + if (aarch64_pstatefields[i].value == opnd->pstatefield) + break; + assert (aarch64_pstatefields[i].name); + snprintf (buf, size, "%s", aarch64_pstatefields[i].name); + break; + + case AARCH64_OPND_SYSREG_AT: + case AARCH64_OPND_SYSREG_DC: + case AARCH64_OPND_SYSREG_IC: + case AARCH64_OPND_SYSREG_TLBI: + snprintf (buf, size, "%s", opnd->sysins_op->template); + break; + + case AARCH64_OPND_BARRIER: + snprintf (buf, size, "%s", opnd->barrier->name); + break; + + case AARCH64_OPND_BARRIER_ISB: + /* Operand can be omitted, e.g. in DCPS1. */ + if (! optional_operand_p (opcode, idx) + || (opnd->barrier->value + != get_optional_operand_default_value (opcode))) + snprintf (buf, size, "#0x%x", opnd->barrier->value); + break; + + case AARCH64_OPND_PRFOP: + snprintf (buf, size, "%s", opnd->prfop->name); + break; + + default: + assert (0); + } +} + +#define CPENC(op0,op1,crn,crm,op2) \ + ((((op0) << 19) | ((op1) << 16) | ((crn) << 12) | ((crm) << 8) | ((op2) << 5)) >> 5) + /* for 3.9.3 Instructions for Accessing Special Purpose Registers */ +#define CPEN_(op1,crm,op2) CPENC(3,(op1),4,(crm),(op2)) + /* for 3.9.10 System Instructions */ +#define CPENS(op1,crn,crm,op2) CPENC(1,(op1),(crn),(crm),(op2)) + +#define C0 0 +#define C1 1 +#define C2 2 +#define C3 3 +#define C4 4 +#define C5 5 +#define C6 6 +#define C7 7 +#define C8 8 +#define C9 9 +#define C10 10 +#define C11 11 +#define C12 12 +#define C13 13 +#define C14 14 +#define C15 15 + +/* TODO there are two more issues need to be resolved + 1. handle read-only and write-only system registers + 2. handle cpu-implementation-defined system registers. */ +const struct aarch64_name_value_pair aarch64_sys_regs [] = +{ + { "spsr_el1", CPEN_(0,C0,0) }, /* = spsr_svc */ + { "elr_el1", CPEN_(0,C0,1) }, + { "sp_el0", CPEN_(0,C1,0) }, + { "spsel", CPEN_(0,C2,0) }, + { "daif", CPEN_(3,C2,1) }, + { "currentel", CPEN_(0,C2,2) }, /* RO */ + { "nzcv", CPEN_(3,C2,0) }, + { "fpcr", CPEN_(3,C4,0) }, + { "fpsr", CPEN_(3,C4,1) }, + { "dspsr_el0", CPEN_(3,C5,0) }, + { "dlr_el0", CPEN_(3,C5,1) }, + { "spsr_el2", CPEN_(4,C0,0) }, /* = spsr_hyp */ + { "elr_el2", CPEN_(4,C0,1) }, + { "sp_el1", CPEN_(4,C1,0) }, + { "spsr_irq", CPEN_(4,C3,0) }, + { "spsr_abt", CPEN_(4,C3,1) }, + { "spsr_und", CPEN_(4,C3,2) }, + { "spsr_fiq", CPEN_(4,C3,3) }, + { "spsr_el3", CPEN_(6,C0,0) }, + { "elr_el3", CPEN_(6,C0,1) }, + { "sp_el2", CPEN_(6,C1,0) }, + { "spsr_svc", CPEN_(0,C0,0) }, /* = spsr_el1 */ + { "spsr_hyp", CPEN_(4,C0,0) }, /* = spsr_el2 */ + { "midr_el1", CPENC(3,0,C0,C0,0) }, /* RO */ + { "ctr_el0", CPENC(3,3,C0,C0,1) }, /* RO */ + { "mpidr_el1", CPENC(3,0,C0,C0,5) }, /* RO */ + { "revidr_el1", CPENC(3,0,C0,C0,6) }, /* RO */ + { "aidr_el1", CPENC(3,1,C0,C0,7) }, /* RO */ + { "dczid_el0", CPENC(3,3,C0,C0,7) }, /* RO */ + { "id_dfr0_el1", CPENC(3,0,C0,C1,2) }, /* RO */ + { "id_pfr0_el1", CPENC(3,0,C0,C1,0) }, /* RO */ + { "id_pfr1_el1", CPENC(3,0,C0,C1,1) }, /* RO */ + { "id_afr0_el1", CPENC(3,0,C0,C1,3) }, /* RO */ + { "id_mmfr0_el1", CPENC(3,0,C0,C1,4) }, /* RO */ + { "id_mmfr1_el1", CPENC(3,0,C0,C1,5) }, /* RO */ + { "id_mmfr2_el1", CPENC(3,0,C0,C1,6) }, /* RO */ + { "id_mmfr3_el1", CPENC(3,0,C0,C1,7) }, /* RO */ + { "id_isar0_el1", CPENC(3,0,C0,C2,0) }, /* RO */ + { "id_isar1_el1", CPENC(3,0,C0,C2,1) }, /* RO */ + { "id_isar2_el1", CPENC(3,0,C0,C2,2) }, /* RO */ + { "id_isar3_el1", CPENC(3,0,C0,C2,3) }, /* RO */ + { "id_isar4_el1", CPENC(3,0,C0,C2,4) }, /* RO */ + { "id_isar5_el1", CPENC(3,0,C0,C2,5) }, /* RO */ + { "mvfr0_el1", CPENC(3,0,C0,C3,0) }, /* RO */ + { "mvfr1_el1", CPENC(3,0,C0,C3,1) }, /* RO */ + { "mvfr2_el1", CPENC(3,0,C0,C3,2) }, /* RO */ + { "ccsidr_el1", CPENC(3,1,C0,C0,0) }, /* RO */ + { "id_aa64pfr0_el1", CPENC(3,0,C0,C4,0) }, /* RO */ + { "id_aa64pfr1_el1", CPENC(3,0,C0,C4,1) }, /* RO */ + { "id_aa64dfr0_el1", CPENC(3,0,C0,C5,0) }, /* RO */ + { "id_aa64dfr1_el1", CPENC(3,0,C0,C5,1) }, /* RO */ + { "id_aa64isar0_el1", CPENC(3,0,C0,C6,0) }, /* RO */ + { "id_aa64isar1_el1", CPENC(3,0,C0,C6,1) }, /* RO */ + { "id_aa64mmfr0_el1", CPENC(3,0,C0,C7,0) }, /* RO */ + { "id_aa64mmfr1_el1", CPENC(3,0,C0,C7,1) }, /* RO */ + { "id_aa64afr0_el1", CPENC(3,0,C0,C5,4) }, /* RO */ + { "id_aa64afr1_el1", CPENC(3,0,C0,C5,5) }, /* RO */ + { "clidr_el1", CPENC(3,1,C0,C0,1) }, /* RO */ + { "csselr_el1", CPENC(3,2,C0,C0,0) }, /* RO */ + { "vpidr_el2", CPENC(3,4,C0,C0,0) }, + { "vmpidr_el2", CPENC(3,4,C0,C0,5) }, + { "sctlr_el1", CPENC(3,0,C1,C0,0) }, + { "sctlr_el2", CPENC(3,4,C1,C0,0) }, + { "sctlr_el3", CPENC(3,6,C1,C0,0) }, + { "actlr_el1", CPENC(3,0,C1,C0,1) }, + { "actlr_el2", CPENC(3,4,C1,C0,1) }, + { "actlr_el3", CPENC(3,6,C1,C0,1) }, + { "cpacr_el1", CPENC(3,0,C1,C0,2) }, + { "cptr_el2", CPENC(3,4,C1,C1,2) }, + { "cptr_el3", CPENC(3,6,C1,C1,2) }, + { "scr_el3", CPENC(3,6,C1,C1,0) }, + { "hcr_el2", CPENC(3,4,C1,C1,0) }, + { "mdcr_el2", CPENC(3,4,C1,C1,1) }, + { "mdcr_el3", CPENC(3,6,C1,C3,1) }, + { "hstr_el2", CPENC(3,4,C1,C1,3) }, + { "hacr_el2", CPENC(3,4,C1,C1,7) }, + { "ttbr0_el1", CPENC(3,0,C2,C0,0) }, + { "ttbr1_el1", CPENC(3,0,C2,C0,1) }, + { "ttbr0_el2", CPENC(3,4,C2,C0,0) }, + { "ttbr0_el3", CPENC(3,6,C2,C0,0) }, + { "vttbr_el2", CPENC(3,4,C2,C1,0) }, + { "tcr_el1", CPENC(3,0,C2,C0,2) }, + { "tcr_el2", CPENC(3,4,C2,C0,2) }, + { "tcr_el3", CPENC(3,6,C2,C0,2) }, + { "vtcr_el2", CPENC(3,4,C2,C1,2) }, + { "afsr0_el1", CPENC(3,0,C5,C1,0) }, + { "afsr1_el1", CPENC(3,0,C5,C1,1) }, + { "afsr0_el2", CPENC(3,4,C5,C1,0) }, + { "afsr1_el2", CPENC(3,4,C5,C1,1) }, + { "afsr0_el3", CPENC(3,6,C5,C1,0) }, + { "afsr1_el3", CPENC(3,6,C5,C1,1) }, + { "esr_el1", CPENC(3,0,C5,C2,0) }, + { "esr_el2", CPENC(3,4,C5,C2,0) }, + { "esr_el3", CPENC(3,6,C5,C2,0) }, + { "fpexc32_el2", CPENC(3,4,C5,C3,0) }, + { "far_el1", CPENC(3,0,C6,C0,0) }, + { "far_el2", CPENC(3,4,C6,C0,0) }, + { "far_el3", CPENC(3,6,C6,C0,0) }, + { "hpfar_el2", CPENC(3,4,C6,C0,4) }, + { "par_el1", CPENC(3,0,C7,C4,0) }, + { "mair_el1", CPENC(3,0,C10,C2,0) }, + { "mair_el2", CPENC(3,4,C10,C2,0) }, + { "mair_el3", CPENC(3,6,C10,C2,0) }, + { "amair_el1", CPENC(3,0,C10,C3,0) }, + { "amair_el2", CPENC(3,4,C10,C3,0) }, + { "amair_el3", CPENC(3,6,C10,C3,0) }, + { "vbar_el1", CPENC(3,0,C12,C0,0) }, + { "vbar_el2", CPENC(3,4,C12,C0,0) }, + { "vbar_el3", CPENC(3,6,C12,C0,0) }, + { "rvbar_el1", CPENC(3,0,C12,C0,1) }, /* RO */ + { "rvbar_el2", CPENC(3,4,C12,C0,1) }, /* RO */ + { "rvbar_el3", CPENC(3,6,C12,C0,1) }, /* RO */ + { "isr_el1", CPENC(3,0,C12,C1,0) }, /* RO */ + { "contextidr_el1", CPENC(3,0,C13,C0,1) }, + { "tpidr_el0", CPENC(3,3,C13,C0,2) }, + { "tpidrro_el0", CPENC(3,3,C13,C0,3) }, /* RO */ + { "tpidr_el1", CPENC(3,0,C13,C0,4) }, + { "tpidr_el2", CPENC(3,4,C13,C0,2) }, + { "tpidr_el3", CPENC(3,6,C13,C0,2) }, + { "teecr32_el1", CPENC(2,2,C0, C0,0) }, /* See section 3.9.7.1 */ + { "cntfrq_el0", CPENC(3,3,C14,C0,0) }, /* RO */ + { "cntpct_el0", CPENC(3,3,C14,C0,1) }, /* RO */ + { "cntvct_el0", CPENC(3,3,C14,C0,2) }, /* RO */ + { "cntvoff_el2", CPENC(3,4,C14,C0,3) }, + { "cntkctl_el1", CPENC(3,0,C14,C1,0) }, + { "cnthctl_el2", CPENC(3,4,C14,C1,0) }, + { "cntp_tval_el0", CPENC(3,3,C14,C2,0) }, + { "cntp_ctl_el0", CPENC(3,3,C14,C2,1) }, + { "cntp_cval_el0", CPENC(3,3,C14,C2,2) }, + { "cntv_tval_el0", CPENC(3,3,C14,C3,0) }, + { "cntv_ctl_el0", CPENC(3,3,C14,C3,1) }, + { "cntv_cval_el0", CPENC(3,3,C14,C3,2) }, + { "cnthp_tval_el2", CPENC(3,4,C14,C2,0) }, + { "cnthp_ctl_el2", CPENC(3,4,C14,C2,1) }, + { "cnthp_cval_el2", CPENC(3,4,C14,C2,2) }, + { "cntps_tval_el1", CPENC(3,7,C14,C2,0) }, + { "cntps_ctl_el1", CPENC(3,7,C14,C2,1) }, + { "cntps_cval_el1", CPENC(3,7,C14,C2,2) }, + { "dacr32_el2", CPENC(3,4,C3,C0,0) }, + { "ifsr32_el2", CPENC(3,4,C5,C0,1) }, + { "teehbr32_el1", CPENC(2,2,C1,C0,0) }, + { "sder32_el3", CPENC(3,6,C1,C1,1) }, + { "mdscr_el1", CPENC(2,0,C0, C2, 2) }, + { "mdccsr_el0", CPENC(2,3,C0, C1, 0) }, /* r */ + { "mdccint_el1", CPENC(2,0,C0, C2, 0) }, + { "dbgdtr_el0", CPENC(2,3,C0, C4, 0) }, + { "dbgdtrrx_el0", CPENC(2,3,C0, C5, 0) }, /* r */ + { "dbgdtrtx_el0", CPENC(2,3,C0, C5, 0) }, /* w */ + { "osdtrrx_el1", CPENC(2,0,C0, C0, 2) }, /* r */ + { "osdtrtx_el1", CPENC(2,0,C0, C3, 2) }, /* w */ + { "oseccr_el1", CPENC(2,0,C0, C6, 2) }, + { "dbgvcr32_el2", CPENC(2,4,C0, C7, 0) }, + { "dbgbvr0_el1", CPENC(2,0,C0, C0, 4) }, + { "dbgbvr1_el1", CPENC(2,0,C0, C1, 4) }, + { "dbgbvr2_el1", CPENC(2,0,C0, C2, 4) }, + { "dbgbvr3_el1", CPENC(2,0,C0, C3, 4) }, + { "dbgbvr4_el1", CPENC(2,0,C0, C4, 4) }, + { "dbgbvr5_el1", CPENC(2,0,C0, C5, 4) }, + { "dbgbvr6_el1", CPENC(2,0,C0, C6, 4) }, + { "dbgbvr7_el1", CPENC(2,0,C0, C7, 4) }, + { "dbgbvr8_el1", CPENC(2,0,C0, C8, 4) }, + { "dbgbvr9_el1", CPENC(2,0,C0, C9, 4) }, + { "dbgbvr10_el1", CPENC(2,0,C0, C10,4) }, + { "dbgbvr11_el1", CPENC(2,0,C0, C11,4) }, + { "dbgbvr12_el1", CPENC(2,0,C0, C12,4) }, + { "dbgbvr13_el1", CPENC(2,0,C0, C13,4) }, + { "dbgbvr14_el1", CPENC(2,0,C0, C14,4) }, + { "dbgbvr15_el1", CPENC(2,0,C0, C15,4) }, + { "dbgbcr0_el1", CPENC(2,0,C0, C0, 5) }, + { "dbgbcr1_el1", CPENC(2,0,C0, C1, 5) }, + { "dbgbcr2_el1", CPENC(2,0,C0, C2, 5) }, + { "dbgbcr3_el1", CPENC(2,0,C0, C3, 5) }, + { "dbgbcr4_el1", CPENC(2,0,C0, C4, 5) }, + { "dbgbcr5_el1", CPENC(2,0,C0, C5, 5) }, + { "dbgbcr6_el1", CPENC(2,0,C0, C6, 5) }, + { "dbgbcr7_el1", CPENC(2,0,C0, C7, 5) }, + { "dbgbcr8_el1", CPENC(2,0,C0, C8, 5) }, + { "dbgbcr9_el1", CPENC(2,0,C0, C9, 5) }, + { "dbgbcr10_el1", CPENC(2,0,C0, C10,5) }, + { "dbgbcr11_el1", CPENC(2,0,C0, C11,5) }, + { "dbgbcr12_el1", CPENC(2,0,C0, C12,5) }, + { "dbgbcr13_el1", CPENC(2,0,C0, C13,5) }, + { "dbgbcr14_el1", CPENC(2,0,C0, C14,5) }, + { "dbgbcr15_el1", CPENC(2,0,C0, C15,5) }, + { "dbgwvr0_el1", CPENC(2,0,C0, C0, 6) }, + { "dbgwvr1_el1", CPENC(2,0,C0, C1, 6) }, + { "dbgwvr2_el1", CPENC(2,0,C0, C2, 6) }, + { "dbgwvr3_el1", CPENC(2,0,C0, C3, 6) }, + { "dbgwvr4_el1", CPENC(2,0,C0, C4, 6) }, + { "dbgwvr5_el1", CPENC(2,0,C0, C5, 6) }, + { "dbgwvr6_el1", CPENC(2,0,C0, C6, 6) }, + { "dbgwvr7_el1", CPENC(2,0,C0, C7, 6) }, + { "dbgwvr8_el1", CPENC(2,0,C0, C8, 6) }, + { "dbgwvr9_el1", CPENC(2,0,C0, C9, 6) }, + { "dbgwvr10_el1", CPENC(2,0,C0, C10,6) }, + { "dbgwvr11_el1", CPENC(2,0,C0, C11,6) }, + { "dbgwvr12_el1", CPENC(2,0,C0, C12,6) }, + { "dbgwvr13_el1", CPENC(2,0,C0, C13,6) }, + { "dbgwvr14_el1", CPENC(2,0,C0, C14,6) }, + { "dbgwvr15_el1", CPENC(2,0,C0, C15,6) }, + { "dbgwcr0_el1", CPENC(2,0,C0, C0, 7) }, + { "dbgwcr1_el1", CPENC(2,0,C0, C1, 7) }, + { "dbgwcr2_el1", CPENC(2,0,C0, C2, 7) }, + { "dbgwcr3_el1", CPENC(2,0,C0, C3, 7) }, + { "dbgwcr4_el1", CPENC(2,0,C0, C4, 7) }, + { "dbgwcr5_el1", CPENC(2,0,C0, C5, 7) }, + { "dbgwcr6_el1", CPENC(2,0,C0, C6, 7) }, + { "dbgwcr7_el1", CPENC(2,0,C0, C7, 7) }, + { "dbgwcr8_el1", CPENC(2,0,C0, C8, 7) }, + { "dbgwcr9_el1", CPENC(2,0,C0, C9, 7) }, + { "dbgwcr10_el1", CPENC(2,0,C0, C10,7) }, + { "dbgwcr11_el1", CPENC(2,0,C0, C11,7) }, + { "dbgwcr12_el1", CPENC(2,0,C0, C12,7) }, + { "dbgwcr13_el1", CPENC(2,0,C0, C13,7) }, + { "dbgwcr14_el1", CPENC(2,0,C0, C14,7) }, + { "dbgwcr15_el1", CPENC(2,0,C0, C15,7) }, + { "mdrar_el1", CPENC(2,0,C1, C0, 0) }, /* r */ + { "oslar_el1", CPENC(2,0,C1, C0, 4) }, /* w */ + { "oslsr_el1", CPENC(2,0,C1, C1, 4) }, /* r */ + { "osdlr_el1", CPENC(2,0,C1, C3, 4) }, + { "dbgprcr_el1", CPENC(2,0,C1, C4, 4) }, + { "dbgclaimset_el1", CPENC(2,0,C7, C8, 6) }, + { "dbgclaimclr_el1", CPENC(2,0,C7, C9, 6) }, + { "dbgauthstatus_el1", CPENC(2,0,C7, C14,6) }, /* r */ + + { "pmcr_el0", CPENC(3,3,C9,C12, 0) }, + { "pmcntenset_el0", CPENC(3,3,C9,C12, 1) }, + { "pmcntenclr_el0", CPENC(3,3,C9,C12, 2) }, + { "pmovsclr_el0", CPENC(3,3,C9,C12, 3) }, + { "pmswinc_el0", CPENC(3,3,C9,C12, 4) }, /* w */ + { "pmselr_el0", CPENC(3,3,C9,C12, 5) }, + { "pmceid0_el0", CPENC(3,3,C9,C12, 6) }, /* r */ + { "pmceid1_el0", CPENC(3,3,C9,C12, 7) }, /* r */ + { "pmccntr_el0", CPENC(3,3,C9,C13, 0) }, + { "pmxevtyper_el0", CPENC(3,3,C9,C13, 1) }, + { "pmxevcntr_el0", CPENC(3,3,C9,C13, 2) }, + { "pmuserenr_el0", CPENC(3,3,C9,C14, 0) }, + { "pmintenset_el1", CPENC(3,0,C9,C14, 1) }, + { "pmintenclr_el1", CPENC(3,0,C9,C14, 2) }, + { "pmovsset_el0", CPENC(3,3,C9,C14, 3) }, + { "pmevcntr0_el0", CPENC(3,3,C14,C8, 0) }, + { "pmevcntr1_el0", CPENC(3,3,C14,C8, 1) }, + { "pmevcntr2_el0", CPENC(3,3,C14,C8, 2) }, + { "pmevcntr3_el0", CPENC(3,3,C14,C8, 3) }, + { "pmevcntr4_el0", CPENC(3,3,C14,C8, 4) }, + { "pmevcntr5_el0", CPENC(3,3,C14,C8, 5) }, + { "pmevcntr6_el0", CPENC(3,3,C14,C8, 6) }, + { "pmevcntr7_el0", CPENC(3,3,C14,C8, 7) }, + { "pmevcntr8_el0", CPENC(3,3,C14,C9, 0) }, + { "pmevcntr9_el0", CPENC(3,3,C14,C9, 1) }, + { "pmevcntr10_el0", CPENC(3,3,C14,C9, 2) }, + { "pmevcntr11_el0", CPENC(3,3,C14,C9, 3) }, + { "pmevcntr12_el0", CPENC(3,3,C14,C9, 4) }, + { "pmevcntr13_el0", CPENC(3,3,C14,C9, 5) }, + { "pmevcntr14_el0", CPENC(3,3,C14,C9, 6) }, + { "pmevcntr15_el0", CPENC(3,3,C14,C9, 7) }, + { "pmevcntr16_el0", CPENC(3,3,C14,C10,0) }, + { "pmevcntr17_el0", CPENC(3,3,C14,C10,1) }, + { "pmevcntr18_el0", CPENC(3,3,C14,C10,2) }, + { "pmevcntr19_el0", CPENC(3,3,C14,C10,3) }, + { "pmevcntr20_el0", CPENC(3,3,C14,C10,4) }, + { "pmevcntr21_el0", CPENC(3,3,C14,C10,5) }, + { "pmevcntr22_el0", CPENC(3,3,C14,C10,6) }, + { "pmevcntr23_el0", CPENC(3,3,C14,C10,7) }, + { "pmevcntr24_el0", CPENC(3,3,C14,C11,0) }, + { "pmevcntr25_el0", CPENC(3,3,C14,C11,1) }, + { "pmevcntr26_el0", CPENC(3,3,C14,C11,2) }, + { "pmevcntr27_el0", CPENC(3,3,C14,C11,3) }, + { "pmevcntr28_el0", CPENC(3,3,C14,C11,4) }, + { "pmevcntr29_el0", CPENC(3,3,C14,C11,5) }, + { "pmevcntr30_el0", CPENC(3,3,C14,C11,6) }, + { "pmevtyper0_el0", CPENC(3,3,C14,C12,0) }, + { "pmevtyper1_el0", CPENC(3,3,C14,C12,1) }, + { "pmevtyper2_el0", CPENC(3,3,C14,C12,2) }, + { "pmevtyper3_el0", CPENC(3,3,C14,C12,3) }, + { "pmevtyper4_el0", CPENC(3,3,C14,C12,4) }, + { "pmevtyper5_el0", CPENC(3,3,C14,C12,5) }, + { "pmevtyper6_el0", CPENC(3,3,C14,C12,6) }, + { "pmevtyper7_el0", CPENC(3,3,C14,C12,7) }, + { "pmevtyper8_el0", CPENC(3,3,C14,C13,0) }, + { "pmevtyper9_el0", CPENC(3,3,C14,C13,1) }, + { "pmevtyper10_el0", CPENC(3,3,C14,C13,2) }, + { "pmevtyper11_el0", CPENC(3,3,C14,C13,3) }, + { "pmevtyper12_el0", CPENC(3,3,C14,C13,4) }, + { "pmevtyper13_el0", CPENC(3,3,C14,C13,5) }, + { "pmevtyper14_el0", CPENC(3,3,C14,C13,6) }, + { "pmevtyper15_el0", CPENC(3,3,C14,C13,7) }, + { "pmevtyper16_el0", CPENC(3,3,C14,C14,0) }, + { "pmevtyper17_el0", CPENC(3,3,C14,C14,1) }, + { "pmevtyper18_el0", CPENC(3,3,C14,C14,2) }, + { "pmevtyper19_el0", CPENC(3,3,C14,C14,3) }, + { "pmevtyper20_el0", CPENC(3,3,C14,C14,4) }, + { "pmevtyper21_el0", CPENC(3,3,C14,C14,5) }, + { "pmevtyper22_el0", CPENC(3,3,C14,C14,6) }, + { "pmevtyper23_el0", CPENC(3,3,C14,C14,7) }, + { "pmevtyper24_el0", CPENC(3,3,C14,C15,0) }, + { "pmevtyper25_el0", CPENC(3,3,C14,C15,1) }, + { "pmevtyper26_el0", CPENC(3,3,C14,C15,2) }, + { "pmevtyper27_el0", CPENC(3,3,C14,C15,3) }, + { "pmevtyper28_el0", CPENC(3,3,C14,C15,4) }, + { "pmevtyper29_el0", CPENC(3,3,C14,C15,5) }, + { "pmevtyper30_el0", CPENC(3,3,C14,C15,6) }, + { "pmccfiltr_el0", CPENC(3,3,C14,C15,7) }, + + { "daifset", CPENC(0,3,C4,C0,6) }, + { "daifclr", CPENC(0,3,C4,C0,7) }, + + { 0, CPENC(0,0,0,0,0) }, +}; + +const struct aarch64_name_value_pair aarch64_pstatefields [] = +{ + { "spsel", 0x05 }, + { "daifset", 0x1e }, + { "daifclr", 0x1f }, + { 0, CPENC(0,0,0,0,0) }, +}; + +const aarch64_sys_ins_reg aarch64_sys_regs_ic[] = +{ + { "ialluis", CPENS(0,C7,C1,0), 0 }, + { "iallu", CPENS(0,C7,C5,0), 0 }, + { "ivau", CPENS(3,C7,C5,1), 1 }, + { 0, CPENS(0,0,0,0), 0 } +}; + +const aarch64_sys_ins_reg aarch64_sys_regs_dc[] = +{ + { "zva", CPENS(3,C7,C4,1), 1 }, + { "ivac", CPENS(0,C7,C6,1), 1 }, + { "isw", CPENS(0,C7,C6,2), 1 }, + { "cvac", CPENS(3,C7,C10,1), 1 }, + { "csw", CPENS(0,C7,C10,2), 1 }, + { "cvau", CPENS(3,C7,C11,1), 1 }, + { "civac", CPENS(3,C7,C14,1), 1 }, + { "cisw", CPENS(0,C7,C14,2), 1 }, + { 0, CPENS(0,0,0,0), 0 } +}; + +const aarch64_sys_ins_reg aarch64_sys_regs_at[] = +{ + { "s1e1r", CPENS(0,C7,C8,0), 1 }, + { "s1e1w", CPENS(0,C7,C8,1), 1 }, + { "s1e0r", CPENS(0,C7,C8,2), 1 }, + { "s1e0w", CPENS(0,C7,C8,3), 1 }, + { "s12e1r", CPENS(4,C7,C8,4), 1 }, + { "s12e1w", CPENS(4,C7,C8,5), 1 }, + { "s12e0r", CPENS(4,C7,C8,6), 1 }, + { "s12e0w", CPENS(4,C7,C8,7), 1 }, + { "s1e2r", CPENS(4,C7,C8,0), 1 }, + { "s1e2w", CPENS(4,C7,C8,1), 1 }, + { "s1e3r", CPENS(6,C7,C8,0), 1 }, + { "s1e3w", CPENS(6,C7,C8,1), 1 }, + { 0, CPENS(0,0,0,0), 0 } +}; + +const aarch64_sys_ins_reg aarch64_sys_regs_tlbi[] = +{ + { "vmalle1", CPENS(0,C8,C7,0), 0 }, + { "vae1", CPENS(0,C8,C7,1), 1 }, + { "aside1", CPENS(0,C8,C7,2), 1 }, + { "vaae1", CPENS(0,C8,C7,3), 1 }, + { "vmalle1is", CPENS(0,C8,C3,0), 0 }, + { "vae1is", CPENS(0,C8,C3,1), 1 }, + { "aside1is", CPENS(0,C8,C3,2), 1 }, + { "vaae1is", CPENS(0,C8,C3,3), 1 }, + { "ipas2e1is", CPENS(4,C8,C0,1), 1 }, + { "ipas2le1is",CPENS(4,C8,C0,5), 1 }, + { "ipas2e1", CPENS(4,C8,C4,1), 1 }, + { "ipas2le1", CPENS(4,C8,C4,5), 1 }, + { "vae2", CPENS(4,C8,C7,1), 1 }, + { "vae2is", CPENS(4,C8,C3,1), 1 }, + { "vmalls12e1",CPENS(4,C8,C7,6), 0 }, + { "vmalls12e1is",CPENS(4,C8,C3,6), 0 }, + { "vae3", CPENS(6,C8,C7,1), 1 }, + { "vae3is", CPENS(6,C8,C3,1), 1 }, + { "alle2", CPENS(4,C8,C7,0), 0 }, + { "alle2is", CPENS(4,C8,C3,0), 0 }, + { "alle1", CPENS(4,C8,C7,4), 0 }, + { "alle1is", CPENS(4,C8,C3,4), 0 }, + { "alle3", CPENS(6,C8,C7,0), 0 }, + { "alle3is", CPENS(6,C8,C3,0), 0 }, + { "vale1is", CPENS(0,C8,C3,5), 1 }, + { "vale2is", CPENS(4,C8,C3,5), 1 }, + { "vale3is", CPENS(6,C8,C3,5), 1 }, + { "vaale1is", CPENS(0,C8,C3,7), 1 }, + { "vale1", CPENS(0,C8,C7,5), 1 }, + { "vale2", CPENS(4,C8,C7,5), 1 }, + { "vale3", CPENS(6,C8,C7,5), 1 }, + { "vaale1", CPENS(0,C8,C7,7), 1 }, + { 0, CPENS(0,0,0,0), 0 } +}; + +#undef C0 +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +#undef C8 +#undef C9 +#undef C10 +#undef C11 +#undef C12 +#undef C13 +#undef C14 +#undef C15 + +/* Include the opcode description table as well as the operand description + table. */ +#include "aarch64-tbl.h" diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h new file mode 100644 index 0000000..d475fa4 --- /dev/null +++ b/opcodes/aarch64-opc.h @@ -0,0 +1,392 @@ +/* aarch64-opc.h -- Header file for aarch64-opc.c and aarch64-opc-2.c. + Copyright 2012 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING3. If not, + see <http://www.gnu.org/licenses/>. */ + +#ifndef OPCODES_AARCH64_OPC_H +#define OPCODES_AARCH64_OPC_H + +#include <string.h> +#include "opcode/aarch64.h" + +/* Instruction fields. + Keep synced with fields. */ +enum aarch64_field_kind +{ + FLD_NIL, + FLD_cond2, + FLD_nzcv, + FLD_defgh, + FLD_abc, + FLD_imm19, + FLD_immhi, + FLD_immlo, + FLD_size, + FLD_vldst_size, + FLD_op, + FLD_Q, + FLD_Rt, + FLD_Rd, + FLD_Rn, + FLD_Rt2, + FLD_Ra, + FLD_op2, + FLD_CRm, + FLD_CRn, + FLD_op1, + FLD_op0, + FLD_imm3, + FLD_cond, + FLD_opcode, + FLD_cmode, + FLD_asisdlso_opcode, + FLD_len, + FLD_Rm, + FLD_Rs, + FLD_option, + FLD_S, + FLD_hw, + FLD_opc, + FLD_opc1, + FLD_shift, + FLD_type, + FLD_ldst_size, + FLD_imm6, + FLD_imm4, + FLD_imm5, + FLD_imm7, + FLD_imm8, + FLD_imm9, + FLD_imm12, + FLD_imm14, + FLD_imm16, + FLD_imm26, + FLD_imms, + FLD_immr, + FLD_immb, + FLD_immh, + FLD_N, + FLD_index, + FLD_index2, + FLD_sf, + FLD_H, + FLD_L, + FLD_M, + FLD_b5, + FLD_b40, + FLD_scale, +}; + +/* Field description. */ +struct aarch64_field +{ + int lsb; + int width; +}; + +typedef struct aarch64_field aarch64_field; + +extern const aarch64_field fields[]; + +/* Operand description. */ + +struct aarch64_operand +{ + enum aarch64_operand_class op_class; + + /* Name of the operand code; used mainly for the purpose of internal + debugging. */ + const char *name; + + unsigned int flags; + + /* The associated instruction bit-fields; no operand has more than 4 + bit-fields */ + enum aarch64_field_kind fields[4]; + + /* Brief description */ + const char *desc; +}; + +typedef struct aarch64_operand aarch64_operand; + +extern const aarch64_operand aarch64_operands[]; + +/* Operand flags. */ + +#define OPD_F_HAS_INSERTER 0x00000001 +#define OPD_F_HAS_EXTRACTOR 0x00000002 +#define OPD_F_SEXT 0x00000004 /* Require sign-extension. */ +#define OPD_F_SHIFT_BY_2 0x00000008 /* Need to left shift the field + value by 2 to get the value + of an immediate operand. */ +#define OPD_F_MAYBE_SP 0x00000010 /* May potentially be SP. */ + +static inline bfd_boolean +operand_has_inserter (const aarch64_operand *operand) +{ + return (operand->flags & OPD_F_HAS_INSERTER) ? TRUE : FALSE; +} + +static inline bfd_boolean +operand_has_extractor (const aarch64_operand *operand) +{ + return (operand->flags & OPD_F_HAS_EXTRACTOR) ? TRUE : FALSE; +} + +static inline bfd_boolean +operand_need_sign_extension (const aarch64_operand *operand) +{ + return (operand->flags & OPD_F_SEXT) ? TRUE : FALSE; +} + +static inline bfd_boolean +operand_need_shift_by_two (const aarch64_operand *operand) +{ + return (operand->flags & OPD_F_SHIFT_BY_2) ? TRUE : FALSE; +} + +static inline bfd_boolean +operand_maybe_stack_pointer (const aarch64_operand *operand) +{ + return (operand->flags & OPD_F_MAYBE_SP) ? TRUE : FALSE; +} + +/* Return the total width of the operand *OPERAND. */ +static inline unsigned +get_operand_fields_width (const aarch64_operand *operand) +{ + int i = 0; + unsigned width = 0; + while (operand->fields[i] != FLD_NIL) + width += fields[operand->fields[i++]].width; + assert (width > 0 && width < 32); + return width; +} + +static inline const aarch64_operand * +get_operand_from_code (enum aarch64_opnd code) +{ + return aarch64_operands + code; +} + +/* Operand qualifier and operand constraint checking. */ + +int aarch64_match_operands_constraint (aarch64_inst *, + aarch64_operand_error *); + +/* Operand qualifier related functions. */ +const char* aarch64_get_qualifier_name (aarch64_opnd_qualifier_t); +unsigned char aarch64_get_qualifier_nelem (aarch64_opnd_qualifier_t); +aarch64_insn aarch64_get_qualifier_standard_value (aarch64_opnd_qualifier_t); +int aarch64_find_best_match (const aarch64_inst *, + const aarch64_opnd_qualifier_seq_t *, + int, aarch64_opnd_qualifier_t *); + +static inline void +reset_operand_qualifier (aarch64_inst *inst, int idx) +{ + assert (idx >=0 && idx < aarch64_num_of_operands (inst->opcode)); + inst->operands[idx].qualifier = AARCH64_OPND_QLF_NIL; +} + +/* Inline functions operating on instruction bit-field(s). */ + +/* Generate a mask that has WIDTH number of consecutive 1s. */ + +static inline aarch64_insn +gen_mask (int width) +{ + return ((aarch64_insn) 1 << width) - 1;; +} + +/* LSB_REL is the relative location of the lsb in the sub field, starting from 0. */ +static inline int +gen_sub_field (enum aarch64_field_kind kind, int lsb_rel, int width, aarch64_field *ret) +{ + const aarch64_field *field = &fields[kind]; + if (lsb_rel < 0 || width <= 0 || lsb_rel + width > field->width) + return 0; + ret->lsb = field->lsb + lsb_rel; + ret->width = width; + return 1; +} + +/* Insert VALUE into FIELD of CODE. MASK can be zero or the base mask + of the opcode. */ + +static inline void +insert_field_2 (const aarch64_field *field, aarch64_insn *code, + aarch64_insn value, aarch64_insn mask) +{ + assert (field->width < 32 && field->width >= 1 && field->lsb >= 0 + && field->lsb + field->width <= 32); + value &= gen_mask (field->width); + value <<= field->lsb; + /* In some opcodes, field can be part of the base opcode, e.g. the size + field in FADD. The following helps avoid corrupt the base opcode. */ + value &= ~mask; + *code |= value; +} + +/* Extract FIELD of CODE and return the value. MASK can be zero or the base + mask of the opcode. */ + +static inline aarch64_insn +extract_field_2 (const aarch64_field *field, aarch64_insn code, + aarch64_insn mask) +{ + aarch64_insn value; + /* Clear any bit that is a part of the base opcode. */ + code &= ~mask; + value = (code >> field->lsb) & gen_mask (field->width); + return value; +} + +/* Insert VALUE into field KIND of CODE. MASK can be zero or the base mask + of the opcode. */ + +static inline void +insert_field (enum aarch64_field_kind kind, aarch64_insn *code, + aarch64_insn value, aarch64_insn mask) +{ + insert_field_2 (&fields[kind], code, value, mask); +} + +/* Extract field KIND of CODE and return the value. MASK can be zero or the + base mask of the opcode. */ + +static inline aarch64_insn +extract_field (enum aarch64_field_kind kind, aarch64_insn code, + aarch64_insn mask) +{ + return extract_field_2 (&fields[kind], code, mask); +} + +/* Inline functions selecting operand to do the encoding/decoding for a + certain instruction bit-field. */ + +/* Select the operand to do the encoding/decoding of the 'sf' field. + The heuristic-based rule is that the result operand is respected more. */ + +static inline int +select_operand_for_sf_field_coding (const aarch64_opcode *opcode) +{ + int idx = -1; + if (aarch64_get_operand_class (opcode->operands[0]) + == AARCH64_OPND_CLASS_INT_REG) + /* normal case. */ + idx = 0; + else if (aarch64_get_operand_class (opcode->operands[1]) + == AARCH64_OPND_CLASS_INT_REG) + /* e.g. float2fix. */ + idx = 1; + else + { assert (0); abort (); } + return idx; +} + +/* Select the operand to do the encoding/decoding of the 'type' field in + the floating-point instructions. + The heuristic-based rule is that the source operand is respected more. */ + +static inline int +select_operand_for_fptype_field_coding (const aarch64_opcode *opcode) +{ + int idx; + if (aarch64_get_operand_class (opcode->operands[1]) + == AARCH64_OPND_CLASS_FP_REG) + /* normal case. */ + idx = 1; + else if (aarch64_get_operand_class (opcode->operands[0]) + == AARCH64_OPND_CLASS_FP_REG) + /* e.g. float2fix. */ + idx = 0; + else + { assert (0); abort (); } + return idx; +} + +/* Select the operand to do the encoding/decoding of the 'size' field in + the AdvSIMD scalar instructions. + The heuristic-based rule is that the destination operand is respected + more. */ + +static inline int +select_operand_for_scalar_size_field_coding (const aarch64_opcode *opcode) +{ + int src_size = 0, dst_size = 0; + if (aarch64_get_operand_class (opcode->operands[0]) + == AARCH64_OPND_CLASS_SISD_REG) + dst_size = aarch64_get_qualifier_esize (opcode->qualifiers_list[0][0]); + if (aarch64_get_operand_class (opcode->operands[1]) + == AARCH64_OPND_CLASS_SISD_REG) + src_size = aarch64_get_qualifier_esize (opcode->qualifiers_list[0][1]); + if (src_size == dst_size && src_size == 0) + { assert (0); abort (); } + /* When the result is not a sisd register or it is a long operantion. */ + if (dst_size == 0 || dst_size == src_size << 1) + return 1; + else + return 0; +} + +/* Select the operand to do the encoding/decoding of the 'size:Q' fields in + the AdvSIMD instructions. */ + +int aarch64_select_operand_for_sizeq_field_coding (const aarch64_opcode *); + +/* Miscellaneous. */ + +aarch64_insn aarch64_get_operand_modifier_value (enum aarch64_modifier_kind); +enum aarch64_modifier_kind +aarch64_get_operand_modifier_from_value (aarch64_insn, bfd_boolean); + + +bfd_boolean aarch64_wide_constant_p (int64_t, int, unsigned int *); +bfd_boolean aarch64_logical_immediate_p (uint64_t, int, aarch64_insn *); +int aarch64_shrink_expanded_imm8 (uint64_t); + +/* Copy the content of INST->OPERANDS[SRC] to INST->OPERANDS[DST]. */ +static inline void +copy_operand_info (aarch64_inst *inst, int dst, int src) +{ + assert (dst >= 0 && src >= 0 && dst < AARCH64_MAX_OPND_NUM + && src < AARCH64_MAX_OPND_NUM); + memcpy (&inst->operands[dst], &inst->operands[src], + sizeof (aarch64_opnd_info)); + inst->operands[dst].idx = dst; +} + +/* A primitive log caculator. */ + +static inline unsigned int +get_logsz (unsigned int size) +{ + const unsigned char ls[16] = + {0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4}; + if (size > 16) + { + assert (0); + return -1; + } + assert (ls[size - 1] != (unsigned char)-1); + return ls[size - 1]; +} + +#endif /* OPCODES_AARCH64_OPC_H */ diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h new file mode 100644 index 0000000..d360b14 --- /dev/null +++ b/opcodes/aarch64-tbl.h @@ -0,0 +1,2253 @@ +/* aarch64-tbl.h -- AArch64 opcode description table and instruction + operand description table. + Copyright 2012 Free Software Foundation, Inc. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this file; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "aarch64-opc.h" + +/* Operand type. */ + +#define OPND(x) AARCH64_OPND_##x +#define OP0() {} +#define OP1(a) {OPND(a)} +#define OP2(a,b) {OPND(a), OPND(b)} +#define OP3(a,b,c) {OPND(a), OPND(b), OPND(c)} +#define OP4(a,b,c,d) {OPND(a), OPND(b), OPND(c), OPND(d)} +#define OP5(a,b,c,d,e) {OPND(a), OPND(b), OPND(c), OPND(d), OPND(e)} + +#define QLF(x) AARCH64_OPND_QLF_##x +#define QLF1(a) {QLF(a)} +#define QLF2(a,b) {QLF(a), QLF(b)} +#define QLF3(a,b,c) {QLF(a), QLF(b), QLF(c)} +#define QLF4(a,b,c,d) {QLF(a), QLF(b), QLF(c), QLF(d)} +#define QLF5(a,b,c,d,e) {QLF(a), QLF(b), QLF(c), QLF(d), QLF(e)} + +/* Qualifiers list. */ + +/* e.g. MSR <systemreg>, <Xt>. */ +#define QL_SRC_X \ +{ \ + QLF2(NIL,X), \ +} + +/* e.g. MRS <Xt>, <systemreg>. */ +#define QL_DST_X \ +{ \ + QLF2(X,NIL), \ +} + +/* e.g. SYS #<op1>, <Cn>, <Cm>, #<op2>{, <Xt>}. */ +#define QL_SYS \ +{ \ + QLF5(NIL,NIL,NIL,NIL,X), \ +} + +/* e.g. SYSL <Xt>, #<op1>, <Cn>, <Cm>, #<op2>. */ +#define QL_SYSL \ +{ \ + QLF5(X,NIL,NIL,NIL,NIL), \ +} + +/* e.g. ADRP <Xd>, <label>. */ +#define QL_ADRP \ +{ \ + QLF2(X,NIL), \ +} + +/* e.g. B.<cond> <label>. */ +#define QL_PCREL_NIL \ +{ \ + QLF1(NIL), \ +} + +/* e.g. TBZ <Xt>, #<imm>, <label>. */ +#define QL_PCREL_14 \ +{ \ + QLF3(X,imm_0_63,NIL), \ +} + +/* e.g. BL <label>. */ +#define QL_PCREL_26 \ +{ \ + QLF1(NIL), \ +} + +/* e.g. LDRSW <Xt>, <label>. */ +#define QL_X_PCREL \ +{ \ + QLF2(X,NIL), \ +} + +/* e.g. LDR <Wt>, <label>. */ +#define QL_R_PCREL \ +{ \ + QLF2(W,NIL), \ + QLF2(X,NIL), \ +} + +/* e.g. LDR <Dt>, <label>. */ +#define QL_FP_PCREL \ +{ \ + QLF2(S_S,NIL), \ + QLF2(S_D,NIL), \ + QLF2(S_Q,NIL), \ +} + +/* e.g. PRFM <prfop>, <label>. */ +#define QL_PRFM_PCREL \ +{ \ + QLF2(NIL,NIL), \ +} + +/* e.g. BR <Xn>. */ +#define QL_I1X \ +{ \ + QLF1(X), \ +} + +/* e.g. RBIT <Wd>, <Wn>. */ +#define QL_I2SAME \ +{ \ + QLF2(W,W), \ + QLF2(X,X), \ +} + +/* e.g. CMN <Wn|WSP>, <Wm>{, <extend> {#<amount>}}. */ +#define QL_I2_EXT \ +{ \ + QLF2(W,W), \ + QLF2(X,W), \ + QLF2(X,X), \ +} + +/* e.g. MOV <Wd|WSP>, <Wn|WSP>, at least one SP. */ +#define QL_I2SP \ +{ \ + QLF2(WSP,W), \ + QLF2(W,WSP), \ + QLF2(SP,X), \ + QLF2(X,SP), \ +} + +/* e.g. REV <Wd>, <Wn>. */ +#define QL_I2SAMEW \ +{ \ + QLF2(W,W), \ +} + +/* e.g. REV32 <Xd>, <Xn>. */ +#define QL_I2SAMEX \ +{ \ + QLF2(X,X), \ +} + +#define QL_I2SAMER \ +{ \ + QLF2(W,W), \ + QLF2(X,X), \ +} + +/* e.g. SMULH <Xd>, <Xn>, <Xm>. */ +#define QL_I3SAMEX \ +{ \ + QLF3(X,X,X), \ +} + +/* e.g. UDIV <Xd>, <Xn>, <Xm>. */ +#define QL_I3SAMER \ +{ \ + QLF3(W,W,W), \ + QLF3(X,X,X), \ +} + +/* e.g. ADDS <Xd>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}. */ +#define QL_I3_EXT \ +{ \ + QLF3(W,W,W), \ + QLF3(X,X,W), \ + QLF3(X,X,X), \ +} + +/* e.g. MADD <Xd>, <Xn>, <Xm>, <Xa>. */ +#define QL_I4SAMER \ +{ \ + QLF4(W,W,W,W), \ + QLF4(X,X,X,X), \ +} + +/* e.g. SMADDL <Xd>, <Wn>, <Wm>, <Xa>. */ +#define QL_I3SAMEL \ +{ \ + QLF3(X,W,W), \ +} + +/* e.g. SMADDL <Xd>, <Wn>, <Wm>, <Xa>. */ +#define QL_I4SAMEL \ +{ \ + QLF4(X,W,W,X), \ +} + +/* e.g. CSINC <Xd>, <Xn>, <Xm>, <cond>. */ +#define QL_CSEL \ +{ \ + QLF4(W, W, W, NIL), \ + QLF4(X, X, X, NIL), \ +} + +/* e.g. CSET <Wd>, <cond>. */ +#define QL_DST_R \ +{ \ + QLF2(W, NIL), \ + QLF2(X, NIL), \ +} + +/* e.g. BFM <Wd>, <Wn>, #<immr>, #<imms>. */ +#define QL_BF \ +{ \ + QLF4(W,W,imm_0_31,imm_0_31), \ + QLF4(X,X,imm_0_63,imm_0_63), \ +} + +/* e.g. UBFIZ <Wd>, <Wn>, #<lsb>, #<width>. */ +#define QL_BF2 \ +{ \ + QLF4(W,W,imm_0_31,imm_1_32), \ + QLF4(X,X,imm_0_63,imm_1_64), \ +} + +/* e.g. SCVTF <Sd>, <Xn>, #<fbits>. */ +#define QL_FIX2FP \ +{ \ + QLF3(S_D,W,imm_1_32), \ + QLF3(S_S,W,imm_1_32), \ + QLF3(S_D,X,imm_1_64), \ + QLF3(S_S,X,imm_1_64), \ +} + +/* e.g. FCVTZS <Wd>, <Dn>, #<fbits>. */ +#define QL_FP2FIX \ +{ \ + QLF3(W,S_D,imm_1_32), \ + QLF3(W,S_S,imm_1_32), \ + QLF3(X,S_D,imm_1_64), \ + QLF3(X,S_S,imm_1_64), \ +} + +/* e.g. SCVTF <Dd>, <Wn>. */ +#define QL_INT2FP \ +{ \ + QLF2(S_D,W), \ + QLF2(S_S,W), \ + QLF2(S_D,X), \ + QLF2(S_S,X), \ +} + +/* e.g. FCVTNS <Xd>, <Dn>. */ +#define QL_FP2INT \ +{ \ + QLF2(W,S_D), \ + QLF2(W,S_S), \ + QLF2(X,S_D), \ + QLF2(X,S_S), \ +} + +/* e.g. FMOV <Xd>, <Vn>.D[1]. */ +#define QL_XVD1 \ +{ \ + QLF2(X,S_D), \ +} + +/* e.g. FMOV <Vd>.D[1], <Xn>. */ +#define QL_VD1X \ +{ \ + QLF2(S_D,X), \ +} + +/* e.g. EXTR <Xd>, <Xn>, <Xm>, #<lsb>. */ +#define QL_EXTR \ +{ \ + QLF4(W,W,W,imm_0_31), \ + QLF4(X,X,X,imm_0_63), \ +} + +/* e.g. LSL <Wd>, <Wn>, #<uimm>. */ +#define QL_SHIFT \ +{ \ + QLF3(W,W,imm_0_31), \ + QLF3(X,X,imm_0_63), \ +} + +/* e.g. UXTH <Xd>, <Wn>. */ +#define QL_EXT \ +{ \ + QLF2(W,W), \ + QLF2(X,W), \ +} + +/* e.g. UXTW <Xd>, <Wn>. */ +#define QL_EXT_W \ +{ \ + QLF2(X,W), \ +} + +/* e.g. SQSHL <V><d>, <V><n>, #<shift>. */ +#define QL_SSHIFT \ +{ \ + QLF3(S_B , S_B , S_B ), \ + QLF3(S_H , S_H , S_H ), \ + QLF3(S_S , S_S , S_S ), \ + QLF3(S_D , S_D , S_D ) \ +} + +/* e.g. SSHR <V><d>, <V><n>, #<shift>. */ +#define QL_SSHIFT_D \ +{ \ + QLF3(S_D , S_D , S_D ) \ +} + +/* e.g. UCVTF <Vd>.<T>, <Vn>.<T>, #<fbits>. */ +#define QL_SSHIFT_SD \ +{ \ + QLF3(S_S , S_S , S_S ), \ + QLF3(S_D , S_D , S_D ) \ +} + +/* e.g. SQSHRUN <Vb><d>, <Va><n>, #<shift>. */ +#define QL_SSHIFTN \ +{ \ + QLF3(S_B , S_H , S_B ), \ + QLF3(S_H , S_S , S_H ), \ + QLF3(S_S , S_D , S_S ), \ +} + +/* e.g. SSHR <Vd>.<T>, <Vn>.<T>, #<shift>. + The register operand variant qualifiers are deliberately used for the + immediate operand to ease the operand encoding/decoding and qualifier + sequence matching. */ +#define QL_VSHIFT \ +{ \ + QLF3(V_8B , V_8B , V_8B ), \ + QLF3(V_16B, V_16B, V_16B), \ + QLF3(V_4H , V_4H , V_4H ), \ + QLF3(V_8H , V_8H , V_8H ), \ + QLF3(V_2S , V_2S , V_2S ), \ + QLF3(V_4S , V_4S , V_4S ), \ + QLF3(V_2D , V_2D , V_2D ) \ +} + +/* e.g. SCVTF <Vd>.<T>, <Vn>.<T>, #<fbits>. */ +#define QL_VSHIFT_SD \ +{ \ + QLF3(V_2S , V_2S , V_2S ), \ + QLF3(V_4S , V_4S , V_4S ), \ + QLF3(V_2D , V_2D , V_2D ) \ +} + +/* e.g. SHRN<Q> <Vd>.<Tb>, <Vn>.<Ta>, #<shift>. */ +#define QL_VSHIFTN \ +{ \ + QLF3(V_8B , V_8H , V_8B ), \ + QLF3(V_4H , V_4S , V_4H ), \ + QLF3(V_2S , V_2D , V_2S ), \ +} + +/* e.g. SHRN<Q> <Vd>.<Tb>, <Vn>.<Ta>, #<shift>. */ +#define QL_VSHIFTN2 \ +{ \ + QLF3(V_16B, V_8H, V_16B), \ + QLF3(V_8H , V_4S , V_8H ), \ + QLF3(V_4S , V_2D , V_4S ), \ +} + +/* e.g. SSHLL<Q> <Vd>.<Ta>, <Vn>.<Tb>, #<shift>. + the 3rd qualifier is used to help the encoding. */ +#define QL_VSHIFTL \ +{ \ + QLF3(V_8H , V_8B , V_8B ), \ + QLF3(V_4S , V_4H , V_4H ), \ + QLF3(V_2D , V_2S , V_2S ), \ +} + +/* e.g. SSHLL<Q> <Vd>.<Ta>, <Vn>.<Tb>, #<shift>. */ +#define QL_VSHIFTL2 \ +{ \ + QLF3(V_8H , V_16B, V_16B), \ + QLF3(V_4S , V_8H , V_8H ), \ + QLF3(V_2D , V_4S , V_4S ), \ +} + +/* e.g. TBL. */ +#define QL_TABLE \ +{ \ + QLF3(V_8B , V_16B, V_8B ), \ + QLF3(V_16B, V_16B, V_16B), \ +} + +/* e.g. SHA1H. */ +#define QL_2SAMES \ +{ \ + QLF2(S_S, S_S), \ +} + +/* e.g. ABS <V><d>, <V><n>. */ +#define QL_2SAMED \ +{ \ + QLF2(S_D, S_D), \ +} + +/* e.g. CMGT <V><d>, <V><n>, #0. */ +#define QL_SISD_CMP_0 \ +{ \ + QLF3(S_D, S_D, NIL), \ +} + +/* e.g. FCMEQ <V><d>, <V><n>, #0. */ +#define QL_SISD_FCMP_0 \ +{ \ + QLF3(S_S, S_S, NIL), \ + QLF3(S_D, S_D, NIL), \ +} + +/* e.g. FMAXNMP <V><d>, <Vn>.<T>. */ +#define QL_SISD_PAIR \ +{ \ + QLF2(S_S, V_2S), \ + QLF2(S_D, V_2D), \ +} + +/* e.g. ADDP <V><d>, <Vn>.<T>. */ +#define QL_SISD_PAIR_D \ +{ \ + QLF2(S_D, V_2D), \ +} + +/* e.g. DUP <V><d>, <Vn>.<T>[<index>]. */ +#define QL_S_2SAME \ +{ \ + QLF2(S_B, S_B), \ + QLF2(S_H, S_H), \ + QLF2(S_S, S_S), \ + QLF2(S_D, S_D), \ +} + +/* e.g. FCVTNS <V><d>, <V><n>. */ +#define QL_S_2SAMESD \ +{ \ + QLF2(S_S, S_S), \ + QLF2(S_D, S_D), \ +} + +/* e.g. SQXTN <Vb><d>, <Va><n>. */ +#define QL_SISD_NARROW \ +{ \ + QLF2(S_B, S_H), \ + QLF2(S_H, S_S), \ + QLF2(S_S, S_D), \ +} + +/* e.g. FCVTXN <Vb><d>, <Va><n>. */ +#define QL_SISD_NARROW_S \ +{ \ + QLF2(S_S, S_D), \ +} + +/* e.g. FCVT. */ +#define QL_FCVT \ +{ \ + QLF2(S_S, S_H), \ + QLF2(S_S, S_D), \ + QLF2(S_D, S_H), \ + QLF2(S_D, S_S), \ + QLF2(S_H, S_S), \ + QLF2(S_H, S_D), \ +} + +/* FMOV <Dd>, <Dn>. */ +#define QL_FP2 \ +{ \ + QLF2(S_S, S_S), \ + QLF2(S_D, S_D), \ +} + +/* e.g. SQADD <V><d>, <V><n>, <V><m>. */ +#define QL_S_3SAME \ +{ \ + QLF3(S_B, S_B, S_B), \ + QLF3(S_H, S_H, S_H), \ + QLF3(S_S, S_S, S_S), \ + QLF3(S_D, S_D, S_D), \ +} + +/* e.g. CMGE <V><d>, <V><n>, <V><m>. */ +#define QL_S_3SAMED \ +{ \ + QLF3(S_D, S_D, S_D), \ +} + +/* e.g. SQDMULH <V><d>, <V><n>, <V><m>. */ +#define QL_SISD_HS \ +{ \ + QLF3(S_H, S_H, S_H), \ + QLF3(S_S, S_S, S_S), \ +} + +/* e.g. SQDMLAL <Va><d>, <Vb><n>, <Vb><m>. */ +#define QL_SISDL_HS \ +{ \ + QLF3(S_S, S_H, S_H), \ + QLF3(S_D, S_S, S_S), \ +} + +/* FMUL <Sd>, <Sn>, <Sm>. */ +#define QL_FP3 \ +{ \ + QLF3(S_S, S_S, S_S), \ + QLF3(S_D, S_D, S_D), \ +} + +/* FMADD <Dd>, <Dn>, <Dm>, <Da>. */ +#define QL_FP4 \ +{ \ + QLF4(S_S, S_S, S_S, S_S), \ + QLF4(S_D, S_D, S_D, S_D), \ +} + +/* e.g. FCMP <Dn>, #0.0. */ +#define QL_DST_SD \ +{ \ + QLF2(S_S, NIL), \ + QLF2(S_D, NIL), \ +} + +/* FCSEL <Sd>, <Sn>, <Sm>, <cond>. */ +#define QL_FP_COND \ +{ \ + QLF4(S_S, S_S, S_S, NIL), \ + QLF4(S_D, S_D, S_D, NIL), \ +} + +/* e.g. CCMN <Xn>, <Xm>, #<nzcv>, <cond>. */ +#define QL_CCMP \ +{ \ + QLF4(W, W, NIL, NIL), \ + QLF4(X, X, NIL, NIL), \ +} + +/* e.g. CCMN <Xn>, #<imm>, #<nzcv>, <cond>, */ +#define QL_CCMP_IMM \ +{ \ + QLF4(W, NIL, NIL, NIL), \ + QLF4(X, NIL, NIL, NIL), \ +} + +/* e.g. FCCMP <Sn>, <Sm>, #<nzcv>, <cond>. */ +#define QL_FCCMP \ +{ \ + QLF4(S_S, S_S, NIL, NIL), \ + QLF4(S_D, S_D, NIL, NIL), \ +} + +/* e.g. DUP <Vd>.<T>, <Vn>.<Ts>[<index>]. */ +#define QL_DUP_VX \ +{ \ + QLF2(V_8B , S_B ), \ + QLF2(V_16B, S_B ), \ + QLF2(V_4H , S_H ), \ + QLF2(V_8H , S_H ), \ + QLF2(V_2S , S_S ), \ + QLF2(V_4S , S_S ), \ + QLF2(V_2D , S_D ), \ +} + +/* e.g. DUP <Vd>.<T>, <Wn>. */ +#define QL_DUP_VR \ +{ \ + QLF2(V_8B , W ), \ + QLF2(V_16B, W ), \ + QLF2(V_4H , W ), \ + QLF2(V_8H , W ), \ + QLF2(V_2S , W ), \ + QLF2(V_4S , W ), \ + QLF2(V_2D , X ), \ +} + +/* e.g. INS <Vd>.<Ts>[<index>], <Wn>. */ +#define QL_INS_XR \ +{ \ + QLF2(S_H , W ), \ + QLF2(S_S , W ), \ + QLF2(S_D , X ), \ + QLF2(S_B , W ), \ +} + +/* e.g. SMOV <Wd>, <Vn>.<Ts>[<index>]. */ +#define QL_SMOV \ +{ \ + QLF2(W , S_H), \ + QLF2(X , S_H), \ + QLF2(X , S_S), \ + QLF2(W , S_B), \ + QLF2(X , S_B), \ +} + +/* e.g. UMOV <Wd>, <Vn>.<Ts>[<index>]. */ +#define QL_UMOV \ +{ \ + QLF2(W , S_H), \ + QLF2(W , S_S), \ + QLF2(X , S_D), \ + QLF2(W , S_B), \ +} + +/* e.g. MOV <Wd>, <Vn>.<Ts>[<index>]. */ +#define QL_MOV \ +{ \ + QLF2(W , S_S), \ + QLF2(X , S_D), \ +} + +/* e.g. SUQADD <Vd>.<T>, <Vn>.<T>. */ +#define QL_V2SAME \ +{ \ + QLF2(V_8B , V_8B ), \ + QLF2(V_16B, V_16B), \ + QLF2(V_4H , V_4H ), \ + QLF2(V_8H , V_8H ), \ + QLF2(V_2S , V_2S ), \ + QLF2(V_4S , V_4S ), \ + QLF2(V_2D , V_2D ), \ +} + +/* e.g. URSQRTE <Vd>.<T>, <Vn>.<T>. */ +#define QL_V2SAMES \ +{ \ + QLF2(V_2S , V_2S ), \ + QLF2(V_4S , V_4S ), \ +} + +/* e.g. REV32 <Vd>.<T>, <Vn>.<T>. */ +#define QL_V2SAMEBH \ +{ \ + QLF2(V_8B , V_8B ), \ + QLF2(V_16B, V_16B), \ + QLF2(V_4H , V_4H ), \ + QLF2(V_8H , V_8H ), \ +} + +/* e.g. FRINTN <Vd>.<T>, <Vn>.<T>. */ +#define QL_V2SAMESD \ +{ \ + QLF2(V_2S , V_2S ), \ + QLF2(V_4S , V_4S ), \ + QLF2(V_2D , V_2D ), \ +} + +/* e.g. REV64 <Vd>.<T>, <Vn>.<T>. */ +#define QL_V2SAMEBHS \ +{ \ + QLF2(V_8B , V_8B ), \ + QLF2(V_16B, V_16B), \ + QLF2(V_4H , V_4H ), \ + QLF2(V_8H , V_8H ), \ + QLF2(V_2S , V_2S ), \ + QLF2(V_4S , V_4S ), \ +} + +/* e.g. REV16 <Vd>.<T>, <Vn>.<T>. */ +#define QL_V2SAMEB \ +{ \ + QLF2(V_8B , V_8B ), \ + QLF2(V_16B, V_16B), \ +} + +/* e.g. SADDLP <Vd>.<Ta>, <Vn>.<Tb>. */ +#define QL_V2PAIRWISELONGBHS \ +{ \ + QLF2(V_4H , V_8B ), \ + QLF2(V_8H , V_16B), \ + QLF2(V_2S , V_4H ), \ + QLF2(V_4S , V_8H ), \ + QLF2(V_1D , V_2S ), \ + QLF2(V_2D , V_4S ), \ +} + +/* e.g. SHLL<Q> <Vd>.<Ta>, <Vn>.<Tb>, #<shift>. */ +#define QL_V2LONGBHS \ +{ \ + QLF2(V_8H , V_8B ), \ + QLF2(V_4S , V_4H ), \ + QLF2(V_2D , V_2S ), \ +} + +/* e.g. SHLL<Q> <Vd>.<Ta>, <Vn>.<Tb>, #<shift>. */ +#define QL_V2LONGBHS2 \ +{ \ + QLF2(V_8H , V_16B), \ + QLF2(V_4S , V_8H ), \ + QLF2(V_2D , V_4S ), \ +} + +/* */ +#define QL_V3SAME \ +{ \ + QLF3(V_8B , V_8B , V_8B ), \ + QLF3(V_16B, V_16B, V_16B), \ + QLF3(V_4H , V_4H , V_4H ), \ + QLF3(V_8H , V_8H , V_8H ), \ + QLF3(V_2S , V_2S , V_2S ), \ + QLF3(V_4S , V_4S , V_4S ), \ + QLF3(V_2D , V_2D , V_2D ) \ +} + +/* e.g. SHADD. */ +#define QL_V3SAMEBHS \ +{ \ + QLF3(V_8B , V_8B , V_8B ), \ + QLF3(V_16B, V_16B, V_16B), \ + QLF3(V_4H , V_4H , V_4H ), \ + QLF3(V_8H , V_8H , V_8H ), \ + QLF3(V_2S , V_2S , V_2S ), \ + QLF3(V_4S , V_4S , V_4S ), \ +} + +/* e.g. FCVTXN<Q> <Vd>.<Tb>, <Vn>.<Ta>. */ +#define QL_V2NARRS \ +{ \ + QLF2(V_2S , V_2D ), \ +} + +/* e.g. FCVTXN<Q> <Vd>.<Tb>, <Vn>.<Ta>. */ +#define QL_V2NARRS2 \ +{ \ + QLF2(V_4S , V_2D ), \ +} + +/* e.g. FCVTN<Q> <Vd>.<Tb>, <Vn>.<Ta>. */ +#define QL_V2NARRHS \ +{ \ + QLF2(V_4H , V_4S ), \ + QLF2(V_2S , V_2D ), \ +} + +/* e.g. FCVTN<Q> <Vd>.<Tb>, <Vn>.<Ta>. */ +#define QL_V2NARRHS2 \ +{ \ + QLF2(V_8H , V_4S ), \ + QLF2(V_4S , V_2D ), \ +} + +/* e.g. FCVTL<Q> <Vd>.<Ta>, <Vn>.<Tb>. */ +#define QL_V2LONGHS \ +{ \ + QLF2(V_4S , V_4H ), \ + QLF2(V_2D , V_2S ), \ +} + +/* e.g. FCVTL<Q> <Vd>.<Ta>, <Vn>.<Tb>. */ +#define QL_V2LONGHS2 \ +{ \ + QLF2(V_4S , V_8H ), \ + QLF2(V_2D , V_4S ), \ +} + +/* e.g. XTN<Q> <Vd>.<Tb>, <Vn>.<Ta>. */ +#define QL_V2NARRBHS \ +{ \ + QLF2(V_8B , V_8H ), \ + QLF2(V_4H , V_4S ), \ + QLF2(V_2S , V_2D ), \ +} + +/* e.g. XTN<Q> <Vd>.<Tb>, <Vn>.<Ta>. */ +#define QL_V2NARRBHS2 \ +{ \ + QLF2(V_16B, V_8H ), \ + QLF2(V_8H , V_4S ), \ + QLF2(V_4S , V_2D ), \ +} + +/* e.g. ORR. */ +#define QL_V2SAMEB \ +{ \ + QLF2(V_8B , V_8B ), \ + QLF2(V_16B, V_16B), \ +} + +/* e.g. AESE. */ +#define QL_V2SAME16B \ +{ \ + QLF2(V_16B, V_16B), \ +} + +/* e.g. SHA1SU1. */ +#define QL_V2SAME4S \ +{ \ + QLF2(V_4S, V_4S), \ +} + +/* e.g. SHA1SU0. */ +#define QL_V3SAME4S \ +{ \ + QLF3(V_4S, V_4S, V_4S), \ +} + +/* e.g. SHADD. */ +#define QL_V3SAMEB \ +{ \ + QLF3(V_8B , V_8B , V_8B ), \ + QLF3(V_16B, V_16B, V_16B), \ +} + +/* e.g. EXT <Vd>.<T>, <Vn>.<T>, <Vm>.<T>, #<index>. */ +#define QL_VEXT \ +{ \ + QLF4(V_8B , V_8B , V_8B , imm_0_7), \ + QLF4(V_16B, V_16B, V_16B, imm_0_15), \ +} + +/* e.g. . */ +#define QL_V3SAMEHS \ +{ \ + QLF3(V_4H , V_4H , V_4H ), \ + QLF3(V_8H , V_8H , V_8H ), \ + QLF3(V_2S , V_2S , V_2S ), \ + QLF3(V_4S , V_4S , V_4S ), \ +} + +/* */ +#define QL_V3SAMESD \ +{ \ + QLF3(V_2S , V_2S , V_2S ), \ + QLF3(V_4S , V_4S , V_4S ), \ + QLF3(V_2D , V_2D , V_2D ) \ +} + +/* e.g. SQDMLAL<Q> <Vd>.<Ta>, <Vn>.<Tb>, <Vm>.<Tb>. */ +#define QL_V3LONGHS \ +{ \ + QLF3(V_4S , V_4H , V_4H ), \ + QLF3(V_2D , V_2S , V_2S ), \ +} + +/* e.g. SQDMLAL<Q> <Vd>.<Ta>, <Vn>.<Tb>, <Vm>.<Tb>. */ +#define QL_V3LONGHS2 \ +{ \ + QLF3(V_4S , V_8H , V_8H ), \ + QLF3(V_2D , V_4S , V_4S ), \ +} + +/* e.g. SADDL<Q> <Vd>.<Ta>, <Vn>.<Tb>, <Vm>.<Tb>. */ +#define QL_V3LONGBHS \ +{ \ + QLF3(V_8H , V_8B , V_8B ), \ + QLF3(V_4S , V_4H , V_4H ), \ + QLF3(V_2D , V_2S , V_2S ), \ +} + +/* e.g. SADDL<Q> <Vd>.<Ta>, <Vn>.<Tb>, <Vm>.<Tb>. */ +#define QL_V3LONGBHS2 \ +{ \ + QLF3(V_8H , V_16B , V_16B ), \ + QLF3(V_4S , V_8H , V_8H ), \ + QLF3(V_2D , V_4S , V_4S ), \ +} + +/* e.g. SADDW<Q> <Vd>.<Ta>, <Vn>.<Ta>, <Vm>.<Tb>. */ +#define QL_V3WIDEBHS \ +{ \ + QLF3(V_8H , V_8H , V_8B ), \ + QLF3(V_4S , V_4S , V_4H ), \ + QLF3(V_2D , V_2D , V_2S ), \ +} + +/* e.g. SADDW<Q> <Vd>.<Ta>, <Vn>.<Ta>, <Vm>.<Tb>. */ +#define QL_V3WIDEBHS2 \ +{ \ + QLF3(V_8H , V_8H , V_16B ), \ + QLF3(V_4S , V_4S , V_8H ), \ + QLF3(V_2D , V_2D , V_4S ), \ +} + +/* e.g. ADDHN<Q> <Vd>.<Tb>, <Vn>.<Ta>, <Vm>.<Ta>. */ +#define QL_V3NARRBHS \ +{ \ + QLF3(V_8B , V_8H , V_8H ), \ + QLF3(V_4H , V_4S , V_4S ), \ + QLF3(V_2S , V_2D , V_2D ), \ +} + +/* e.g. ADDHN<Q> <Vd>.<Tb>, <Vn>.<Ta>, <Vm>.<Ta>. */ +#define QL_V3NARRBHS2 \ +{ \ + QLF3(V_16B , V_8H , V_8H ), \ + QLF3(V_8H , V_4S , V_4S ), \ + QLF3(V_4S , V_2D , V_2D ), \ +} + +/* e.g. PMULL. */ +#define QL_V3LONGB \ +{ \ + QLF3(V_8H , V_8B , V_8B ), \ +} + +/* e.g. PMULL crypto. */ +#define QL_V3LONGD \ +{ \ + QLF3(V_1Q , V_1D , V_1D ), \ +} + +/* e.g. PMULL2. */ +#define QL_V3LONGB2 \ +{ \ + QLF3(V_8H , V_16B, V_16B), \ +} + +/* e.g. PMULL2 crypto. */ +#define QL_V3LONGD2 \ +{ \ + QLF3(V_1Q , V_2D , V_2D ), \ +} + +/* e.g. SHA1C. */ +#define QL_SHAUPT \ +{ \ + QLF3(S_Q, S_S, V_4S), \ +} + +/* e.g. SHA256H2. */ +#define QL_SHA256UPT \ +{ \ + QLF3(S_Q, S_Q, V_4S), \ +} + +/* e.g. LDXRB <Wt>, [<Xn|SP>{,#0}]. */ +#define QL_W1_LDST_EXC \ +{ \ + QLF2(W, NIL), \ +} + +/* e.g. LDXR <Xt>, [<Xn|SP>{,#0}]. */ +#define QL_R1NIL \ +{ \ + QLF2(W, NIL), \ + QLF2(X, NIL), \ +} + +/* e.g. STXRB <Ws>, <Wt>, [<Xn|SP>{,#0}]. */ +#define QL_W2_LDST_EXC \ +{ \ + QLF3(W, W, NIL), \ +} + +/* e.g. STXR <Ws>, <Xt>, [<Xn|SP>{,#0}]. */ +#define QL_R2_LDST_EXC \ +{ \ + QLF3(W, W, NIL), \ + QLF3(W, X, NIL), \ +} + +/* e.g. LDXP <Xt1>, <Xt2>, [<Xn|SP>{,#0}]. */ +#define QL_R2NIL \ +{ \ + QLF3(W, W, NIL), \ + QLF3(X, X, NIL), \ +} + +/* e.g. STXP <Ws>, <Xt1>, <Xt2>, [<Xn|SP>{,#0}]. */ +#define QL_R3_LDST_EXC \ +{ \ + QLF4(W, W, W, NIL), \ + QLF4(W, X, X, NIL), \ +} + +/* e.g. STR <Qt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */ +#define QL_LDST_FP \ +{ \ + QLF2(S_B, S_B), \ + QLF2(S_H, S_H), \ + QLF2(S_S, S_S), \ + QLF2(S_D, S_D), \ + QLF2(S_Q, S_Q), \ +} + +/* e.g. STR <Xt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */ +#define QL_LDST_R \ +{ \ + QLF2(W, S_S), \ + QLF2(X, S_D), \ +} + +/* e.g. STRB <Wt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */ +#define QL_LDST_W8 \ +{ \ + QLF2(W, S_B), \ +} + +/* e.g. LDRSB <Wt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */ +#define QL_LDST_R8 \ +{ \ + QLF2(W, S_B), \ + QLF2(X, S_B), \ +} + +/* e.g. STRH <Wt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */ +#define QL_LDST_W16 \ +{ \ + QLF2(W, S_H), \ +} + +/* e.g. LDRSW <Xt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */ +#define QL_LDST_X32 \ +{ \ + QLF2(X, S_S), \ +} + +/* e.g. LDRSH <Wt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */ +#define QL_LDST_R16 \ +{ \ + QLF2(W, S_H), \ + QLF2(X, S_H), \ +} + +/* e.g. PRFM <prfop>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */ +#define QL_LDST_PRFM \ +{ \ + QLF2(NIL, S_D), \ +} + +/* e.g. LDPSW <Xt1>, <Xt2>, [<Xn|SP>{, #<imm>}]. */ +#define QL_LDST_PAIR_X32 \ +{ \ + QLF3(X, X, S_S), \ +} + +/* e.g. STP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]!. */ +#define QL_LDST_PAIR_R \ +{ \ + QLF3(W, W, S_S), \ + QLF3(X, X, S_D), \ +} + +/* e.g. STNP <Qt1>, <Qt2>, [<Xn|SP>{, #<imm>}]. */ +#define QL_LDST_PAIR_FP \ +{ \ + QLF3(S_S, S_S, S_S), \ + QLF3(S_D, S_D, S_D), \ + QLF3(S_Q, S_Q, S_Q), \ +} + +/* e.g. LD3 {<Vt>.<T>, <Vt2>.<T>, <Vt3>.<T>}, [<Xn|SP>]. */ +#define QL_SIMD_LDST \ +{ \ + QLF2(V_8B, NIL), \ + QLF2(V_16B, NIL), \ + QLF2(V_4H, NIL), \ + QLF2(V_8H, NIL), \ + QLF2(V_2S, NIL), \ + QLF2(V_4S, NIL), \ + QLF2(V_2D, NIL), \ +} + +/* e.g. LD1 {<Vt>.<T>, <Vt2>.<T>, <Vt3>.<T>}, [<Xn|SP>]. */ +#define QL_SIMD_LDST_ANY \ +{ \ + QLF2(V_8B, NIL), \ + QLF2(V_16B, NIL), \ + QLF2(V_4H, NIL), \ + QLF2(V_8H, NIL), \ + QLF2(V_2S, NIL), \ + QLF2(V_4S, NIL), \ + QLF2(V_1D, NIL), \ + QLF2(V_2D, NIL), \ +} + +/* e.g. LD4 {<Vt>.<T>, <Vt2a>.<T>, <Vt3a>.<T>, <Vt4a>.<T>}[<index>], [<Xn|SP>]. */ +#define QL_SIMD_LDSTONE \ +{ \ + QLF2(S_B, NIL), \ + QLF2(S_H, NIL), \ + QLF2(S_S, NIL), \ + QLF2(S_D, NIL), \ +} + +/* e.g. ADDV <V><d>, <Vn>.<T>. */ +#define QL_XLANES \ +{ \ + QLF2(S_B, V_8B), \ + QLF2(S_B, V_16B), \ + QLF2(S_H, V_4H), \ + QLF2(S_H, V_8H), \ + QLF2(S_S, V_4S), \ +} + +/* e.g. FMINV <V><d>, <Vn>.<T>. */ +#define QL_XLANES_FP \ +{ \ + QLF2(S_S, V_4S), \ +} + +/* e.g. SADDLV <V><d>, <Vn>.<T>. */ +#define QL_XLANES_L \ +{ \ + QLF2(S_H, V_8B), \ + QLF2(S_H, V_16B), \ + QLF2(S_S, V_4H), \ + QLF2(S_S, V_8H), \ + QLF2(S_D, V_4S), \ +} + +/* e.g. MUL <Vd>.<T>, <Vn>.<T>, <Vm>.<Ts>[<index>]. */ +#define QL_ELEMENT \ +{ \ + QLF3(V_4H, V_4H, S_H), \ + QLF3(V_8H, V_8H, S_H), \ + QLF3(V_2S, V_2S, S_S), \ + QLF3(V_4S, V_4S, S_S), \ +} + +/* e.g. SMLAL <Vd>.<Ta>, <Vn>.<Tb>, <Vm>.<Ts>[<index>]. */ +#define QL_ELEMENT_L \ +{ \ + QLF3(V_4S, V_4H, S_H), \ + QLF3(V_2D, V_2S, S_S), \ +} + +/* e.g. SMLAL2 <Vd>.<Ta>, <Vn>.<Tb>, <Vm>.<Ts>[<index>]. */ +#define QL_ELEMENT_L2 \ +{ \ + QLF3(V_4S, V_8H, S_H), \ + QLF3(V_2D, V_4S, S_S), \ +} + +/* e.g. FMLA <V><d>, <V><n>, <Vm>.<Ts>[<index>]. */ +#define QL_ELEMENT_FP \ +{ \ + QLF3(V_2S, V_2S, S_S), \ + QLF3(V_4S, V_4S, S_S), \ + QLF3(V_2D, V_2D, S_D), \ +} + +/* e.g. MOVI <Vd>.4S, #<imm8> {, LSL #<amount>}. */ +#define QL_SIMD_IMM_S0W \ +{ \ + QLF2(V_2S, LSL), \ + QLF2(V_4S, LSL), \ +} + +/* e.g. MOVI <Vd>.4S, #<imm8>, MSL #<amount>. */ +#define QL_SIMD_IMM_S1W \ +{ \ + QLF2(V_2S, MSL), \ + QLF2(V_4S, MSL), \ +} + +/* e.g. MOVI <Vd>.4H, #<imm8> {, LSL #<amount>}. */ +#define QL_SIMD_IMM_S0H \ +{ \ + QLF2(V_4H, LSL), \ + QLF2(V_8H, LSL), \ +} + +/* e.g. FMOV <Vd>.<T>, #<imm>. */ +#define QL_SIMD_IMM_S \ +{ \ + QLF2(V_2S, NIL), \ + QLF2(V_4S, NIL), \ +} + +/* e.g. MOVI <Vd>.8B, #<imm8>. */ +#define QL_SIMD_IMM_B \ +{ \ + QLF2(V_8B, NIL), \ + QLF2(V_16B, NIL), \ +} +/* e.g. MOVI <Dd>, #<imm>. */ +#define QL_SIMD_IMM_D \ +{ \ + QLF2(S_D, NIL), \ +} + +/* e.g. MOVI <Vd>.2D, #<imm>. */ +#define QL_SIMD_IMM_V2D \ +{ \ + QLF2(V_2D, NIL), \ +} + +/* Opcode table. */ + +static const aarch64_feature_set aarch64_feature_v8 = + AARCH64_FEATURE (AARCH64_FEATURE_V8, 0); +static const aarch64_feature_set aarch64_feature_fp = + AARCH64_FEATURE (AARCH64_FEATURE_FP, 0); +static const aarch64_feature_set aarch64_feature_simd = + AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0); +static const aarch64_feature_set aarch64_feature_crypto = + AARCH64_FEATURE (AARCH64_FEATURE_CRYPTO, 0); + +#define CORE &aarch64_feature_v8 +#define FP &aarch64_feature_fp +#define SIMD &aarch64_feature_simd +#define CRYPTO &aarch64_feature_crypto + +struct aarch64_opcode aarch64_opcode_table[] = +{ + /* Add/subtract (with carry). */ + {"adc", 0x1a000000, 0x7fe0fc00, addsub_carry, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_SF}, + {"adcs", 0x3a000000, 0x7fe0fc00, addsub_carry, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_SF}, + {"sbc", 0x5a000000, 0x7fe0fc00, addsub_carry, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_HAS_ALIAS | F_SF}, + {"ngc", 0x5a0003e0, 0x7fe0ffe0, addsub_carry, 0, CORE, OP2 (Rd, Rm), QL_I2SAME, F_ALIAS | F_SF}, + {"sbcs", 0x7a000000, 0x7fe0fc00, addsub_carry, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_HAS_ALIAS | F_SF}, + {"ngcs", 0x7a0003e0, 0x7fe0ffe0, addsub_carry, 0, CORE, OP2 (Rd, Rm), QL_I2SAME, F_ALIAS | F_SF}, + /* Add/subtract (extended register). */ + {"add", 0x0b200000, 0x7fe00000, addsub_ext, 0, CORE, OP3 (Rd_SP, Rn_SP, Rm_EXT), QL_I3_EXT, F_SF}, + {"adds", 0x2b200000, 0x7fe00000, addsub_ext, 0, CORE, OP3 (Rd, Rn_SP, Rm_EXT), QL_I3_EXT, F_HAS_ALIAS | F_SF}, + {"cmn", 0x2b20001f, 0x7fe0001f, addsub_ext, 0, CORE, OP2 (Rn_SP, Rm_EXT), QL_I2_EXT, F_ALIAS | F_SF}, + {"sub", 0x4b200000, 0x7fe00000, addsub_ext, 0, CORE, OP3 (Rd_SP, Rn_SP, Rm_EXT), QL_I3_EXT, F_SF}, + {"subs", 0x6b200000, 0x7fe00000, addsub_ext, 0, CORE, OP3 (Rd, Rn_SP, Rm_EXT), QL_I3_EXT, F_HAS_ALIAS | F_SF}, + {"cmp", 0x6b20001f, 0x7fe0001f, addsub_ext, 0, CORE, OP2 (Rn_SP, Rm_EXT), QL_I2_EXT, F_ALIAS | F_SF}, + /* Add/subtract (immediate). */ + {"add", 0x11000000, 0x7f000000, addsub_imm, OP_ADD, CORE, OP3 (Rd_SP, Rn_SP, AIMM), QL_R2NIL, F_HAS_ALIAS | F_SF}, + {"mov", 0x11000000, 0x7ffffc00, addsub_imm, 0, CORE, OP2 (Rd_SP, Rn_SP), QL_I2SP, F_ALIAS | F_SF}, + {"adds", 0x31000000, 0x7f000000, addsub_imm, 0, CORE, OP3 (Rd, Rn_SP, AIMM), QL_R2NIL, F_HAS_ALIAS | F_SF}, + {"cmn", 0x3100001f, 0x7f00001f, addsub_imm, 0, CORE, OP2 (Rn_SP, AIMM), QL_R1NIL, F_ALIAS | F_SF}, + {"sub", 0x51000000, 0x7f000000, addsub_imm, 0, CORE, OP3 (Rd_SP, Rn_SP, AIMM), QL_R2NIL, F_SF}, + {"subs", 0x71000000, 0x7f000000, addsub_imm, 0, CORE, OP3 (Rd, Rn_SP, AIMM), QL_R2NIL, F_HAS_ALIAS | F_SF}, + {"cmp", 0x7100001f, 0x7f00001f, addsub_imm, 0, CORE, OP2 (Rn_SP, AIMM), QL_R1NIL, F_ALIAS | F_SF}, + /* Add/subtract (shifted register). */ + {"add", 0xb000000, 0x7f200000, addsub_shift, 0, CORE, OP3 (Rd, Rn, Rm_SFT), QL_I3SAMER, F_SF}, + {"adds", 0x2b000000, 0x7f200000, addsub_shift, 0, CORE, OP3 (Rd, Rn, Rm_SFT), QL_I3SAMER, F_HAS_ALIAS | F_SF}, + {"cmn", 0x2b00001f, 0x7f20001f, addsub_shift, 0, CORE, OP2 (Rn, Rm_SFT), QL_I2SAME, F_ALIAS | F_SF}, + {"sub", 0x4b000000, 0x7f200000, addsub_shift, 0, CORE, OP3 (Rd, Rn, Rm_SFT), QL_I3SAMER, F_HAS_ALIAS | F_SF}, + {"neg", 0x4b0003e0, 0x7f2003e0, addsub_shift, 0, CORE, OP2 (Rd, Rm_SFT), QL_I2SAME, F_ALIAS | F_SF}, + {"subs", 0x6b000000, 0x7f200000, addsub_shift, 0, CORE, OP3 (Rd, Rn, Rm_SFT), QL_I3SAMER, F_HAS_ALIAS | F_SF}, + {"cmp", 0x6b00001f, 0x7f20001f, addsub_shift, 0, CORE, OP2 (Rn, Rm_SFT), QL_I2SAME, F_ALIAS | F_SF}, + {"negs", 0x6b0003e0, 0x7f2003e0, addsub_shift, 0, CORE, OP2 (Rd, Rm_SFT), QL_I2SAME, F_ALIAS | F_SF}, + /* AdvSIMD across lanes. */ + {"saddlv", 0xe303800, 0xbf3ffc00, asimdall, 0, SIMD, OP2 (Fd, Vn), QL_XLANES_L, F_SIZEQ}, + {"smaxv", 0xe30a800, 0xbf3ffc00, asimdall, 0, SIMD, OP2 (Fd, Vn), QL_XLANES, F_SIZEQ}, + {"sminv", 0xe31a800, 0xbf3ffc00, asimdall, 0, SIMD, OP2 (Fd, Vn), QL_XLANES, F_SIZEQ}, + {"addv", 0xe31b800, 0xbf3ffc00, asimdall, 0, SIMD, OP2 (Fd, Vn), QL_XLANES, F_SIZEQ}, + {"uaddlv", 0x2e303800, 0xbf3ffc00, asimdall, 0, SIMD, OP2 (Fd, Vn), QL_XLANES_L, F_SIZEQ}, + {"umaxv", 0x2e30a800, 0xbf3ffc00, asimdall, 0, SIMD, OP2 (Fd, Vn), QL_XLANES, F_SIZEQ}, + {"uminv", 0x2e31a800, 0xbf3ffc00, asimdall, 0, SIMD, OP2 (Fd, Vn), QL_XLANES, F_SIZEQ}, + {"fmaxnmv", 0x2e30c800, 0xbfbffc00, asimdall, 0, SIMD, OP2 (Fd, Vn), QL_XLANES_FP, F_SIZEQ}, + {"fmaxv", 0x2e30f800, 0xbfbffc00, asimdall, 0, SIMD, OP2 (Fd, Vn), QL_XLANES_FP, F_SIZEQ}, + {"fminnmv", 0x2eb0c800, 0xbfbffc00, asimdall, 0, SIMD, OP2 (Fd, Vn), QL_XLANES_FP, F_SIZEQ}, + {"fminv", 0x2eb0f800, 0xbfbffc00, asimdall, 0, SIMD, OP2 (Fd, Vn), QL_XLANES_FP, F_SIZEQ}, + /* AdvSIMD three different. */ + {"saddl", 0x0e200000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS, F_SIZEQ}, + {"saddl2", 0x4e200000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS2, F_SIZEQ}, + {"saddw", 0x0e201000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3WIDEBHS, F_SIZEQ}, + {"saddw2", 0x4e201000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3WIDEBHS2, F_SIZEQ}, + {"ssubl", 0x0e202000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS, F_SIZEQ}, + {"ssubl2", 0x4e202000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS2, F_SIZEQ}, + {"ssubw", 0x0e203000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3WIDEBHS, F_SIZEQ}, + {"ssubw2", 0x4e203000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3WIDEBHS2, F_SIZEQ}, + {"addhn", 0x0e204000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3NARRBHS, F_SIZEQ}, + {"addhn2", 0x4e204000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3NARRBHS2, F_SIZEQ}, + {"sabal", 0x0e205000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS, F_SIZEQ}, + {"sabal2", 0x4e205000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS2, F_SIZEQ}, + {"subhn", 0x0e206000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3NARRBHS, F_SIZEQ}, + {"subhn2", 0x4e206000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3NARRBHS2, F_SIZEQ}, + {"sabdl", 0x0e207000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS, F_SIZEQ}, + {"sabdl2", 0x4e207000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS2, F_SIZEQ}, + {"smlal", 0x0e208000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS, F_SIZEQ}, + {"smlal2", 0x4e208000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS2, F_SIZEQ}, + {"sqdmlal", 0x0e209000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGHS, F_SIZEQ}, + {"sqdmlal2", 0x4e209000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGHS2, F_SIZEQ}, + {"smlsl", 0x0e20a000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS, F_SIZEQ}, + {"smlsl2", 0x4e20a000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS2, F_SIZEQ}, + {"sqdmlsl", 0x0e20b000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGHS, F_SIZEQ}, + {"sqdmlsl2", 0x4e20b000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGHS2, F_SIZEQ}, + {"smull", 0x0e20c000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS, F_SIZEQ}, + {"smull2", 0x4e20c000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS2, F_SIZEQ}, + {"sqdmull", 0x0e20d000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGHS, F_SIZEQ}, + {"sqdmull2", 0x4e20d000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGHS2, F_SIZEQ}, + {"pmull", 0x0e20e000, 0xffe0fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGB, 0}, + {"pmull", 0x0ee0e000, 0xffe0fc00, asimddiff, 0, CRYPTO, OP3 (Vd, Vn, Vm), QL_V3LONGD, 0}, + {"pmull2", 0x4e20e000, 0xffe0fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGB2, 0}, + {"pmull2", 0x4ee0e000, 0xffe0fc00, asimddiff, 0, CRYPTO, OP3 (Vd, Vn, Vm), QL_V3LONGD2, 0}, + {"uaddl", 0x2e200000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS, F_SIZEQ}, + {"uaddl2", 0x6e200000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS2, F_SIZEQ}, + {"uaddw", 0x2e201000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3WIDEBHS, F_SIZEQ}, + {"uaddw2", 0x6e201000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3WIDEBHS2, F_SIZEQ}, + {"usubl", 0x2e202000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS, F_SIZEQ}, + {"usubl2", 0x6e202000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS2, F_SIZEQ}, + {"usubw", 0x2e203000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3WIDEBHS, F_SIZEQ}, + {"usubw2", 0x6e203000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3WIDEBHS2, F_SIZEQ}, + {"raddhn", 0x2e204000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3NARRBHS, F_SIZEQ}, + {"raddhn2", 0x6e204000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3NARRBHS2, F_SIZEQ}, + {"uabal", 0x2e205000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS, F_SIZEQ}, + {"uabal2", 0x6e205000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS2, F_SIZEQ}, + {"rsubhn", 0x2e206000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3NARRBHS, F_SIZEQ}, + {"rsubhn2", 0x6e206000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3NARRBHS2, F_SIZEQ}, + {"uabdl", 0x2e207000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS, F_SIZEQ}, + {"uabdl2", 0x6e207000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS2, F_SIZEQ}, + {"umlal", 0x2e208000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS, F_SIZEQ}, + {"umlal2", 0x6e208000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS2, F_SIZEQ}, + {"umlsl", 0x2e20a000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS, F_SIZEQ}, + {"umlsl2", 0x6e20a000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS2, F_SIZEQ}, + {"umull", 0x2e20c000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS, F_SIZEQ}, + {"umull2", 0x6e20c000, 0xff20fc00, asimddiff, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3LONGBHS2, F_SIZEQ}, + /* AdvSIMD vector x indexed element. */ + {"smlal", 0x0f002000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L, F_SIZEQ}, + {"smlal2", 0x4f002000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L2, F_SIZEQ}, + {"sqdmlal", 0x0f003000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L, F_SIZEQ}, + {"sqdmlal2", 0x4f003000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L2, F_SIZEQ}, + {"smlsl", 0x0f006000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L, F_SIZEQ}, + {"smlsl2", 0x4f006000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L2, F_SIZEQ}, + {"sqdmlsl", 0x0f007000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L, F_SIZEQ}, + {"sqdmlsl2", 0x4f007000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L2, F_SIZEQ}, + {"mul", 0xf008000, 0xbf00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT, F_SIZEQ}, + {"smull", 0x0f00a000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L, F_SIZEQ}, + {"smull2", 0x4f00a000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L2, F_SIZEQ}, + {"sqdmull", 0x0f00b000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L, F_SIZEQ}, + {"sqdmull2", 0x4f00b000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L2, F_SIZEQ}, + {"sqdmulh", 0xf00c000, 0xbf00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT, F_SIZEQ}, + {"sqrdmulh", 0xf00d000, 0xbf00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT, F_SIZEQ}, + {"fmla", 0xf801000, 0xbf80f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_FP, F_SIZEQ}, + {"fmls", 0xf805000, 0xbf80f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_FP, F_SIZEQ}, + {"fmul", 0xf809000, 0xbf80f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_FP, F_SIZEQ}, + {"mla", 0x2f000000, 0xbf00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT, F_SIZEQ}, + {"umlal", 0x2f002000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L, F_SIZEQ}, + {"umlal2", 0x6f002000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L2, F_SIZEQ}, + {"mls", 0x2f004000, 0xbf00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT, F_SIZEQ}, + {"umlsl", 0x2f006000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L, F_SIZEQ}, + {"umlsl2", 0x6f006000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L2, F_SIZEQ}, + {"umull", 0x2f00a000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L, F_SIZEQ}, + {"umull2", 0x6f00a000, 0xff00f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_L2, F_SIZEQ}, + {"fmulx", 0x2f809000, 0xbf80f400, asimdelem, 0, SIMD, OP3 (Vd, Vn, Em), QL_ELEMENT_FP, F_SIZEQ}, + /* AdvSIMD EXT. */ + {"ext", 0x2e000000, 0xbfe0c400, asimdext, 0, SIMD, OP4 (Vd, Vn, Vm, IDX), QL_VEXT, F_SIZEQ}, + /* AdvSIMD modified immediate. */ + {"movi", 0xf000400, 0xbff89c00, asimdimm, 0, SIMD, OP2 (Vd, SIMD_IMM_SFT), QL_SIMD_IMM_S0W, F_SIZEQ}, + {"orr", 0xf001400, 0xbff89c00, asimdimm, 0, SIMD, OP2 (Vd, SIMD_IMM_SFT), QL_SIMD_IMM_S0W, F_SIZEQ}, + {"movi", 0xf008400, 0xbff8dc00, asimdimm, 0, SIMD, OP2 (Vd, SIMD_IMM_SFT), QL_SIMD_IMM_S0H, F_SIZEQ}, + {"orr", 0xf009400, 0xbff8dc00, asimdimm, 0, SIMD, OP2 (Vd, SIMD_IMM_SFT), QL_SIMD_IMM_S0H, F_SIZEQ}, + {"movi", 0xf00c400, 0xbff8ec00, asimdimm, 0, SIMD, OP2 (Vd, SIMD_IMM_SFT), QL_SIMD_IMM_S1W, F_SIZEQ}, + {"movi", 0xf00e400, 0xbff8fc00, asimdimm, OP_V_MOVI_B, SIMD, OP2 (Vd, SIMD_IMM), QL_SIMD_IMM_B, F_SIZEQ}, + {"fmov", 0xf00f400, 0xbff8fc00, asimdimm, 0, SIMD, OP2 (Vd, SIMD_FPIMM), QL_SIMD_IMM_S, F_SIZEQ}, + {"mvni", 0x2f000400, 0xbff89c00, asimdimm, 0, SIMD, OP2 (Vd, SIMD_IMM_SFT), QL_SIMD_IMM_S0W, F_SIZEQ}, + {"bic", 0x2f001400, 0xbff89c00, asimdimm, 0, SIMD, OP2 (Vd, SIMD_IMM_SFT), QL_SIMD_IMM_S0W, F_SIZEQ}, + {"mvni", 0x2f008400, 0xbff8dc00, asimdimm, 0, SIMD, OP2 (Vd, SIMD_IMM_SFT), QL_SIMD_IMM_S0H, F_SIZEQ}, + {"bic", 0x2f009400, 0xbff8dc00, asimdimm, 0, SIMD, OP2 (Vd, SIMD_IMM_SFT), QL_SIMD_IMM_S0H, F_SIZEQ}, + {"mvni", 0x2f00c400, 0xbff8ec00, asimdimm, 0, SIMD, OP2 (Vd, SIMD_IMM_SFT), QL_SIMD_IMM_S1W, F_SIZEQ}, + {"movi", 0x2f00e400, 0xfff8fc00, asimdimm, 0, SIMD, OP2 (Sd, SIMD_IMM), QL_SIMD_IMM_D, F_SIZEQ}, + {"movi", 0x6f00e400, 0xfff8fc00, asimdimm, 0, SIMD, OP2 (Vd, SIMD_IMM), QL_SIMD_IMM_V2D, F_SIZEQ}, + {"fmov", 0x6f00f400, 0xfff8fc00, asimdimm, 0, SIMD, OP2 (Vd, SIMD_FPIMM), QL_SIMD_IMM_V2D, F_SIZEQ}, + /* AdvSIMD copy. */ + {"dup", 0xe000400, 0xbfe0fc00, asimdins, 0, SIMD, OP2 (Vd, En), QL_DUP_VX, F_T}, + {"dup", 0xe000c00, 0xbfe0fc00, asimdins, 0, SIMD, OP2 (Vd, Rn), QL_DUP_VR, F_T}, + {"smov", 0xe002c00, 0xbfe0fc00, asimdins, 0, SIMD, OP2 (Rd, En), QL_SMOV, F_GPRSIZE_IN_Q}, + {"umov", 0xe003c00, 0xbfe0fc00, asimdins, 0, SIMD, OP2 (Rd, En), QL_UMOV, F_HAS_ALIAS | F_GPRSIZE_IN_Q}, + {"mov", 0xe003c00, 0xbfe0fc00, asimdins, 0, SIMD, OP2 (Rd, En), QL_MOV, F_ALIAS | F_GPRSIZE_IN_Q}, + {"ins", 0x4e001c00, 0xffe0fc00, asimdins, 0, SIMD, OP2 (Ed, Rn), QL_INS_XR, F_HAS_ALIAS}, + {"mov", 0x4e001c00, 0xffe0fc00, asimdins, 0, SIMD, OP2 (Ed, Rn), QL_INS_XR, F_ALIAS}, + {"ins", 0x6e000400, 0xffe08400, asimdins, 0, SIMD, OP2 (Ed, En), QL_S_2SAME, F_HAS_ALIAS}, + {"mov", 0x6e000400, 0xffe08400, asimdins, 0, SIMD, OP2 (Ed, En), QL_S_2SAME, F_ALIAS}, + /* AdvSIMD two-reg misc. */ + {"rev64", 0xe200800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMEBHS, F_SIZEQ}, + {"rev16", 0xe201800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMEB, F_SIZEQ}, + {"saddlp", 0xe202800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2PAIRWISELONGBHS, F_SIZEQ}, + {"suqadd", 0xe203800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAME, F_SIZEQ}, + {"cls", 0xe204800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMEBHS, F_SIZEQ}, + {"cnt", 0xe205800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMEB, F_SIZEQ}, + {"sadalp", 0xe206800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2PAIRWISELONGBHS, F_SIZEQ}, + {"sqabs", 0xe207800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAME, F_SIZEQ}, + {"cmgt", 0xe208800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP3 (Vd, Vn, IMM0), QL_V2SAME, F_SIZEQ}, + {"cmeq", 0xe209800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP3 (Vd, Vn, IMM0), QL_V2SAME, F_SIZEQ}, + {"cmlt", 0xe20a800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP3 (Vd, Vn, IMM0), QL_V2SAME, F_SIZEQ}, + {"abs", 0xe20b800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAME, F_SIZEQ}, + {"xtn", 0xe212800, 0xff3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2NARRBHS, F_SIZEQ}, + {"xtn2", 0x4e212800, 0xff3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2NARRBHS2, F_SIZEQ}, + {"sqxtn", 0xe214800, 0xff3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2NARRBHS, F_SIZEQ}, + {"sqxtn2", 0x4e214800, 0xff3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2NARRBHS2, F_SIZEQ}, + {"fcvtn", 0xe216800, 0xffbffc00, asimdmisc, OP_FCVTN, SIMD, OP2 (Vd, Vn), QL_V2NARRHS, F_MISC}, + {"fcvtn2", 0x4e216800, 0xffbffc00, asimdmisc, OP_FCVTN2, SIMD, OP2 (Vd, Vn), QL_V2NARRHS2, F_MISC}, + {"fcvtl", 0xe217800, 0xffbffc00, asimdmisc, OP_FCVTL, SIMD, OP2 (Vd, Vn), QL_V2LONGHS, F_MISC}, + {"fcvtl2", 0x4e217800, 0xffbffc00, asimdmisc, OP_FCVTL2, SIMD, OP2 (Vd, Vn), QL_V2LONGHS2, F_MISC}, + {"frintn", 0xe218800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"frintm", 0xe219800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"fcvtns", 0xe21a800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"fcvtms", 0xe21b800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"fcvtas", 0xe21c800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"scvtf", 0xe21d800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"fcmgt", 0xea0c800, 0xbfbffc00, asimdmisc, 0, SIMD, OP3 (Vd, Vn, IMM0), QL_V2SAMESD, F_SIZEQ}, + {"fcmeq", 0xea0d800, 0xbfbffc00, asimdmisc, 0, SIMD, OP3 (Vd, Vn, IMM0), QL_V2SAMESD, F_SIZEQ}, + {"fcmlt", 0xea0e800, 0xbfbffc00, asimdmisc, 0, SIMD, OP3 (Vd, Vn, IMM0), QL_V2SAMESD, F_SIZEQ}, + {"fabs", 0xea0f800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"frintp", 0xea18800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"frintz", 0xea19800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"fcvtps", 0xea1a800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"fcvtzs", 0xea1b800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"urecpe", 0xea1c800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMES, F_SIZEQ}, + {"frecpe", 0xea1d800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"rev32", 0x2e200800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMEBH, F_SIZEQ}, + {"uaddlp", 0x2e202800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2PAIRWISELONGBHS, F_SIZEQ}, + {"usqadd", 0x2e203800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAME, F_SIZEQ}, + {"clz", 0x2e204800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMEBHS, F_SIZEQ}, + {"uadalp", 0x2e206800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2PAIRWISELONGBHS, F_SIZEQ}, + {"sqneg", 0x2e207800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAME, F_SIZEQ}, + {"cmge", 0x2e208800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP3 (Vd, Vn, IMM0), QL_V2SAME, F_SIZEQ}, + {"cmle", 0x2e209800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP3 (Vd, Vn, IMM0), QL_V2SAME, F_SIZEQ}, + {"neg", 0x2e20b800, 0xbf3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAME, F_SIZEQ}, + {"sqxtun", 0x2e212800, 0xff3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2NARRBHS, F_SIZEQ}, + {"sqxtun2", 0x6e212800, 0xff3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2NARRBHS2, F_SIZEQ}, + {"shll", 0x2e213800, 0xff3ffc00, asimdmisc, 0, SIMD, OP3 (Vd, Vn, SHLL_IMM), QL_V2LONGBHS, F_SIZEQ}, + {"shll2", 0x6e213800, 0xff3ffc00, asimdmisc, 0, SIMD, OP3 (Vd, Vn, SHLL_IMM), QL_V2LONGBHS2, F_SIZEQ}, + {"uqxtn", 0x2e214800, 0xff3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2NARRBHS, F_SIZEQ}, + {"uqxtn2", 0x6e214800, 0xff3ffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2NARRBHS2, F_SIZEQ}, + {"fcvtxn", 0x2e616800, 0xfffffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2NARRS, 0}, + {"fcvtxn2", 0x6e616800, 0xfffffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2NARRS2, 0}, + {"frinta", 0x2e218800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"frintx", 0x2e219800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"fcvtnu", 0x2e21a800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"fcvtmu", 0x2e21b800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"fcvtau", 0x2e21c800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"ucvtf", 0x2e21d800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"not", 0x2e205800, 0xbffffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMEB, F_SIZEQ | F_HAS_ALIAS}, + {"mvn", 0x2e205800, 0xbffffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMEB, F_SIZEQ | F_ALIAS}, + {"rbit", 0x2e605800, 0xbffffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMEB, F_SIZEQ}, + {"fcmge", 0x2ea0c800, 0xbfbffc00, asimdmisc, 0, SIMD, OP3 (Vd, Vn, IMM0), QL_V2SAMESD, F_SIZEQ}, + {"fcmle", 0x2ea0d800, 0xbfbffc00, asimdmisc, 0, SIMD, OP3 (Vd, Vn, IMM0), QL_V2SAMESD, F_SIZEQ}, + {"fneg", 0x2ea0f800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"frinti", 0x2ea19800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"fcvtpu", 0x2ea1a800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"fcvtzu", 0x2ea1b800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"ursqrte", 0x2ea1c800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMES, F_SIZEQ}, + {"frsqrte", 0x2ea1d800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + {"fsqrt", 0x2ea1f800, 0xbfbffc00, asimdmisc, 0, SIMD, OP2 (Vd, Vn), QL_V2SAMESD, F_SIZEQ}, + /* AdvSIMD ZIP/UZP/TRN. */ + {"uzp1", 0xe001800, 0xbf20fc00, asimdperm, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"trn1", 0xe002800, 0xbf20fc00, asimdperm, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"zip1", 0xe003800, 0xbf20fc00, asimdperm, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"uzp2", 0xe005800, 0xbf20fc00, asimdperm, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"trn2", 0xe006800, 0xbf20fc00, asimdperm, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"zip2", 0xe007800, 0xbf20fc00, asimdperm, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + /* AdvSIMD three same. */ + {"shadd", 0xe200400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"sqadd", 0xe200c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"srhadd", 0xe201400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"shsub", 0xe202400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"sqsub", 0xe202c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"cmgt", 0xe203400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"cmge", 0xe203c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"sshl", 0xe204400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"sqshl", 0xe204c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"srshl", 0xe205400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"sqrshl", 0xe205c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"smax", 0xe206400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"smin", 0xe206c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"sabd", 0xe207400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"saba", 0xe207c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"add", 0xe208400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"cmtst", 0xe208c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"mla", 0xe209400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"mul", 0xe209c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"smaxp", 0xe20a400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"sminp", 0xe20ac00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"sqdmulh", 0xe20b400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEHS, F_SIZEQ}, + {"addp", 0xe20bc00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"fmaxnm", 0xe20c400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fmla", 0xe20cc00, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fadd", 0xe20d400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fmulx", 0xe20dc00, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fcmeq", 0xe20e400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fmax", 0xe20f400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"frecps", 0xe20fc00, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"and", 0xe201c00, 0xbfe0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEB, F_SIZEQ}, + {"bic", 0xe601c00, 0xbfe0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEB, F_SIZEQ}, + {"fminnm", 0xea0c400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fmls", 0xea0cc00, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fsub", 0xea0d400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fmin", 0xea0f400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"frsqrts", 0xea0fc00, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"orr", 0xea01c00, 0xbfe0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEB, F_HAS_ALIAS | F_SIZEQ}, + {"mov", 0xea01c00, 0xbfe0fc00, asimdsame, OP_MOV_V, SIMD, OP2 (Vd, Vn), QL_V2SAMEB, F_ALIAS | F_CONV}, + {"orn", 0xee01c00, 0xbfe0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEB, F_SIZEQ}, + {"uhadd", 0x2e200400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"uqadd", 0x2e200c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"urhadd", 0x2e201400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"uhsub", 0x2e202400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"uqsub", 0x2e202c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"cmhi", 0x2e203400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"cmhs", 0x2e203c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"ushl", 0x2e204400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"uqshl", 0x2e204c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"urshl", 0x2e205400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"uqrshl", 0x2e205c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"umax", 0x2e206400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"umin", 0x2e206c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"uabd", 0x2e207400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"uaba", 0x2e207c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"sub", 0x2e208400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"cmeq", 0x2e208c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAME, F_SIZEQ}, + {"mls", 0x2e209400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"pmul", 0x2e209c00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEB, F_SIZEQ}, + {"umaxp", 0x2e20a400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"uminp", 0x2e20ac00, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEBHS, F_SIZEQ}, + {"sqrdmulh", 0x2e20b400, 0xbf20fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEHS, F_SIZEQ}, + {"fmaxnmp", 0x2e20c400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"faddp", 0x2e20d400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fmul", 0x2e20dc00, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fcmge", 0x2e20e400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"facge", 0x2e20ec00, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fmaxp", 0x2e20f400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fdiv", 0x2e20fc00, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"eor", 0x2e201c00, 0xbfe0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEB, F_SIZEQ}, + {"bsl", 0x2e601c00, 0xbfe0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEB, F_SIZEQ}, + {"fminnmp", 0x2ea0c400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fabd", 0x2ea0d400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fcmgt", 0x2ea0e400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"facgt", 0x2ea0ec00, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"fminp", 0x2ea0f400, 0xbfa0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMESD, F_SIZEQ}, + {"bit", 0x2ea01c00, 0xbfe0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEB, F_SIZEQ}, + {"bif", 0x2ee01c00, 0xbfe0fc00, asimdsame, 0, SIMD, OP3 (Vd, Vn, Vm), QL_V3SAMEB, F_SIZEQ}, + /* AdvSIMD shift by immediate. */ + {"sshr", 0xf000400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFT, 0}, + {"ssra", 0xf001400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFT, 0}, + {"srshr", 0xf002400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFT, 0}, + {"srsra", 0xf003400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFT, 0}, + {"shl", 0xf005400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSL), QL_VSHIFT, 0}, + {"sqshl", 0xf007400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSL), QL_VSHIFT, 0}, + {"shrn", 0xf008400, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN, 0}, + {"shrn2", 0x4f008400, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN2, 0}, + {"rshrn", 0xf008c00, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN, 0}, + {"rshrn2", 0x4f008c00, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN2, 0}, + {"sqshrn", 0xf009400, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN, 0}, + {"sqshrn2", 0x4f009400, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN2, 0}, + {"sqrshrn", 0xf009c00, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN, 0}, + {"sqrshrn2", 0x4f009c00, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN2, 0}, + {"sshll", 0xf00a400, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSL), QL_VSHIFTL, 0}, + {"sshll2", 0x4f00a400, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSL), QL_VSHIFTL2, 0}, + {"scvtf", 0xf00e400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFT_SD, 0}, + {"fcvtzs", 0xf00fc00, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFT_SD, 0}, + {"ushr", 0x2f000400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFT, 0}, + {"usra", 0x2f001400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFT, 0}, + {"urshr", 0x2f002400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFT, 0}, + {"ursra", 0x2f003400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFT, 0}, + {"sri", 0x2f004400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFT, 0}, + {"sli", 0x2f005400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSL), QL_VSHIFT, 0}, + {"sqshlu", 0x2f006400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSL), QL_VSHIFT, 0}, + {"uqshl", 0x2f007400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSL), QL_VSHIFT, 0}, + {"sqshrun", 0x2f008400, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN, 0}, + {"sqshrun2", 0x6f008400, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN2, 0}, + {"sqrshrun", 0x2f008c00, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN, 0}, + {"sqrshrun2", 0x6f008c00, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN2, 0}, + {"uqshrn", 0x2f009400, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN, 0}, + {"uqshrn2", 0x6f009400, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN2, 0}, + {"uqrshrn", 0x2f009c00, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN, 0}, + {"uqrshrn2", 0x6f009c00, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFTN2, 0}, + {"ushll", 0x2f00a400, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSL), QL_VSHIFTL, 0}, + {"ushll2", 0x6f00a400, 0xff80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSL), QL_VSHIFTL2, 0}, + {"ucvtf", 0x2f00e400, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFT_SD, 0}, + {"fcvtzu", 0x2f00fc00, 0xbf80fc00, asimdshf, 0, SIMD, OP3 (Vd, Vn, IMM_VLSR), QL_VSHIFT_SD, 0}, + /* AdvSIMD TBL/TBX. */ + {"tbl", 0xe000000, 0xbfe09c00, asimdtbl, 0, SIMD, OP3 (Vd, LVn, Vm), QL_TABLE, F_SIZEQ}, + {"tbx", 0xe001000, 0xbfe09c00, asimdtbl, 0, SIMD, OP3 (Vd, LVn, Vm), QL_TABLE, F_SIZEQ}, + /* AdvSIMD scalar three different. */ + {"sqdmlal", 0x5e209000, 0xff20fc00, asisddiff, 0, SIMD, OP3 (Sd, Sn, Sm), QL_SISDL_HS, F_SSIZE}, + {"sqdmlsl", 0x5e20b000, 0xff20fc00, asisddiff, 0, SIMD, OP3 (Sd, Sn, Sm), QL_SISDL_HS, F_SSIZE}, + {"sqdmull", 0x5e20d000, 0xff20fc00, asisddiff, 0, SIMD, OP3 (Sd, Sn, Sm), QL_SISDL_HS, F_SSIZE}, + /* AdvSIMD scalar x indexed element. */ + {"sqdmlal", 0x5f003000, 0xff00f400, asisdelem, 0, SIMD, OP3 (Sd, Sn, Em), QL_SISDL_HS, F_SSIZE}, + {"sqdmlsl", 0x5f007000, 0xff00f400, asisdelem, 0, SIMD, OP3 (Sd, Sn, Em), QL_SISDL_HS, F_SSIZE}, + {"sqdmull", 0x5f00b000, 0xff00f400, asisdelem, 0, SIMD, OP3 (Sd, Sn, Em), QL_SISDL_HS, F_SSIZE}, + {"sqdmulh", 0x5f00c000, 0xff00f400, asisdelem, 0, SIMD, OP3 (Sd, Sn, Em), QL_SISD_HS, F_SSIZE}, + {"sqrdmulh", 0x5f00d000, 0xff00f400, asisdelem, 0, SIMD, OP3 (Sd, Sn, Em), QL_SISD_HS, F_SSIZE}, + {"fmla", 0x5f801000, 0xff80f400, asisdelem, 0, SIMD, OP3 (Sd, Sn, Em), QL_FP3, F_SSIZE}, + {"fmls", 0x5f805000, 0xff80f400, asisdelem, 0, SIMD, OP3 (Sd, Sn, Em), QL_FP3, F_SSIZE}, + {"fmul", 0x5f809000, 0xff80f400, asisdelem, 0, SIMD, OP3 (Sd, Sn, Em), QL_FP3, F_SSIZE}, + {"fmulx", 0x7f809000, 0xff80f400, asisdelem, 0, SIMD, OP3 (Sd, Sn, Em), QL_FP3, F_SSIZE}, + /* AdvSIMD load/store multiple structures. */ + {"st4", 0xc000000, 0xbfff0000, asisdlse, 0, SIMD, OP2 (LVt, SIMD_ADDR_SIMPLE), QL_SIMD_LDST, F_SIZEQ | F_OD(4)}, + {"st1", 0xc000000, 0xbfff0000, asisdlse, 0, SIMD, OP2 (LVt, SIMD_ADDR_SIMPLE), QL_SIMD_LDST_ANY, F_SIZEQ | F_OD(1)}, + {"st2", 0xc000000, 0xbfff0000, asisdlse, 0, SIMD, OP2 (LVt, SIMD_ADDR_SIMPLE), QL_SIMD_LDST, F_SIZEQ | F_OD(2)}, + {"st3", 0xc000000, 0xbfff0000, asisdlse, 0, SIMD, OP2 (LVt, SIMD_ADDR_SIMPLE), QL_SIMD_LDST, F_SIZEQ | F_OD(3)}, + {"ld4", 0xc400000, 0xbfff0000, asisdlse, 0, SIMD, OP2 (LVt, SIMD_ADDR_SIMPLE), QL_SIMD_LDST, F_SIZEQ | F_OD(4)}, + {"ld1", 0xc400000, 0xbfff0000, asisdlse, 0, SIMD, OP2 (LVt, SIMD_ADDR_SIMPLE), QL_SIMD_LDST_ANY, F_SIZEQ | F_OD(1)}, + {"ld2", 0xc400000, 0xbfff0000, asisdlse, 0, SIMD, OP2 (LVt, SIMD_ADDR_SIMPLE), QL_SIMD_LDST, F_SIZEQ | F_OD(2)}, + {"ld3", 0xc400000, 0xbfff0000, asisdlse, 0, SIMD, OP2 (LVt, SIMD_ADDR_SIMPLE), QL_SIMD_LDST, F_SIZEQ | F_OD(3)}, + /* AdvSIMD load/store multiple structures (post-indexed). */ + {"st4", 0xc800000, 0xbfe00000, asisdlsep, 0, SIMD, OP2 (LVt, SIMD_ADDR_POST), QL_SIMD_LDST, F_SIZEQ | F_OD(4)}, + {"st1", 0xc800000, 0xbfe00000, asisdlsep, 0, SIMD, OP2 (LVt, SIMD_ADDR_POST), QL_SIMD_LDST_ANY, F_SIZEQ | F_OD(1)}, + {"st2", 0xc800000, 0xbfe00000, asisdlsep, 0, SIMD, OP2 (LVt, SIMD_ADDR_POST), QL_SIMD_LDST, F_SIZEQ | F_OD(2)}, + {"st3", 0xc800000, 0xbfe00000, asisdlsep, 0, SIMD, OP2 (LVt, SIMD_ADDR_POST), QL_SIMD_LDST, F_SIZEQ | F_OD(3)}, + {"ld4", 0xcc00000, 0xbfe00000, asisdlsep, 0, SIMD, OP2 (LVt, SIMD_ADDR_POST), QL_SIMD_LDST, F_SIZEQ | F_OD(4)}, + {"ld1", 0xcc00000, 0xbfe00000, asisdlsep, 0, SIMD, OP2 (LVt, SIMD_ADDR_POST), QL_SIMD_LDST_ANY, F_SIZEQ | F_OD(1)}, + {"ld2", 0xcc00000, 0xbfe00000, asisdlsep, 0, SIMD, OP2 (LVt, SIMD_ADDR_POST), QL_SIMD_LDST, F_SIZEQ | F_OD(2)}, + {"ld3", 0xcc00000, 0xbfe00000, asisdlsep, 0, SIMD, OP2 (LVt, SIMD_ADDR_POST), QL_SIMD_LDST, F_SIZEQ | F_OD(3)}, + /* AdvSIMD load/store single structure. */ + {"st1", 0xd000000, 0xbfff2000, asisdlso, 0, SIMD, OP2 (LEt, SIMD_ADDR_SIMPLE), QL_SIMD_LDSTONE, F_OD(1)}, + {"st3", 0xd002000, 0xbfff2000, asisdlso, 0, SIMD, OP2 (LEt, SIMD_ADDR_SIMPLE), QL_SIMD_LDSTONE, F_OD(3)}, + {"st2", 0xd200000, 0xbfff2000, asisdlso, 0, SIMD, OP2 (LEt, SIMD_ADDR_SIMPLE), QL_SIMD_LDSTONE, F_OD(2)}, + {"st4", 0xd202000, 0xbfff2000, asisdlso, 0, SIMD, OP2 (LEt, SIMD_ADDR_SIMPLE), QL_SIMD_LDSTONE, F_OD(4)}, + {"ld1", 0xd400000, 0xbfff2000, asisdlso, 0, SIMD, OP2 (LEt, SIMD_ADDR_SIMPLE), QL_SIMD_LDSTONE, F_OD(1)}, + {"ld3", 0xd402000, 0xbfff2000, asisdlso, 0, SIMD, OP2 (LEt, SIMD_ADDR_SIMPLE), QL_SIMD_LDSTONE, F_OD(3)}, + {"ld1r", 0xd40c000, 0xbfffe000, asisdlso, 0, SIMD, OP2 (LVt_AL, SIMD_ADDR_SIMPLE), QL_SIMD_LDST_ANY, F_SIZEQ | F_OD(1)}, + {"ld3r", 0xd40e000, 0xbfffe000, asisdlso, 0, SIMD, OP2 (LVt_AL, SIMD_ADDR_SIMPLE), QL_SIMD_LDST_ANY, F_SIZEQ | F_OD(3)}, + {"ld2", 0xd600000, 0xbfff2000, asisdlso, 0, SIMD, OP2 (LEt, SIMD_ADDR_SIMPLE), QL_SIMD_LDSTONE, F_OD(2)}, + {"ld4", 0xd602000, 0xbfff2000, asisdlso, 0, SIMD, OP2 (LEt, SIMD_ADDR_SIMPLE), QL_SIMD_LDSTONE, F_OD(4)}, + {"ld2r", 0xd60c000, 0xbfffe000, asisdlso, 0, SIMD, OP2 (LVt_AL, SIMD_ADDR_SIMPLE), QL_SIMD_LDST_ANY, F_SIZEQ | F_OD(2)}, + {"ld4r", 0xd60e000, 0xbfffe000, asisdlso, 0, SIMD, OP2 (LVt_AL, SIMD_ADDR_SIMPLE), QL_SIMD_LDST_ANY, F_SIZEQ | F_OD(4)}, + /* AdvSIMD load/store single structure (post-indexed). */ + {"st1", 0xd800000, 0xbfe02000, asisdlsop, 0, SIMD, OP2 (LEt, SIMD_ADDR_POST), QL_SIMD_LDSTONE, F_OD(1)}, + {"st3", 0xd802000, 0xbfe02000, asisdlsop, 0, SIMD, OP2 (LEt, SIMD_ADDR_POST), QL_SIMD_LDSTONE, F_OD(3)}, + {"st2", 0xda00000, 0xbfe02000, asisdlsop, 0, SIMD, OP2 (LEt, SIMD_ADDR_POST), QL_SIMD_LDSTONE, F_OD(2)}, + {"st4", 0xda02000, 0xbfe02000, asisdlsop, 0, SIMD, OP2 (LEt, SIMD_ADDR_POST), QL_SIMD_LDSTONE, F_OD(4)}, + {"ld1", 0xdc00000, 0xbfe02000, asisdlsop, 0, SIMD, OP2 (LEt, SIMD_ADDR_POST), QL_SIMD_LDSTONE, F_OD(1)}, + {"ld3", 0xdc02000, 0xbfe02000, asisdlsop, 0, SIMD, OP2 (LEt, SIMD_ADDR_POST), QL_SIMD_LDSTONE, F_OD(3)}, + {"ld1r", 0xdc0c000, 0xbfe0e000, asisdlsop, 0, SIMD, OP2 (LVt_AL, SIMD_ADDR_POST), QL_SIMD_LDST_ANY, F_SIZEQ | F_OD(1)}, + {"ld3r", 0xdc0e000, 0xbfe0e000, asisdlsop, 0, SIMD, OP2 (LVt_AL, SIMD_ADDR_POST), QL_SIMD_LDST_ANY, F_SIZEQ | F_OD(3)}, + {"ld2", 0xde00000, 0xbfe02000, asisdlsop, 0, SIMD, OP2 (LEt, SIMD_ADDR_POST), QL_SIMD_LDSTONE, F_OD(2)}, + {"ld4", 0xde02000, 0xbfe02000, asisdlsop, 0, SIMD, OP2 (LEt, SIMD_ADDR_POST), QL_SIMD_LDSTONE, F_OD(4)}, + {"ld2r", 0xde0c000, 0xbfe0e000, asisdlsop, 0, SIMD, OP2 (LVt_AL, SIMD_ADDR_POST), QL_SIMD_LDST_ANY, F_SIZEQ | F_OD(2)}, + {"ld4r", 0xde0e000, 0xbfe0e000, asisdlsop, 0, SIMD, OP2 (LVt_AL, SIMD_ADDR_POST), QL_SIMD_LDST_ANY, F_SIZEQ | F_OD(4)}, + /* AdvSIMD scalar two-reg misc. */ + {"suqadd", 0x5e203800, 0xff3ffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAME, F_SSIZE}, + {"sqabs", 0x5e207800, 0xff3ffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAME, F_SSIZE}, + {"cmgt", 0x5e208800, 0xff3ffc00, asisdmisc, 0, SIMD, OP3 (Sd, Sn, IMM0), QL_SISD_CMP_0, F_SSIZE}, + {"cmeq", 0x5e209800, 0xff3ffc00, asisdmisc, 0, SIMD, OP3 (Sd, Sn, IMM0), QL_SISD_CMP_0, F_SSIZE}, + {"cmlt", 0x5e20a800, 0xff3ffc00, asisdmisc, 0, SIMD, OP3 (Sd, Sn, IMM0), QL_SISD_CMP_0, F_SSIZE}, + {"abs", 0x5e20b800, 0xff3ffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_2SAMED, F_SSIZE}, + {"sqxtn", 0x5e214800, 0xff3ffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_SISD_NARROW, F_SSIZE}, + {"fcvtns", 0x5e21a800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + {"fcvtms", 0x5e21b800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + {"fcvtas", 0x5e21c800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + {"scvtf", 0x5e21d800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + {"fcmgt", 0x5ea0c800, 0xffbffc00, asisdmisc, 0, SIMD, OP3 (Sd, Sn, IMM0), QL_SISD_FCMP_0, F_SSIZE}, + {"fcmeq", 0x5ea0d800, 0xffbffc00, asisdmisc, 0, SIMD, OP3 (Sd, Sn, IMM0), QL_SISD_FCMP_0, F_SSIZE}, + {"fcmlt", 0x5ea0e800, 0xffbffc00, asisdmisc, 0, SIMD, OP3 (Sd, Sn, IMM0), QL_SISD_FCMP_0, F_SSIZE}, + {"fcvtps", 0x5ea1a800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + {"fcvtzs", 0x5ea1b800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + {"frecpe", 0x5ea1d800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + {"frecpx", 0x5ea1f800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + {"usqadd", 0x7e203800, 0xff3ffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAME, F_SSIZE}, + {"sqneg", 0x7e207800, 0xff3ffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAME, F_SSIZE}, + {"cmge", 0x7e208800, 0xff3ffc00, asisdmisc, 0, SIMD, OP3 (Sd, Sn, IMM0), QL_SISD_CMP_0, F_SSIZE}, + {"cmle", 0x7e209800, 0xff3ffc00, asisdmisc, 0, SIMD, OP3 (Sd, Sn, IMM0), QL_SISD_CMP_0, F_SSIZE}, + {"neg", 0x7e20b800, 0xff3ffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_2SAMED, F_SSIZE}, + {"sqxtun", 0x7e212800, 0xff3ffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_SISD_NARROW, F_SSIZE}, + {"uqxtn", 0x7e214800, 0xff3ffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_SISD_NARROW, F_SSIZE}, + {"fcvtxn", 0x7e216800, 0xffbffc00, asisdmisc, OP_FCVTXN_S, SIMD, OP2 (Sd, Sn), QL_SISD_NARROW_S, F_MISC}, + {"fcvtnu", 0x7e21a800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + {"fcvtmu", 0x7e21b800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + {"fcvtau", 0x7e21c800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + {"ucvtf", 0x7e21d800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + {"fcmge", 0x7ea0c800, 0xffbffc00, asisdmisc, 0, SIMD, OP3 (Sd, Sn, IMM0), QL_SISD_FCMP_0, F_SSIZE}, + {"fcmle", 0x7ea0d800, 0xffbffc00, asisdmisc, 0, SIMD, OP3 (Sd, Sn, IMM0), QL_SISD_FCMP_0, F_SSIZE}, + {"fcvtpu", 0x7ea1a800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + {"fcvtzu", 0x7ea1b800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + {"frsqrte", 0x7ea1d800, 0xffbffc00, asisdmisc, 0, SIMD, OP2 (Sd, Sn), QL_S_2SAMESD, F_SSIZE}, + /* AdvSIMD scalar copy. */ + {"dup", 0x5e000400, 0xffe0fc00, asisdone, 0, SIMD, OP2 (Sd, En), QL_S_2SAME, F_HAS_ALIAS}, + {"mov", 0x5e000400, 0xffe0fc00, asisdone, 0, SIMD, OP2 (Sd, En), QL_S_2SAME, F_ALIAS}, + /* AdvSIMD scalar pairwise. */ + {"addp", 0x5e31b800, 0xff3ffc00, asisdpair, 0, SIMD, OP2 (Sd, Vn), QL_SISD_PAIR_D, F_SIZEQ}, + {"fmaxnmp", 0x7e30c800, 0xffbffc00, asisdpair, 0, SIMD, OP2 (Sd, Vn), QL_SISD_PAIR, F_SIZEQ}, + {"faddp", 0x7e30d800, 0xffbffc00, asisdpair, 0, SIMD, OP2 (Sd, Vn), QL_SISD_PAIR, F_SIZEQ}, + {"fmaxp", 0x7e30f800, 0xffbffc00, asisdpair, 0, SIMD, OP2 (Sd, Vn), QL_SISD_PAIR, F_SIZEQ}, + {"fminnmp", 0x7eb0c800, 0xffbffc00, asisdpair, 0, SIMD, OP2 (Sd, Vn), QL_SISD_PAIR, F_SIZEQ}, + {"fminp", 0x7eb0f800, 0xffbffc00, asisdpair, 0, SIMD, OP2 (Sd, Vn), QL_SISD_PAIR, F_SIZEQ}, + /* AdvSIMD scalar three same. */ + {"sqadd", 0x5e200c00, 0xff20fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAME, F_SSIZE}, + {"sqsub", 0x5e202c00, 0xff20fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAME, F_SSIZE}, + {"sqshl", 0x5e204c00, 0xff20fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAME, F_SSIZE}, + {"sqrshl", 0x5e205c00, 0xff20fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAME, F_SSIZE}, + {"sqdmulh", 0x5e20b400, 0xff20fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_SISD_HS, F_SSIZE}, + {"fmulx", 0x5e20dc00, 0xffa0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_FP3, F_SSIZE}, + {"fcmeq", 0x5e20e400, 0xffa0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_FP3, F_SSIZE}, + {"frecps", 0x5e20fc00, 0xffa0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_FP3, F_SSIZE}, + {"frsqrts", 0x5ea0fc00, 0xffa0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_FP3, F_SSIZE}, + {"cmgt", 0x5ee03400, 0xffe0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAMED, F_SSIZE}, + {"cmge", 0x5ee03c00, 0xffe0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAMED, F_SSIZE}, + {"sshl", 0x5ee04400, 0xffe0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAMED, F_SSIZE}, + {"srshl", 0x5ee05400, 0xffe0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAMED, F_SSIZE}, + {"add", 0x5ee08400, 0xffe0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAMED, F_SSIZE}, + {"cmtst", 0x5ee08c00, 0xffe0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAMED, F_SSIZE}, + {"uqadd", 0x7e200c00, 0xff20fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAME, F_SSIZE}, + {"uqsub", 0x7e202c00, 0xff20fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAME, F_SSIZE}, + {"uqshl", 0x7e204c00, 0xff20fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAME, F_SSIZE}, + {"uqrshl", 0x7e205c00, 0xff20fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAME, F_SSIZE}, + {"sqrdmulh", 0x7e20b400, 0xff20fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_SISD_HS, F_SSIZE}, + {"fcmge", 0x7e20e400, 0xffa0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_FP3, F_SSIZE}, + {"facge", 0x7e20ec00, 0xffa0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_FP3, F_SSIZE}, + {"fabd", 0x7ea0d400, 0xffa0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_FP3, F_SSIZE}, + {"fcmgt", 0x7ea0e400, 0xffa0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_FP3, F_SSIZE}, + {"facgt", 0x7ea0ec00, 0xffa0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_FP3, F_SSIZE}, + {"cmhi", 0x7ee03400, 0xffe0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAMED, F_SSIZE}, + {"cmhs", 0x7ee03c00, 0xffe0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAMED, F_SSIZE}, + {"ushl", 0x7ee04400, 0xffe0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAMED, F_SSIZE}, + {"urshl", 0x7ee05400, 0xffe0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAMED, F_SSIZE}, + {"sub", 0x7ee08400, 0xffe0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAMED, F_SSIZE}, + {"cmeq", 0x7ee08c00, 0xffe0fc00, asisdsame, 0, SIMD, OP3 (Sd, Sn, Sm), QL_S_3SAMED, F_SSIZE}, + /* AdvSIMD scalar shift by immediate. */ + {"sshr", 0x5f000400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFT_D, 0}, + {"ssra", 0x5f001400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFT_D, 0}, + {"srshr", 0x5f002400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFT_D, 0}, + {"srsra", 0x5f003400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFT_D, 0}, + {"shl", 0x5f005400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSL), QL_SSHIFT_D, 0}, + {"sqshl", 0x5f007400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSL), QL_SSHIFT, 0}, + {"sqshrn", 0x5f009400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFTN, 0}, + {"sqrshrn", 0x5f009c00, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFTN, 0}, + {"scvtf", 0x5f00e400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFT_SD, 0}, + {"fcvtzs", 0x5f00fc00, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFT_SD, 0}, + {"ushr", 0x7f000400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFT_D, 0}, + {"usra", 0x7f001400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFT_D, 0}, + {"urshr", 0x7f002400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFT_D, 0}, + {"ursra", 0x7f003400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFT_D, 0}, + {"sri", 0x7f004400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFT_D, 0}, + {"sli", 0x7f005400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSL), QL_SSHIFT_D, 0}, + {"sqshlu", 0x7f006400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSL), QL_SSHIFT, 0}, + {"uqshl", 0x7f007400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSL), QL_SSHIFT, 0}, + {"sqshrun", 0x7f008400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFTN, 0}, + {"sqrshrun", 0x7f008c00, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFTN, 0}, + {"uqshrn", 0x7f009400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFTN, 0}, + {"uqrshrn", 0x7f009c00, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFTN, 0}, + {"ucvtf", 0x7f00e400, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFT_SD, 0}, + {"fcvtzu", 0x7f00fc00, 0xff80fc00, asisdshf, 0, SIMD, OP3 (Sd, Sn, IMM_VLSR), QL_SSHIFT_SD, 0}, + /* Bitfield. */ + {"sbfm", 0x13000000, 0x7f800000, bitfield, 0, CORE, OP4 (Rd, Rn, IMMR, IMMS), QL_BF, F_HAS_ALIAS | F_SF | F_N}, + {"sbfiz", 0x13000000, 0x7f800000, bitfield, OP_SBFIZ, CORE, OP4 (Rd, Rn, IMM, WIDTH), QL_BF2, F_ALIAS | F_P1 | F_CONV}, + {"sbfx", 0x13000000, 0x7f800000, bitfield, OP_SBFX, CORE, OP4 (Rd, Rn, IMM, WIDTH), QL_BF2, F_ALIAS | F_P1 | F_CONV}, + {"sxtb", 0x13001c00, 0x7fbffc00, bitfield, 0, CORE, OP2 (Rd, Rn), QL_EXT, F_ALIAS | F_P3 | F_SF | F_N}, + {"sxth", 0x13003c00, 0x7fbffc00, bitfield, 0, CORE, OP2 (Rd, Rn), QL_EXT, F_ALIAS | F_P3 | F_SF | F_N}, + {"sxtw", 0x93407c00, 0xfffffc00, bitfield, 0, CORE, OP2 (Rd, Rn), QL_EXT_W, F_ALIAS | F_P3}, + {"asr", 0x13000000, 0x7f800000, bitfield, OP_ASR_IMM, CORE, OP3 (Rd, Rn, IMM), QL_SHIFT, F_ALIAS | F_P2 | F_CONV}, + {"bfm", 0x33000000, 0x7f800000, bitfield, 0, CORE, OP4 (Rd, Rn, IMMR, IMMS), QL_BF, F_HAS_ALIAS | F_SF | F_N}, + {"bfi", 0x33000000, 0x7f800000, bitfield, OP_BFI, CORE, OP4 (Rd, Rn, IMM, WIDTH), QL_BF2, F_ALIAS | F_P1 | F_CONV}, + {"bfxil", 0x33000000, 0x7f800000, bitfield, OP_BFXIL, CORE, OP4 (Rd, Rn, IMM, WIDTH), QL_BF2, F_ALIAS | F_P1 | F_CONV}, + {"ubfm", 0x53000000, 0x7f800000, bitfield, 0, CORE, OP4 (Rd, Rn, IMMR, IMMS), QL_BF, F_HAS_ALIAS | F_SF | F_N}, + {"ubfiz", 0x53000000, 0x7f800000, bitfield, OP_UBFIZ, CORE, OP4 (Rd, Rn, IMM, WIDTH), QL_BF2, F_ALIAS | F_P1 | F_CONV}, + {"ubfx", 0x53000000, 0x7f800000, bitfield, OP_UBFX, CORE, OP4 (Rd, Rn, IMM, WIDTH), QL_BF2, F_ALIAS | F_P1 | F_CONV}, + {"uxtb", 0x53001c00, 0xfffffc00, bitfield, OP_UXTB, CORE, OP2 (Rd, Rn), QL_I2SAMEW, F_ALIAS | F_P3}, + {"uxth", 0x53003c00, 0xfffffc00, bitfield, OP_UXTH, CORE, OP2 (Rd, Rn), QL_I2SAMEW, F_ALIAS | F_P3}, + {"lsl", 0x53000000, 0x7f800000, bitfield, OP_LSL_IMM, CORE, OP3 (Rd, Rn, IMM), QL_SHIFT, F_ALIAS | F_P2 | F_CONV}, + {"lsr", 0x53000000, 0x7f800000, bitfield, OP_LSR_IMM, CORE, OP3 (Rd, Rn, IMM), QL_SHIFT, F_ALIAS | F_P2 | F_CONV}, + /* Unconditional branch (immediate). */ + {"b", 0x14000000, 0xfc000000, branch_imm, OP_B, CORE, OP1 (ADDR_PCREL26), QL_PCREL_26, 0}, + {"bl", 0x94000000, 0xfc000000, branch_imm, OP_BL, CORE, OP1 (ADDR_PCREL26), QL_PCREL_26, 0}, + /* Unconditional branch (register). */ + {"br", 0xd61f0000, 0xfffffc1f, branch_reg, 0, CORE, OP1 (Rn), QL_I1X, 0}, + {"blr", 0xd63f0000, 0xfffffc1f, branch_reg, 0, CORE, OP1 (Rn), QL_I1X, 0}, + {"ret", 0xd65f0000, 0xfffffc1f, branch_reg, 0, CORE, OP1 (Rn), QL_I1X, F_OPD0_OPT | F_DEFAULT (30)}, + {"eret", 0xd69f03e0, 0xffffffff, branch_reg, 0, CORE, OP0 (), {}, 0}, + {"drps", 0xd6bf03e0, 0xffffffff, branch_reg, 0, CORE, OP0 (), {}, 0}, + /* Compare & branch (immediate). */ + {"cbz", 0x34000000, 0x7f000000, compbranch, 0, CORE, OP2 (Rt, ADDR_PCREL19), QL_R_PCREL, F_SF}, + {"cbnz", 0x35000000, 0x7f000000, compbranch, 0, CORE, OP2 (Rt, ADDR_PCREL19), QL_R_PCREL, F_SF}, + /* Conditional branch (immediate). */ + {"b.c", 0x54000000, 0xff000010, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_COND}, + /* Conditional compare (immediate). */ + {"ccmn", 0x3a400800, 0x7fe00c10, condcmp_imm, 0, CORE, OP4 (Rn, CCMP_IMM, NZCV, COND), QL_CCMP_IMM, F_SF}, + {"ccmp", 0x7a400800, 0x7fe00c10, condcmp_imm, 0, CORE, OP4 (Rn, CCMP_IMM, NZCV, COND), QL_CCMP_IMM, F_SF}, + /* Conditional compare (register). */ + {"ccmn", 0x3a400000, 0x7fe00c10, condcmp_reg, 0, CORE, OP4 (Rn, Rm, NZCV, COND), QL_CCMP, F_SF}, + {"ccmp", 0x7a400000, 0x7fe00c10, condcmp_reg, 0, CORE, OP4 (Rn, Rm, NZCV, COND), QL_CCMP, F_SF}, + /* Conditional select. */ + {"csel", 0x1a800000, 0x7fe00c00, condsel, 0, CORE, OP4 (Rd, Rn, Rm, COND), QL_CSEL, F_SF}, + {"csinc", 0x1a800400, 0x7fe00c00, condsel, 0, CORE, OP4 (Rd, Rn, Rm, COND), QL_CSEL, F_HAS_ALIAS | F_SF}, + {"cinc", 0x1a800400, 0x7fe00c00, condsel, OP_CINC, CORE, OP3 (Rd, Rn, COND), QL_CSEL, F_ALIAS | F_SF | F_CONV}, + {"cset", 0x1a9f07e0, 0x7fff0fe0, condsel, OP_CSET, CORE, OP2 (Rd, COND), QL_DST_R, F_ALIAS | F_P1 | F_SF | F_CONV}, + {"csinv", 0x5a800000, 0x7fe00c00, condsel, 0, CORE, OP4 (Rd, Rn, Rm, COND), QL_CSEL, F_HAS_ALIAS | F_SF}, + {"cinv", 0x5a800000, 0x7fe00c00, condsel, OP_CINV, CORE, OP3 (Rd, Rn, COND), QL_CSEL, F_ALIAS | F_SF | F_CONV}, + {"csetm", 0x5a9f03e0, 0x7fff0fe0, condsel, OP_CSETM, CORE, OP2 (Rd, COND), QL_DST_R, F_ALIAS | F_P1 | F_SF | F_CONV}, + {"csneg", 0x5a800400, 0x7fe00c00, condsel, 0, CORE, OP4 (Rd, Rn, Rm, COND), QL_CSEL, F_HAS_ALIAS | F_SF}, + {"cneg", 0x5a800400, 0x7fe00c00, condsel, OP_CNEG, CORE, OP3 (Rd, Rn, COND), QL_CSEL, F_ALIAS | F_SF | F_CONV}, + /* Crypto AES. */ + {"aese", 0x4e284800, 0xfffffc00, cryptoaes, 0, CRYPTO, OP2 (Vd, Vn), QL_V2SAME16B, 0}, + {"aesd", 0x4e285800, 0xfffffc00, cryptoaes, 0, CRYPTO, OP2 (Vd, Vn), QL_V2SAME16B, 0}, + {"aesmc", 0x4e286800, 0xfffffc00, cryptoaes, 0, CRYPTO, OP2 (Vd, Vn), QL_V2SAME16B, 0}, + {"aesimc", 0x4e287800, 0xfffffc00, cryptoaes, 0, CRYPTO, OP2 (Vd, Vn), QL_V2SAME16B, 0}, + /* Crypto two-reg SHA. */ + {"sha1h", 0x5e280800, 0xfffffc00, cryptosha2, 0, CRYPTO, OP2 (Fd, Fn), QL_2SAMES, 0}, + {"sha1su1", 0x5e281800, 0xfffffc00, cryptosha2, 0, CRYPTO, OP2 (Vd, Vn), QL_V2SAME4S, 0}, + {"sha256su0", 0x5e282800, 0xfffffc00, cryptosha2, 0, CRYPTO, OP2 (Vd, Vn), QL_V2SAME4S, 0}, + /* Crypto three-reg SHA. */ + {"sha1c", 0x5e000000, 0xffe0fc00, cryptosha3, 0, CRYPTO, OP3 (Fd, Fn, Vm), QL_SHAUPT, 0}, + {"sha1p", 0x5e001000, 0xffe0fc00, cryptosha3, 0, CRYPTO, OP3 (Fd, Fn, Vm), QL_SHAUPT, 0}, + {"sha1m", 0x5e002000, 0xffe0fc00, cryptosha3, 0, CRYPTO, OP3 (Fd, Fn, Vm), QL_SHAUPT, 0}, + {"sha1su0", 0x5e003000, 0xffe0fc00, cryptosha3, 0, CRYPTO, OP3 (Vd, Vn, Vm), QL_V3SAME4S, 0}, + {"sha256h", 0x5e004000, 0xffe0fc00, cryptosha3, 0, CRYPTO, OP3 (Fd, Fn, Vm), QL_SHA256UPT, 0}, + {"sha256h2", 0x5e005000, 0xffe0fc00, cryptosha3, 0, CRYPTO, OP3 (Fd, Fn, Vm), QL_SHA256UPT, 0}, + {"sha256su1", 0x5e006000, 0xffe0fc00, cryptosha3, 0, CRYPTO, OP3 (Vd, Vn, Vm), QL_V3SAME4S, 0}, + /* Data-processing (1 source). */ + {"rbit", 0x5ac00000, 0x7ffffc00, dp_1src, 0, CORE, OP2 (Rd, Rn), QL_I2SAME, F_SF}, + {"rev16", 0x5ac00400, 0x7ffffc00, dp_1src, 0, CORE, OP2 (Rd, Rn), QL_I2SAME, F_SF}, + {"rev", 0x5ac00800, 0xfffffc00, dp_1src, 0, CORE, OP2 (Rd, Rn), QL_I2SAMEW, 0}, + {"rev", 0xdac00c00, 0x7ffffc00, dp_1src, 0, CORE, OP2 (Rd, Rn), QL_I2SAMEX, 0}, + {"clz", 0x5ac01000, 0x7ffffc00, dp_1src, 0, CORE, OP2 (Rd, Rn), QL_I2SAME, F_SF}, + {"cls", 0x5ac01400, 0x7ffffc00, dp_1src, 0, CORE, OP2 (Rd, Rn), QL_I2SAME, F_SF}, + {"rev32", 0xdac00800, 0xfffffc00, dp_1src, 0, CORE, OP2 (Rd, Rn), QL_I2SAMEX, 0}, + /* Data-processing (2 source). */ + {"udiv", 0x1ac00800, 0x7fe0fc00, dp_2src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_SF}, + {"sdiv", 0x1ac00c00, 0x7fe0fc00, dp_2src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_SF}, + {"lslv", 0x1ac02000, 0x7fe0fc00, dp_2src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_SF | F_HAS_ALIAS}, + {"lsl", 0x1ac02000, 0x7fe0fc00, dp_2src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_SF | F_ALIAS}, + {"lsrv", 0x1ac02400, 0x7fe0fc00, dp_2src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_SF | F_HAS_ALIAS}, + {"lsr", 0x1ac02400, 0x7fe0fc00, dp_2src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_SF | F_ALIAS}, + {"asrv", 0x1ac02800, 0x7fe0fc00, dp_2src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_SF | F_HAS_ALIAS}, + {"asr", 0x1ac02800, 0x7fe0fc00, dp_2src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_SF | F_ALIAS}, + {"rorv", 0x1ac02c00, 0x7fe0fc00, dp_2src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_SF | F_HAS_ALIAS}, + {"ror", 0x1ac02c00, 0x7fe0fc00, dp_2src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_SF | F_ALIAS}, + /* Data-processing (3 source). */ + {"madd", 0x1b000000, 0x7fe08000, dp_3src, 0, CORE, OP4 (Rd, Rn, Rm, Ra), QL_I4SAMER, F_HAS_ALIAS | F_SF}, + {"mul", 0x1b007c00, 0x7fe0fc00, dp_3src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_ALIAS | F_SF}, + {"msub", 0x1b008000, 0x7fe08000, dp_3src, 0, CORE, OP4 (Rd, Rn, Rm, Ra), QL_I4SAMER, F_HAS_ALIAS | F_SF}, + {"mneg", 0x1b00fc00, 0x7fe0fc00, dp_3src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_ALIAS | F_SF}, + {"smaddl", 0x9b200000, 0xffe08000, dp_3src, 0, CORE, OP4 (Rd, Rn, Rm, Ra), QL_I4SAMEL, F_HAS_ALIAS}, + {"smull", 0x9b207c00, 0xffe0fc00, dp_3src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMEL, F_ALIAS}, + {"smsubl", 0x9b208000, 0xffe08000, dp_3src, 0, CORE, OP4 (Rd, Rn, Rm, Ra), QL_I4SAMEL, F_HAS_ALIAS}, + {"smnegl", 0x9b20fc00, 0xffe0fc00, dp_3src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMEL, F_ALIAS}, + {"smulh", 0x9b407c00, 0xffe08000, dp_3src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMEX, 0}, + {"umaddl", 0x9ba00000, 0xffe08000, dp_3src, 0, CORE, OP4 (Rd, Rn, Rm, Ra), QL_I4SAMEL, F_HAS_ALIAS}, + {"umull", 0x9ba07c00, 0xffe0fc00, dp_3src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMEL, F_ALIAS}, + {"umsubl", 0x9ba08000, 0xffe08000, dp_3src, 0, CORE, OP4 (Rd, Rn, Rm, Ra), QL_I4SAMEL, F_HAS_ALIAS}, + {"umnegl", 0x9ba0fc00, 0xffe0fc00, dp_3src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMEL, F_ALIAS}, + {"umulh", 0x9bc07c00, 0xffe08000, dp_3src, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMEX, 0}, + /* Excep'n generation. */ + {"svc", 0xd4000001, 0xffe0001f, exception, 0, CORE, OP1 (EXCEPTION), {}, 0}, + {"hvc", 0xd4000002, 0xffe0001f, exception, 0, CORE, OP1 (EXCEPTION), {}, 0}, + {"smc", 0xd4000003, 0xffe0001f, exception, 0, CORE, OP1 (EXCEPTION), {}, 0}, + {"brk", 0xd4200000, 0xffe0001f, exception, 0, CORE, OP1 (EXCEPTION), {}, 0}, + {"hlt", 0xd4400000, 0xffe0001f, exception, 0, CORE, OP1 (EXCEPTION), {}, 0}, + {"dcps1", 0xd4a00001, 0xffe0001f, exception, 0, CORE, OP1 (EXCEPTION), {}, F_OPD0_OPT | F_DEFAULT (0)}, + {"dcps2", 0xd4a00002, 0xffe0001f, exception, 0, CORE, OP1 (EXCEPTION), {}, F_OPD0_OPT | F_DEFAULT (0)}, + {"dcps3", 0xd4a00003, 0xffe0001f, exception, 0, CORE, OP1 (EXCEPTION), {}, F_OPD0_OPT | F_DEFAULT (0)}, + /* Extract. */ + {"extr", 0x13800000, 0x7fa00000, extract, 0, CORE, OP4 (Rd, Rn, Rm, IMMS), QL_EXTR, F_HAS_ALIAS | F_SF | F_N}, + {"ror", 0x13800000, 0x7fa00000, extract, OP_ROR_IMM, CORE, OP3 (Rd, Rm, IMMS), QL_SHIFT, F_ALIAS | F_CONV}, + /* Floating-point<->fixed-point conversions. */ + {"scvtf", 0x1e020000, 0x7f3f0000, float2fix, 0, FP, OP3 (Fd, Rn, FBITS), QL_FIX2FP, F_FPTYPE | F_SF}, + {"ucvtf", 0x1e030000, 0x7f3f0000, float2fix, 0, FP, OP3 (Fd, Rn, FBITS), QL_FIX2FP, F_FPTYPE | F_SF}, + {"fcvtzs", 0x1e180000, 0x7f3f0000, float2fix, 0, FP, OP3 (Rd, Fn, FBITS), QL_FP2FIX, F_FPTYPE | F_SF}, + {"fcvtzu", 0x1e190000, 0x7f3f0000, float2fix, 0, FP, OP3 (Rd, Fn, FBITS), QL_FP2FIX, F_FPTYPE | F_SF}, + /* Floating-point<->integer conversions. */ + {"fcvtns", 0x1e200000, 0x7f3ffc00, float2int, 0, FP, OP2 (Rd, Fn), QL_FP2INT, F_FPTYPE | F_SF}, + {"fcvtnu", 0x1e210000, 0x7f3ffc00, float2int, 0, FP, OP2 (Rd, Fn), QL_FP2INT, F_FPTYPE | F_SF}, + {"scvtf", 0x1e220000, 0x7f3ffc00, float2int, 0, FP, OP2 (Fd, Rn), QL_INT2FP, F_FPTYPE | F_SF}, + {"ucvtf", 0x1e230000, 0x7f3ffc00, float2int, 0, FP, OP2 (Fd, Rn), QL_INT2FP, F_FPTYPE | F_SF}, + {"fcvtas", 0x1e240000, 0x7f3ffc00, float2int, 0, FP, OP2 (Rd, Fn), QL_FP2INT, F_FPTYPE | F_SF}, + {"fcvtau", 0x1e250000, 0x7f3ffc00, float2int, 0, FP, OP2 (Rd, Fn), QL_FP2INT, F_FPTYPE | F_SF}, + {"fmov", 0x1e260000, 0x7f3ffc00, float2int, 0, FP, OP2 (Rd, Fn), QL_FP2INT, F_FPTYPE | F_SF}, + {"fmov", 0x1e270000, 0x7f3ffc00, float2int, 0, FP, OP2 (Fd, Rn), QL_INT2FP, F_FPTYPE | F_SF}, + {"fcvtps", 0x1e280000, 0x7f3ffc00, float2int, 0, FP, OP2 (Rd, Fn), QL_FP2INT, F_FPTYPE | F_SF}, + {"fcvtpu", 0x1e290000, 0x7f3ffc00, float2int, 0, FP, OP2 (Rd, Fn), QL_FP2INT, F_FPTYPE | F_SF}, + {"fcvtms", 0x1e300000, 0x7f3ffc00, float2int, 0, FP, OP2 (Rd, Fn), QL_FP2INT, F_FPTYPE | F_SF}, + {"fcvtmu", 0x1e310000, 0x7f3ffc00, float2int, 0, FP, OP2 (Rd, Fn), QL_FP2INT, F_FPTYPE | F_SF}, + {"fcvtzs", 0x1e380000, 0x7f3ffc00, float2int, 0, FP, OP2 (Rd, Fn), QL_FP2INT, F_FPTYPE | F_SF}, + {"fcvtzu", 0x1e390000, 0x7f3ffc00, float2int, 0, FP, OP2 (Rd, Fn), QL_FP2INT, F_FPTYPE | F_SF}, + {"fmov", 0x9eae0000, 0xfffffc00, float2int, 0, FP, OP2 (Rd, VnD1), QL_XVD1, 0}, + {"fmov", 0x9eaf0000, 0xfffffc00, float2int, 0, FP, OP2 (VdD1, Rn), QL_VD1X, 0}, + /* Floating-point conditional compare. */ + {"fccmp", 0x1e200400, 0xff200c10, floatccmp, 0, FP, OP4 (Fn, Fm, NZCV, COND), QL_FCCMP, F_FPTYPE}, + {"fccmpe", 0x1e200410, 0xff200c10, floatccmp, 0, FP, OP4 (Fn, Fm, NZCV, COND), QL_FCCMP, F_FPTYPE}, + /* Floating-point compare. */ + {"fcmp", 0x1e202000, 0xff20fc1f, floatcmp, 0, FP, OP2 (Fn, Fm), QL_FP2, F_FPTYPE}, + {"fcmpe", 0x1e202010, 0xff20fc1f, floatcmp, 0, FP, OP2 (Fn, Fm), QL_FP2, F_FPTYPE}, + {"fcmp", 0x1e202008, 0xff20fc1f, floatcmp, 0, FP, OP2 (Fn, FPIMM0), QL_DST_SD, F_FPTYPE}, + {"fcmpe", 0x1e202018, 0xff20fc1f, floatcmp, 0, FP, OP2 (Fn, FPIMM0), QL_DST_SD, F_FPTYPE}, + /* Floating-point data-processing (1 source). */ + {"fmov", 0x1e204000, 0xff3ffc00, floatdp1, 0, FP, OP2 (Fd, Fn), QL_FP2, F_FPTYPE}, + {"fabs", 0x1e20c000, 0xff3ffc00, floatdp1, 0, FP, OP2 (Fd, Fn), QL_FP2, F_FPTYPE}, + {"fneg", 0x1e214000, 0xff3ffc00, floatdp1, 0, FP, OP2 (Fd, Fn), QL_FP2, F_FPTYPE}, + {"fsqrt", 0x1e21c000, 0xff3ffc00, floatdp1, 0, FP, OP2 (Fd, Fn), QL_FP2, F_FPTYPE}, + {"fcvt", 0x1e224000, 0xff3e7c00, floatdp1, OP_FCVT, FP, OP2 (Fd, Fn), QL_FCVT, F_FPTYPE | F_MISC}, + {"frintn", 0x1e244000, 0xff3ffc00, floatdp1, 0, FP, OP2 (Fd, Fn), QL_FP2, F_FPTYPE}, + {"frintp", 0x1e24c000, 0xff3ffc00, floatdp1, 0, FP, OP2 (Fd, Fn), QL_FP2, F_FPTYPE}, + {"frintm", 0x1e254000, 0xff3ffc00, floatdp1, 0, FP, OP2 (Fd, Fn), QL_FP2, F_FPTYPE}, + {"frintz", 0x1e25c000, 0xff3ffc00, floatdp1, 0, FP, OP2 (Fd, Fn), QL_FP2, F_FPTYPE}, + {"frinta", 0x1e264000, 0xff3ffc00, floatdp1, 0, FP, OP2 (Fd, Fn), QL_FP2, F_FPTYPE}, + {"frintx", 0x1e274000, 0xff3ffc00, floatdp1, 0, FP, OP2 (Fd, Fn), QL_FP2, F_FPTYPE}, + {"frinti", 0x1e27c000, 0xff3ffc00, floatdp1, 0, FP, OP2 (Fd, Fn), QL_FP2, F_FPTYPE}, + /* Floating-point data-processing (2 source). */ + {"fmul", 0x1e200800, 0xff20fc00, floatdp2, 0, FP, OP3 (Fd, Fn, Fm), QL_FP3, F_FPTYPE}, + {"fdiv", 0x1e201800, 0xff20fc00, floatdp2, 0, FP, OP3 (Fd, Fn, Fm), QL_FP3, F_FPTYPE}, + {"fadd", 0x1e202800, 0xff20fc00, floatdp2, 0, FP, OP3 (Fd, Fn, Fm), QL_FP3, F_FPTYPE}, + {"fsub", 0x1e203800, 0xff20fc00, floatdp2, 0, FP, OP3 (Fd, Fn, Fm), QL_FP3, F_FPTYPE}, + {"fmax", 0x1e204800, 0xff20fc00, floatdp2, 0, FP, OP3 (Fd, Fn, Fm), QL_FP3, F_FPTYPE}, + {"fmin", 0x1e205800, 0xff20fc00, floatdp2, 0, FP, OP3 (Fd, Fn, Fm), QL_FP3, F_FPTYPE}, + {"fmaxnm", 0x1e206800, 0xff20fc00, floatdp2, 0, FP, OP3 (Fd, Fn, Fm), QL_FP3, F_FPTYPE}, + {"fminnm", 0x1e207800, 0xff20fc00, floatdp2, 0, FP, OP3 (Fd, Fn, Fm), QL_FP3, F_FPTYPE}, + {"fnmul", 0x1e208800, 0xff20fc00, floatdp2, 0, FP, OP3 (Fd, Fn, Fm), QL_FP3, F_FPTYPE}, + /* Floating-point data-processing (3 source). */ + {"fmadd", 0x1f000000, 0xff208000, floatdp3, 0, FP, OP4 (Fd, Fn, Fm, Fa), QL_FP4, F_FPTYPE}, + {"fmsub", 0x1f008000, 0xff208000, floatdp3, 0, FP, OP4 (Fd, Fn, Fm, Fa), QL_FP4, F_FPTYPE}, + {"fnmadd", 0x1f200000, 0xff208000, floatdp3, 0, FP, OP4 (Fd, Fn, Fm, Fa), QL_FP4, F_FPTYPE}, + {"fnmsub", 0x1f208000, 0xff208000, floatdp3, 0, FP, OP4 (Fd, Fn, Fm, Fa), QL_FP4, F_FPTYPE}, + /* Floating-point immediate. */ + {"fmov", 0x1e201000, 0xff201fe0, floatimm, 0, FP, OP2 (Fd, FPIMM), QL_DST_SD, F_FPTYPE}, + /* Floating-point conditional select. */ + {"fcsel", 0x1e200c00, 0xff200c00, floatsel, 0, FP, OP4 (Fd, Fn, Fm, COND), QL_FP_COND, F_FPTYPE}, + /* Load/store register (immediate indexed). */ + {"strb", 0x38000400, 0xffe00400, ldst_imm9, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_W8, 0}, + {"ldrb", 0x38400400, 0xffe00400, ldst_imm9, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_W8, 0}, + {"ldrsb", 0x38800400, 0xffa00400, ldst_imm9, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_R8, F_LDS_SIZE}, + {"str", 0x3c000400, 0x3f600400, ldst_imm9, 0, CORE, OP2 (Ft, ADDR_SIMM9), QL_LDST_FP, 0}, + {"ldr", 0x3c400400, 0x3f600400, ldst_imm9, 0, CORE, OP2 (Ft, ADDR_SIMM9), QL_LDST_FP, 0}, + {"strh", 0x78000400, 0xffe00400, ldst_imm9, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_W16, 0}, + {"ldrh", 0x78400400, 0xffe00400, ldst_imm9, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_W16, 0}, + {"ldrsh", 0x78800400, 0xffa00400, ldst_imm9, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_R16, F_LDS_SIZE}, + {"str", 0xb8000400, 0xbfe00400, ldst_imm9, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_R, F_GPRSIZE_IN_Q}, + {"ldr", 0xb8400400, 0xbfe00400, ldst_imm9, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_R, F_GPRSIZE_IN_Q}, + {"ldrsw", 0xb8800400, 0xffe00400, ldst_imm9, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_X32, 0}, + /* Load/store register (unsigned immediate). */ + {"strb", 0x39000000, 0xffc00000, ldst_pos, OP_STRB_POS, CORE, OP2 (Rt, ADDR_UIMM12), QL_LDST_W8, 0}, + {"ldrb", 0x39400000, 0xffc00000, ldst_pos, OP_LDRB_POS, CORE, OP2 (Rt, ADDR_UIMM12), QL_LDST_W8, 0}, + {"ldrsb", 0x39800000, 0xff800000, ldst_pos, OP_LDRSB_POS, CORE, OP2 (Rt, ADDR_UIMM12), QL_LDST_R8, F_LDS_SIZE}, + {"str", 0x3d000000, 0x3f400000, ldst_pos, OP_STRF_POS, CORE, OP2 (Ft, ADDR_UIMM12), QL_LDST_FP, 0}, + {"ldr", 0x3d400000, 0x3f400000, ldst_pos, OP_LDRF_POS, CORE, OP2 (Ft, ADDR_UIMM12), QL_LDST_FP, 0}, + {"strh", 0x79000000, 0xffc00000, ldst_pos, OP_STRH_POS, CORE, OP2 (Rt, ADDR_UIMM12), QL_LDST_W16, 0}, + {"ldrh", 0x79400000, 0xffc00000, ldst_pos, OP_LDRH_POS, CORE, OP2 (Rt, ADDR_UIMM12), QL_LDST_W16, 0}, + {"ldrsh", 0x79800000, 0xff800000, ldst_pos, OP_LDRSH_POS, CORE, OP2 (Rt, ADDR_UIMM12), QL_LDST_R16, F_LDS_SIZE}, + {"str", 0xb9000000, 0xbfc00000, ldst_pos, OP_STR_POS, CORE, OP2 (Rt, ADDR_UIMM12), QL_LDST_R, F_GPRSIZE_IN_Q}, + {"ldr", 0xb9400000, 0xbfc00000, ldst_pos, OP_LDR_POS, CORE, OP2 (Rt, ADDR_UIMM12), QL_LDST_R, F_GPRSIZE_IN_Q}, + {"ldrsw", 0xb9800000, 0xffc00000, ldst_pos, OP_LDRSW_POS, CORE, OP2 (Rt, ADDR_UIMM12), QL_LDST_X32, 0}, + {"prfm", 0xf9800000, 0xffc00000, ldst_pos, OP_PRFM_POS, CORE, OP2 (PRFOP, ADDR_UIMM12), QL_LDST_PRFM, 0}, + /* Load/store register (register offset). */ + {"strb", 0x38200800, 0xffe00c00, ldst_regoff, 0, CORE, OP2 (Rt, ADDR_REGOFF), QL_LDST_W8, 0}, + {"ldrb", 0x38600800, 0xffe00c00, ldst_regoff, 0, CORE, OP2 (Rt, ADDR_REGOFF), QL_LDST_W8, 0}, + {"ldrsb", 0x38a00800, 0xffa00c00, ldst_regoff, 0, CORE, OP2 (Rt, ADDR_REGOFF), QL_LDST_R8, F_LDS_SIZE}, + {"str", 0x3c200800, 0x3f600c00, ldst_regoff, 0, CORE, OP2 (Ft, ADDR_REGOFF), QL_LDST_FP, 0}, + {"ldr", 0x3c600800, 0x3f600c00, ldst_regoff, 0, CORE, OP2 (Ft, ADDR_REGOFF), QL_LDST_FP, 0}, + {"strh", 0x78200800, 0xffe00c00, ldst_regoff, 0, CORE, OP2 (Rt, ADDR_REGOFF), QL_LDST_W16, 0}, + {"ldrh", 0x78600800, 0xffe00c00, ldst_regoff, 0, CORE, OP2 (Rt, ADDR_REGOFF), QL_LDST_W16, 0}, + {"ldrsh", 0x78a00800, 0xffa00c00, ldst_regoff, 0, CORE, OP2 (Rt, ADDR_REGOFF), QL_LDST_R16, F_LDS_SIZE}, + {"str", 0xb8200800, 0xbfe00c00, ldst_regoff, 0, CORE, OP2 (Rt, ADDR_REGOFF), QL_LDST_R, F_GPRSIZE_IN_Q}, + {"ldr", 0xb8600800, 0xbfe00c00, ldst_regoff, 0, CORE, OP2 (Rt, ADDR_REGOFF), QL_LDST_R, F_GPRSIZE_IN_Q}, + {"ldrsw", 0xb8a00800, 0xffe00c00, ldst_regoff, 0, CORE, OP2 (Rt, ADDR_REGOFF), QL_LDST_X32, 0}, + {"prfm", 0xf8a00800, 0xffe00c00, ldst_regoff, 0, CORE, OP2 (PRFOP, ADDR_REGOFF), QL_LDST_PRFM, 0}, + /* Load/store register (unprivileged). */ + {"sttrb", 0x38000800, 0xffe00c00, ldst_unpriv, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_W8, 0}, + {"ldtrb", 0x38400800, 0xffe00c00, ldst_unpriv, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_W8, 0}, + {"ldtrsb", 0x38800800, 0xffa00c00, ldst_unpriv, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_R8, F_LDS_SIZE}, + {"sttrh", 0x78000800, 0xffe00c00, ldst_unpriv, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_W16, 0}, + {"ldtrh", 0x78400800, 0xffe00c00, ldst_unpriv, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_W16, 0}, + {"ldtrsh", 0x78800800, 0xffa00c00, ldst_unpriv, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_R16, F_LDS_SIZE}, + {"sttr", 0xb8000800, 0xbfe00c00, ldst_unpriv, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_R, F_GPRSIZE_IN_Q}, + {"ldtr", 0xb8400800, 0xbfe00c00, ldst_unpriv, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_R, F_GPRSIZE_IN_Q}, + {"ldtrsw", 0xb8800800, 0xffe00c00, ldst_unpriv, 0, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_X32, 0}, + /* Load/store register (unscaled immediate). */ + {"sturb", 0x38000000, 0xffe00c00, ldst_unscaled, OP_STURB, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_W8, F_HAS_ALIAS}, + {"ldurb", 0x38400000, 0xffe00c00, ldst_unscaled, OP_LDURB, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_W8, F_HAS_ALIAS}, + {"strb", 0x38000000, 0xffe00c00, ldst_unscaled, 0, CORE, OP2 (Rt, ADDR_SIMM9_2), QL_LDST_W8, F_ALIAS}, + {"ldrb", 0x38400000, 0xffe00c00, ldst_unscaled, 0, CORE, OP2 (Rt, ADDR_SIMM9_2), QL_LDST_W8, F_ALIAS}, + {"ldursb", 0x38800000, 0xffa00c00, ldst_unscaled, OP_LDURSB, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_R8, F_HAS_ALIAS | F_LDS_SIZE}, + {"ldrsb", 0x38800000, 0xffa00c00, ldst_unscaled, 0, CORE, OP2 (Rt, ADDR_SIMM9_2), QL_LDST_R8, F_ALIAS | F_LDS_SIZE}, + {"stur", 0x3c000000, 0x3f600c00, ldst_unscaled, OP_STURV, CORE, OP2 (Ft, ADDR_SIMM9), QL_LDST_FP, F_HAS_ALIAS}, + {"ldur", 0x3c400000, 0x3f600c00, ldst_unscaled, OP_LDURV, CORE, OP2 (Ft, ADDR_SIMM9), QL_LDST_FP, F_HAS_ALIAS}, + {"str", 0x3c000000, 0x3f600c00, ldst_unscaled, 0, CORE, OP2 (Ft, ADDR_SIMM9_2), QL_LDST_FP, F_ALIAS}, + {"ldr", 0x3c400000, 0x3f600c00, ldst_unscaled, 0, CORE, OP2 (Ft, ADDR_SIMM9_2), QL_LDST_FP, F_ALIAS}, + {"sturh", 0x78000000, 0xffe00c00, ldst_unscaled, OP_STURH, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_W16, F_HAS_ALIAS}, + {"ldurh", 0x78400000, 0xffe00c00, ldst_unscaled, OP_LDURH, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_W16, F_HAS_ALIAS}, + {"strh", 0x78000000, 0xffe00c00, ldst_unscaled, 0, CORE, OP2 (Rt, ADDR_SIMM9_2), QL_LDST_W16, F_ALIAS}, + {"ldrh", 0x78400000, 0xffe00c00, ldst_unscaled, 0, CORE, OP2 (Rt, ADDR_SIMM9_2), QL_LDST_W16, F_ALIAS}, + {"ldursh", 0x78800000, 0xffa00c00, ldst_unscaled, OP_LDURSH, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_R16, F_HAS_ALIAS | F_LDS_SIZE}, + {"ldrsh", 0x78800000, 0xffa00c00, ldst_unscaled, 0, CORE, OP2 (Rt, ADDR_SIMM9_2), QL_LDST_R16, F_ALIAS | F_LDS_SIZE}, + {"stur", 0xb8000000, 0xbfe00c00, ldst_unscaled, OP_STUR, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_R, F_HAS_ALIAS | F_GPRSIZE_IN_Q}, + {"ldur", 0xb8400000, 0xbfe00c00, ldst_unscaled, OP_LDUR, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_R, F_HAS_ALIAS | F_GPRSIZE_IN_Q}, + {"str", 0xb8000000, 0xbfe00c00, ldst_unscaled, 0, CORE, OP2 (Rt, ADDR_SIMM9_2), QL_LDST_R, F_ALIAS | F_GPRSIZE_IN_Q}, + {"ldr", 0xb8400000, 0xbfe00c00, ldst_unscaled, 0, CORE, OP2 (Rt, ADDR_SIMM9_2), QL_LDST_R, F_ALIAS | F_GPRSIZE_IN_Q}, + {"ldursw", 0xb8800000, 0xffe00c00, ldst_unscaled, OP_LDURSW, CORE, OP2 (Rt, ADDR_SIMM9), QL_LDST_X32, F_HAS_ALIAS}, + {"ldrsw", 0xb8800000, 0xffe00c00, ldst_unscaled, 0, CORE, OP2 (Rt, ADDR_SIMM9_2), QL_LDST_X32, F_ALIAS}, + {"prfum", 0xf8800000, 0xffe00c00, ldst_unscaled, OP_PRFUM, CORE, OP2 (PRFOP, ADDR_SIMM9), QL_LDST_PRFM, F_HAS_ALIAS}, + {"prfm", 0xf8800000, 0xffe00c00, ldst_unscaled, 0, CORE, OP2 (PRFOP, ADDR_SIMM9_2), QL_LDST_PRFM, F_ALIAS}, + /* Load/store exclusive. */ + {"stxrb", 0x8007c00, 0xffe08000, ldstexcl, 0, CORE, OP3 (Rs, Rt, ADDR_SIMPLE), QL_W2_LDST_EXC, 0}, + {"stlxrb", 0x800fc00, 0xffe08000, ldstexcl, 0, CORE, OP3 (Rs, Rt, ADDR_SIMPLE), QL_W2_LDST_EXC, 0}, + {"ldxrb", 0x85f7c00, 0xffe08000, ldstexcl, 0, CORE, OP2 (Rt, ADDR_SIMPLE), QL_W1_LDST_EXC, 0}, + {"ldaxrb", 0x85ffc00, 0xffe08000, ldstexcl, 0, CORE, OP2 (Rt, ADDR_SIMPLE), QL_W1_LDST_EXC, 0}, + {"stlrb", 0x89ffc00, 0xffe08000, ldstexcl, 0, CORE, OP2 (Rt, ADDR_SIMPLE), QL_W1_LDST_EXC, 0}, + {"ldarb", 0x8dffc00, 0xffe08000, ldstexcl, 0, CORE, OP2 (Rt, ADDR_SIMPLE), QL_W1_LDST_EXC, 0}, + {"stxrh", 0x48007c00, 0xffe08000, ldstexcl, 0, CORE, OP3 (Rs, Rt, ADDR_SIMPLE), QL_W2_LDST_EXC, 0}, + {"stlxrh", 0x4800fc00, 0xffe08000, ldstexcl, 0, CORE, OP3 (Rs, Rt, ADDR_SIMPLE), QL_W2_LDST_EXC, 0}, + {"ldxrh", 0x485f7c00, 0xffe08000, ldstexcl, 0, CORE, OP2 (Rt, ADDR_SIMPLE), QL_W1_LDST_EXC, 0}, + {"ldaxrh", 0x485ffc00, 0xffe08000, ldstexcl, 0, CORE, OP2 (Rt, ADDR_SIMPLE), QL_W1_LDST_EXC, 0}, + {"stlrh", 0x489ffc00, 0xffe08000, ldstexcl, 0, CORE, OP2 (Rt, ADDR_SIMPLE), QL_W1_LDST_EXC, 0}, + {"ldarh", 0x48dffc00, 0xffe08000, ldstexcl, 0, CORE, OP2 (Rt, ADDR_SIMPLE), QL_W1_LDST_EXC, 0}, + {"stxr", 0x88007c00, 0xbfe08000, ldstexcl, 0, CORE, OP3 (Rs, Rt, ADDR_SIMPLE), QL_R2_LDST_EXC, F_GPRSIZE_IN_Q}, + {"stlxr", 0x8800fc00, 0xbfe08000, ldstexcl, 0, CORE, OP3 (Rs, Rt, ADDR_SIMPLE), QL_R2_LDST_EXC, F_GPRSIZE_IN_Q}, + {"stxp", 0x88200000, 0xbfe08000, ldstexcl, 0, CORE, OP4 (Rs, Rt, Rt2, ADDR_SIMPLE), QL_R3_LDST_EXC, F_GPRSIZE_IN_Q}, + {"stlxp", 0x88208000, 0xbfe08000, ldstexcl, 0, CORE, OP4 (Rs, Rt, Rt2, ADDR_SIMPLE), QL_R3_LDST_EXC, F_GPRSIZE_IN_Q}, + {"ldxr", 0x885f7c00, 0xbfe08000, ldstexcl, 0, CORE, OP2 (Rt, ADDR_SIMPLE), QL_R1NIL, F_GPRSIZE_IN_Q}, + {"ldaxr", 0x885ffc00, 0xbfe08000, ldstexcl, 0, CORE, OP2 (Rt, ADDR_SIMPLE), QL_R1NIL, F_GPRSIZE_IN_Q}, + {"ldxp", 0x887f0000, 0xbfe08000, ldstexcl, 0, CORE, OP3 (Rt, Rt2, ADDR_SIMPLE), QL_R2NIL, F_GPRSIZE_IN_Q}, + {"ldaxp", 0x887f8000, 0xbfe08000, ldstexcl, 0, CORE, OP3 (Rt, Rt2, ADDR_SIMPLE), QL_R2NIL, F_GPRSIZE_IN_Q}, + {"stlr", 0x889ffc00, 0xbfe08000, ldstexcl, 0, CORE, OP2 (Rt, ADDR_SIMPLE), QL_R1NIL, F_GPRSIZE_IN_Q}, + {"ldar", 0x88dffc00, 0xbfe08000, ldstexcl, 0, CORE, OP2 (Rt, ADDR_SIMPLE), QL_R1NIL, F_GPRSIZE_IN_Q}, + /* Load/store no-allocate pair (offset). */ + {"stnp", 0x28000000, 0x7fc00000, ldstnapair_offs, 0, CORE, OP3 (Rt, Rt2, ADDR_SIMM7), QL_LDST_PAIR_R, F_SF}, + {"ldnp", 0x28400000, 0x7fc00000, ldstnapair_offs, 0, CORE, OP3 (Rt, Rt2, ADDR_SIMM7), QL_LDST_PAIR_R, F_SF}, + {"stnp", 0x2c000000, 0x3fc00000, ldstnapair_offs, 0, CORE, OP3 (Ft, Ft2, ADDR_SIMM7), QL_LDST_PAIR_FP, 0}, + {"ldnp", 0x2c400000, 0x3fc00000, ldstnapair_offs, 0, CORE, OP3 (Ft, Ft2, ADDR_SIMM7), QL_LDST_PAIR_FP, 0}, + /* Load/store register pair (offset). */ + {"stp", 0x29000000, 0x7ec00000, ldstpair_off, 0, CORE, OP3 (Rt, Rt2, ADDR_SIMM7), QL_LDST_PAIR_R, F_SF}, + {"ldp", 0x29400000, 0x7ec00000, ldstpair_off, 0, CORE, OP3 (Rt, Rt2, ADDR_SIMM7), QL_LDST_PAIR_R, F_SF}, + {"stp", 0x2d000000, 0x3fc00000, ldstpair_off, 0, CORE, OP3 (Ft, Ft2, ADDR_SIMM7), QL_LDST_PAIR_FP, 0}, + {"ldp", 0x2d400000, 0x3fc00000, ldstpair_off, 0, CORE, OP3 (Ft, Ft2, ADDR_SIMM7), QL_LDST_PAIR_FP, 0}, + {"ldpsw", 0x69400000, 0xffc00000, ldstpair_off, 0, CORE, OP3 (Rt, Rt2, ADDR_SIMM7), QL_LDST_PAIR_X32, 0}, + /* Load/store register pair (indexed). */ + {"stp", 0x28800000, 0x7ec00000, ldstpair_indexed, 0, CORE, OP3 (Rt, Rt2, ADDR_SIMM7), QL_LDST_PAIR_R, F_SF}, + {"ldp", 0x28c00000, 0x7ec00000, ldstpair_indexed, 0, CORE, OP3 (Rt, Rt2, ADDR_SIMM7), QL_LDST_PAIR_R, F_SF}, + {"stp", 0x2c800000, 0x3ec00000, ldstpair_indexed, 0, CORE, OP3 (Ft, Ft2, ADDR_SIMM7), QL_LDST_PAIR_FP, 0}, + {"ldp", 0x2cc00000, 0x3ec00000, ldstpair_indexed, 0, CORE, OP3 (Ft, Ft2, ADDR_SIMM7), QL_LDST_PAIR_FP, 0}, + {"ldpsw", 0x68c00000, 0xfec00000, ldstpair_indexed, 0, CORE, OP3 (Rt, Rt2, ADDR_SIMM7), QL_LDST_PAIR_X32, 0}, + /* Load register (literal). */ + {"ldr", 0x18000000, 0xbf000000, loadlit, OP_LDR_LIT, CORE, OP2 (Rt, ADDR_PCREL19), QL_R_PCREL, F_GPRSIZE_IN_Q}, + {"ldr", 0x1c000000, 0x3f000000, loadlit, OP_LDRV_LIT, CORE, OP2 (Ft, ADDR_PCREL19), QL_FP_PCREL, 0}, + {"ldrsw", 0x98000000, 0xff000000, loadlit, OP_LDRSW_LIT, CORE, OP2 (Rt, ADDR_PCREL19), QL_X_PCREL, 0}, + {"prfm", 0xd8000000, 0xff000000, loadlit, OP_PRFM_LIT, CORE, OP2 (PRFOP, ADDR_PCREL19), QL_PRFM_PCREL, 0}, + /* Logical (immediate). */ + {"and", 0x12000000, 0x7f800000, log_imm, 0, CORE, OP3 (Rd_SP, Rn, LIMM), QL_R2NIL, F_HAS_ALIAS | F_SF}, + {"bic", 0x12000000, 0x7f800000, log_imm, OP_BIC, CORE, OP3 (Rd_SP, Rn, LIMM), QL_R2NIL, F_ALIAS | F_PSEUDO | F_SF}, + {"orr", 0x32000000, 0x7f800000, log_imm, 0, CORE, OP3 (Rd_SP, Rn, LIMM), QL_R2NIL, F_HAS_ALIAS | F_SF}, + {"mov", 0x320003e0, 0x7f8003e0, log_imm, OP_MOV_IMM_LOG, CORE, OP2 (Rd_SP, IMM_MOV), QL_R1NIL, F_ALIAS | F_PSEUDO | F_P1 | F_SF | F_CONV}, + {"eor", 0x52000000, 0x7f800000, log_imm, 0, CORE, OP3 (Rd_SP, Rn, LIMM), QL_R2NIL, F_SF}, + {"ands", 0x72000000, 0x7f800000, log_imm, 0, CORE, OP3 (Rd, Rn, LIMM), QL_R2NIL, F_HAS_ALIAS | F_SF}, + {"tst", 0x7200001f, 0x7f80001f, log_imm, 0, CORE, OP2 (Rn, LIMM), QL_R1NIL, F_ALIAS | F_SF}, + /* Logical (shifted register). */ + {"and", 0xa000000, 0x7f200000, log_shift, 0, CORE, OP3 (Rd, Rn, Rm_SFT), QL_I3SAMER, F_SF}, + {"bic", 0xa200000, 0x7f200000, log_shift, 0, CORE, OP3 (Rd, Rn, Rm_SFT), QL_I3SAMER, F_SF}, + {"orr", 0x2a000000, 0x7f200000, log_shift, 0, CORE, OP3 (Rd, Rn, Rm_SFT), QL_I3SAMER, F_HAS_ALIAS | F_SF}, + {"mov", 0x2a0003e0, 0x7f2003e0, log_shift, 0, CORE, OP2 (Rd, Rm), QL_I2SAMER, F_ALIAS | F_SF}, + {"uxtw", 0x2a0003e0, 0x7f2003e0, log_shift, OP_UXTW, CORE, OP2 (Rd, Rm), QL_I2SAMEW, F_ALIAS | F_PSEUDO}, + {"orn", 0x2a200000, 0x7f200000, log_shift, 0, CORE, OP3 (Rd, Rn, Rm_SFT), QL_I3SAMER, F_HAS_ALIAS | F_SF}, + {"mvn", 0x2a2003e0, 0x7f2003e0, log_shift, 0, CORE, OP2 (Rd, Rm_SFT), QL_I2SAMER, F_ALIAS | F_SF}, + {"eor", 0x4a000000, 0x7f200000, log_shift, 0, CORE, OP3 (Rd, Rn, Rm_SFT), QL_I3SAMER, F_SF}, + {"eon", 0x4a200000, 0x7f200000, log_shift, 0, CORE, OP3 (Rd, Rn, Rm_SFT), QL_I3SAMER, F_SF}, + {"ands", 0x6a000000, 0x7f200000, log_shift, 0, CORE, OP3 (Rd, Rn, Rm_SFT), QL_I3SAMER, F_HAS_ALIAS | F_SF}, + {"tst", 0x6a00001f, 0x7f20001f, log_shift, 0, CORE, OP2 (Rn, Rm_SFT), QL_I2SAMER, F_ALIAS | F_SF}, + {"bics", 0x6a200000, 0x7f200000, log_shift, 0, CORE, OP3 (Rd, Rn, Rm_SFT), QL_I3SAMER, F_SF}, + /* Move wide (immediate). */ + {"movn", 0x12800000, 0x7f800000, movewide, OP_MOVN, CORE, OP2 (Rd, HALF), QL_DST_R, F_SF | F_HAS_ALIAS}, + {"mov", 0x12800000, 0x7f800000, movewide, OP_MOV_IMM_WIDEN, CORE, OP2 (Rd, IMM_MOV), QL_DST_R, F_SF | F_ALIAS | F_PSEUDO | F_CONV}, + {"movz", 0x52800000, 0x7f800000, movewide, OP_MOVZ, CORE, OP2 (Rd, HALF), QL_DST_R, F_SF | F_HAS_ALIAS}, + {"mov", 0x52800000, 0x7f800000, movewide, OP_MOV_IMM_WIDE, CORE, OP2 (Rd, IMM_MOV), QL_DST_R, F_SF | F_ALIAS | F_PSEUDO | F_CONV}, + {"movk", 0x72800000, 0x7f800000, movewide, OP_MOVK, CORE, OP2 (Rd, HALF), QL_DST_R, F_SF}, + /* PC-rel. addressing. */ + {"adr", 0x10000000, 0x9f000000, pcreladdr, 0, CORE, OP2 (Rd, ADDR_PCREL21), QL_ADRP, 0}, + {"adrp", 0x90000000, 0x9f000000, pcreladdr, 0, CORE, OP2 (Rd, ADDR_ADRP), QL_ADRP, 0}, + /* System. */ + {"msr", 0xd500401f, 0xfff8f01f, ic_system, 0, CORE, OP2 (PSTATEFIELD, UIMM4), {}, 0}, + {"hint", 0xd503201f, 0xfffff01f, ic_system, 0, CORE, OP1 (UIMM7), {}, F_HAS_ALIAS}, + {"nop", 0xd503201f, 0xffffffff, ic_system, 0, CORE, OP0 (), {}, F_ALIAS}, + {"yield", 0xd503203f, 0xffffffff, ic_system, 0, CORE, OP0 (), {}, F_ALIAS}, + {"wfe", 0xd503205f, 0xffffffff, ic_system, 0, CORE, OP0 (), {}, F_ALIAS}, + {"wfi", 0xd503207f, 0xffffffff, ic_system, 0, CORE, OP0 (), {}, F_ALIAS}, + {"sev", 0xd503209f, 0xffffffff, ic_system, 0, CORE, OP0 (), {}, F_ALIAS}, + {"sevl", 0xd50320bf, 0xffffffff, ic_system, 0, CORE, OP0 (), {}, F_ALIAS}, + {"clrex", 0xd503305f, 0xfffff0ff, ic_system, 0, CORE, OP1 (UIMM4), {}, F_OPD0_OPT | F_DEFAULT (0xF)}, + {"dsb", 0xd503309f, 0xfffff0ff, ic_system, 0, CORE, OP1 (BARRIER), {}, 0}, + {"dmb", 0xd50330bf, 0xfffff0ff, ic_system, 0, CORE, OP1 (BARRIER), {}, 0}, + {"isb", 0xd50330df, 0xfffff0ff, ic_system, 0, CORE, OP1 (BARRIER_ISB), {}, F_OPD0_OPT | F_DEFAULT (0xF)}, + {"sys", 0xd5080000, 0xfff80000, ic_system, 0, CORE, OP5 (UIMM3_OP1, Cn, Cm, UIMM3_OP2, Rt), QL_SYS, F_HAS_ALIAS | F_OPD4_OPT | F_DEFAULT (0x1F)}, + {"at", 0xd5080000, 0xfff80000, ic_system, 0, CORE, OP2 (SYSREG_AT, Rt), QL_SRC_X, F_ALIAS}, + {"dc", 0xd5080000, 0xfff80000, ic_system, 0, CORE, OP2 (SYSREG_DC, Rt), QL_SRC_X, F_ALIAS}, + {"ic", 0xd5080000, 0xfff80000, ic_system, 0, CORE, OP2 (SYSREG_IC, Rt_SYS), QL_SRC_X, F_ALIAS | F_OPD1_OPT | F_DEFAULT (0x1F)}, + {"tlbi", 0xd5080000, 0xfff80000, ic_system, 0, CORE, OP2 (SYSREG_TLBI, Rt_SYS), QL_SRC_X, F_ALIAS | F_OPD1_OPT | F_DEFAULT (0x1F)}, + {"msr", 0xd5100000, 0xfff00000, ic_system, 0, CORE, OP2 (SYSREG, Rt), QL_SRC_X, 0}, + {"sysl", 0xd5280000, 0xfff80000, ic_system, 0, CORE, OP5 (Rt, UIMM3_OP1, Cn, Cm, UIMM3_OP2), QL_SYSL, 0}, + {"mrs", 0xd5300000, 0xfff00000, ic_system, 0, CORE, OP2 (Rt, SYSREG), QL_DST_X, 0}, + /* Test & branch (immediate). */ + {"tbz", 0x36000000, 0x7f000000, testbranch, 0, CORE, OP3 (Rt, BIT_NUM, ADDR_PCREL14), QL_PCREL_14, 0}, + {"tbnz", 0x37000000, 0x7f000000, testbranch, 0, CORE, OP3 (Rt, BIT_NUM, ADDR_PCREL14), QL_PCREL_14, 0}, + /* The old UAL conditional branch mnemonics (to aid portability). */ + {"beq", 0x54000000, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"bne", 0x54000001, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"bcs", 0x54000002, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"bhs", 0x54000002, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"bcc", 0x54000003, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"blo", 0x54000003, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"bmi", 0x54000004, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"bpl", 0x54000005, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"bvs", 0x54000006, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"bvc", 0x54000007, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"bhi", 0x54000008, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"bls", 0x54000009, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"bge", 0x5400000a, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"blt", 0x5400000b, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"bgt", 0x5400000c, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + {"ble", 0x5400000d, 0xff00001f, condbranch, 0, CORE, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_ALIAS | F_PSEUDO}, + + {0, 0, 0, 0, 0, 0, {}, {}, 0}, +}; + +#ifdef AARCH64_OPERANDS +#undef AARCH64_OPERANDS +#endif + +/* Macro-based operand decription; this will be fed into aarch64-gen for it + to generate the structure aarch64_operands and the function + aarch64_insert_operand and aarch64_extract_operand. + + These inserters and extracters in the description execute the conversion + between the aarch64_opnd_info and value in the operand-related instruction + field(s). */ + +/* Y expects arguments (left to right) to be operand class, inserter/extractor + name suffix, operand name, flags, related bitfield(s) and description. + X only differs from Y by having the operand inserter and extractor names + listed separately. */ + +#define AARCH64_OPERANDS \ + Y(INT_REG, regno, "Rd", 0, F(FLD_Rd), "an integer register") \ + Y(INT_REG, regno, "Rn", 0, F(FLD_Rn), "an integer register") \ + Y(INT_REG, regno, "Rm", 0, F(FLD_Rm), "an integer register") \ + Y(INT_REG, regno, "Rt", 0, F(FLD_Rt), "an integer register") \ + Y(INT_REG, regno, "Rt2", 0, F(FLD_Rt2), "an integer register") \ + Y(INT_REG, regno, "Rs", 0, F(FLD_Rs), "an integer register") \ + Y(INT_REG, regno, "Ra", 0, F(FLD_Ra), "an integer register") \ + X(INT_REG, ins_regno, ext_regrt_sysins, "Rt_SYS", 0, F(FLD_Rt), \ + "an integer register") \ + Y(INT_REG, regno, "Rd_SP", OPD_F_MAYBE_SP, F(FLD_Rd), \ + "an integer or stack pointer register") \ + Y(INT_REG, regno, "Rn_SP", OPD_F_MAYBE_SP, F(FLD_Rn), \ + "an integer or stack pointer register") \ + Y(MODIFIED_REG, reg_extended, "Rm_EXT", 0, F(), \ + "an integer register with optional extension") \ + Y(MODIFIED_REG, reg_shifted, "Rm_SFT", 0, F(), \ + "an integer register with optional shift") \ + Y(FP_REG, regno, "Fd", 0, F(FLD_Rd), "a floating-point register") \ + Y(FP_REG, regno, "Fn", 0, F(FLD_Rn), "a floating-point register") \ + Y(FP_REG, regno, "Fm", 0, F(FLD_Rm), "a floating-point register") \ + Y(FP_REG, regno, "Fa", 0, F(FLD_Ra), "a floating-point register") \ + Y(FP_REG, ft, "Ft", 0, F(FLD_Rt), "a floating-point register") \ + Y(FP_REG, regno, "Ft2", 0, F(FLD_Rt2), "a floating-point register") \ + Y(SISD_REG, regno, "Sd", 0, F(FLD_Rd), "a SIMD scalar register") \ + Y(SISD_REG, regno, "Sn", 0, F(FLD_Rn), "a SIMD scalar register") \ + Y(SISD_REG, regno, "Sm", 0, F(FLD_Rm), "a SIMD scalar register") \ + Y(SIMD_REG, regno, "Vd", 0, F(FLD_Rd), "a SIMD vector register") \ + Y(SIMD_REG, regno, "Vn", 0, F(FLD_Rn), "a SIMD vector register") \ + Y(SIMD_REG, regno, "Vm", 0, F(FLD_Rm), "a SIMD vector register") \ + Y(FP_REG, regno, "VdD1", 0, F(FLD_Rd), \ + "the top half of a 128-bit FP/SIMD register") \ + Y(FP_REG, regno, "VnD1", 0, F(FLD_Rn), \ + "the top half of a 128-bit FP/SIMD register") \ + Y(SIMD_ELEMENT, reglane, "Ed", 0, F(FLD_Rd), \ + "a SIMD vector element") \ + Y(SIMD_ELEMENT, reglane, "En", 0, F(FLD_Rn), \ + "a SIMD vector element") \ + Y(SIMD_ELEMENT, reglane, "Em", 0, F(FLD_Rm), \ + "a SIMD vector element") \ + Y(SIMD_REGLIST, reglist, "LVn", 0, F(FLD_Rn), \ + "a SIMD vector register list") \ + Y(SIMD_REGLIST, ldst_reglist, "LVt", 0, F(), \ + "a SIMD vector register list") \ + Y(SIMD_REGLIST, ldst_reglist_r, "LVt_AL", 0, F(), \ + "a SIMD vector register list") \ + Y(SIMD_REGLIST, ldst_elemlist, "LEt", 0, F(), \ + "a SIMD vector element list") \ + Y(CP_REG, regno, "Cn", 0, F(FLD_CRn), \ + "a 4-bit opcode field named for historical reasons C0 - C15") \ + Y(CP_REG, regno, "Cm", 0, F(FLD_CRm), \ + "a 4-bit opcode field named for historical reasons C0 - C15") \ + Y(IMMEDIATE, imm, "IDX", 0, F(FLD_imm4), \ + "an immediate as the index of the least significant byte") \ + Y(IMMEDIATE, advsimd_imm_shift, "IMM_VLSL", 0, F(), \ + "a left shift amount for an AdvSIMD register") \ + Y(IMMEDIATE, advsimd_imm_shift, "IMM_VLSR", 0, F(), \ + "a right shift amount for an AdvSIMD register") \ + Y(IMMEDIATE, advsimd_imm_modified, "SIMD_IMM", 0, F(), \ + "an immediate") \ + Y(IMMEDIATE, advsimd_imm_modified, "SIMD_IMM_SFT", 0, F(), \ + "an 8-bit unsigned immediate with optional shift") \ + Y(IMMEDIATE, advsimd_imm_modified, "SIMD_FPIMM", 0, F(), \ + "an 8-bit floating-point constant") \ + X(IMMEDIATE, 0, ext_shll_imm, "SHLL_IMM", 0, F(), \ + "an immediate shift amount of 8, 16 or 32") \ + X(IMMEDIATE, 0, 0, "IMM0", 0, F(), "0") \ + X(IMMEDIATE, 0, 0, "FPIMM0", 0, F(), "0.0") \ + Y(IMMEDIATE, imm, "FPIMM", 0, F(FLD_imm8), \ + "an 8-bit floating-point constant") \ + Y(IMMEDIATE, imm, "IMMR", 0, F(FLD_immr), \ + "the right rotate amount") \ + Y(IMMEDIATE, imm, "IMMS", 0, F(FLD_imm6), \ + "the leftmost bit number to be moved from the source") \ + Y(IMMEDIATE, imm, "WIDTH", 0, F(FLD_imm6), \ + "the width of the bit-field") \ + Y(IMMEDIATE, imm, "IMM", 0, F(FLD_imm6), "an immediate") \ + Y(IMMEDIATE, imm, "UIMM3_OP1", 0, F(FLD_op1), \ + "a 3-bit unsigned immediate") \ + Y(IMMEDIATE, imm, "UIMM3_OP2", 0, F(FLD_op2), \ + "a 3-bit unsigned immediate") \ + Y(IMMEDIATE, imm, "UIMM4", 0, F(FLD_CRm), \ + "a 4-bit unsigned immediate") \ + Y(IMMEDIATE, imm, "UIMM7", 0, F(FLD_CRm, FLD_op2), \ + "a 7-bit unsigned immediate") \ + Y(IMMEDIATE, imm, "BIT_NUM", 0, F(FLD_b5, FLD_b40), \ + "the bit number to be tested") \ + Y(IMMEDIATE, imm, "EXCEPTION", 0, F(FLD_imm16), \ + "a 16-bit unsigned immediate") \ + Y(IMMEDIATE, imm, "CCMP_IMM", 0, F(FLD_imm5), \ + "a 5-bit unsigned immediate") \ + Y(IMMEDIATE, imm, "NZCV", 0, F(FLD_nzcv), \ + "a flag bit specifier giving an alternative value for each flag") \ + Y(IMMEDIATE, limm, "LIMM", 0, F(FLD_N,FLD_immr,FLD_imms), \ + "Logical immediate") \ + Y(IMMEDIATE, aimm, "AIMM", 0, F(FLD_shift,FLD_imm12), \ + "a 12-bit unsigned immediate with optional left shift of 12 bits")\ + Y(IMMEDIATE, imm_half, "HALF", 0, F(FLD_imm16), \ + "a 16-bit immediate with optional left shift") \ + Y(IMMEDIATE, fbits, "FBITS", 0, F(FLD_scale), \ + "the number of bits after the binary point in the fixed-point value")\ + X(IMMEDIATE, 0, 0, "IMM_MOV", 0, F(), "an immediate") \ + Y(NIL, cond, "COND", 0, F(), "a condition") \ + X(ADDRESS, 0, ext_imm, "ADDR_ADRP", OPD_F_SEXT, F(FLD_immhi, FLD_immlo),\ + "21-bit PC-relative address of a 4KB page") \ + Y(ADDRESS, imm, "ADDR_PCREL14", OPD_F_SEXT | OPD_F_SHIFT_BY_2, \ + F(FLD_imm14), "14-bit PC-relative address") \ + Y(ADDRESS, imm, "ADDR_PCREL19", OPD_F_SEXT | OPD_F_SHIFT_BY_2, \ + F(FLD_imm19), "19-bit PC-relative address") \ + Y(ADDRESS, imm, "ADDR_PCREL21", OPD_F_SEXT, F(FLD_immhi,FLD_immlo), \ + "21-bit PC-relative address") \ + Y(ADDRESS, imm, "ADDR_PCREL26", OPD_F_SEXT | OPD_F_SHIFT_BY_2, \ + F(FLD_imm26), "26-bit PC-relative address") \ + Y(ADDRESS, addr_simple, "ADDR_SIMPLE", 0, F(), \ + "an address with base register (no offset)") \ + Y(ADDRESS, addr_regoff, "ADDR_REGOFF", 0, F(), \ + "an address with register offset") \ + Y(ADDRESS, addr_simm, "ADDR_SIMM7", 0, F(FLD_imm7,FLD_index2), \ + "an address with 7-bit signed immediate offset") \ + Y(ADDRESS, addr_simm, "ADDR_SIMM9", 0, F(FLD_imm9,FLD_index), \ + "an address with 9-bit signed immediate offset") \ + Y(ADDRESS, addr_simm, "ADDR_SIMM9_2", 0, F(FLD_imm9,FLD_index), \ + "an address with 9-bit negative or unaligned immediate offset") \ + Y(ADDRESS, addr_uimm12, "ADDR_UIMM12", 0, F(FLD_Rn,FLD_imm12), \ + "an address with scaled, unsigned immediate offset") \ + Y(ADDRESS, addr_simple, "SIMD_ADDR_SIMPLE", 0, F(), \ + "an address with base register (no offset)") \ + Y(ADDRESS, simd_addr_post, "SIMD_ADDR_POST", 0, F(), \ + "a post-indexed address with immediate or register increment") \ + Y(SYSTEM, sysreg, "SYSREG", 0, F(), "a system register") \ + Y(SYSTEM, pstatefield, "PSTATEFIELD", 0, F(), \ + "a PSTATE field name") \ + Y(SYSTEM, sysins_op, "SYSREG_AT", 0, F(), \ + "an address translation operation specifier") \ + Y(SYSTEM, sysins_op, "SYSREG_DC", 0, F(), \ + "a data cache maintenance operation specifier") \ + Y(SYSTEM, sysins_op, "SYSREG_IC", 0, F(), \ + "an instructin cache maintenance operation specifier") \ + Y(SYSTEM, sysins_op, "SYSREG_TLBI", 0, F(), \ + "a TBL invalidation operation specifier") \ + Y(SYSTEM, barrier, "BARRIER", 0, F(), \ + "a barrier option name") \ + Y(SYSTEM, barrier, "BARRIER_ISB", 0, F(), \ + "the ISB option name SY or an optional 4-bit unsigned immediate") \ + Y(SYSTEM, prfop, "PRFOP", 0, F(), \ + "an prefetch operation specifier") diff --git a/opcodes/configure b/opcodes/configure index 9b6cc7d..708996b 100755 --- a/opcodes/configure +++ b/opcodes/configure @@ -12486,6 +12486,7 @@ if test x${all_targets} = xfalse ; then ad=`echo $arch | sed -e s/bfd_//g -e s/_arch//g` archdefs="$archdefs -DARCH_$ad" case "$arch" in + bfd_aarch64_arch) ta="$ta aarch64-asm.lo aarch64-dis.lo aarch64-opc.lo aarch64-asm-2.lo aarch64-dis-2.lo aarch64-opc-2.lo" ;; bfd_alpha_arch) ta="$ta alpha-dis.lo alpha-opc.lo" ;; bfd_arc_arch) ta="$ta arc-dis.lo arc-opc.lo arc-ext.lo" ;; bfd_arm_arch) ta="$ta arm-dis.lo" ;; diff --git a/opcodes/configure.in b/opcodes/configure.in index 486ffa0..0d6d742 100644 --- a/opcodes/configure.in +++ b/opcodes/configure.in @@ -231,6 +231,7 @@ if test x${all_targets} = xfalse ; then ad=`echo $arch | sed -e s/bfd_//g -e s/_arch//g` archdefs="$archdefs -DARCH_$ad" case "$arch" in + bfd_aarch64_arch) ta="$ta aarch64-asm.lo aarch64-dis.lo aarch64-opc.lo aarch64-asm-2.lo aarch64-dis-2.lo aarch64-opc-2.lo" ;; bfd_alpha_arch) ta="$ta alpha-dis.lo alpha-opc.lo" ;; bfd_arc_arch) ta="$ta arc-dis.lo arc-opc.lo arc-ext.lo" ;; bfd_arm_arch) ta="$ta arm-dis.lo" ;; diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c index 3dad64b..c5887b0 100644 --- a/opcodes/disassemble.c +++ b/opcodes/disassemble.c @@ -24,6 +24,7 @@ #include "dis-asm.h" #ifdef ARCH_all +#define ARCH_aarch64 #define ARCH_alpha #define ARCH_arc #define ARCH_arm @@ -113,6 +114,11 @@ disassembler (abfd) { /* If you add a case to this table, also add it to the ARCH_all definition right above this function. */ +#ifdef ARCH_aarch64 + case bfd_arch_aarch64: + disassemble = print_insn_aarch64; + break; +#endif #ifdef ARCH_alpha case bfd_arch_alpha: disassemble = print_insn_alpha; @@ -516,6 +522,9 @@ void disassembler_usage (stream) FILE * stream ATTRIBUTE_UNUSED; { +#ifdef ARCH_aarch64 + print_aarch64_disassembler_options (stream); +#endif #ifdef ARCH_arm print_arm_disassembler_options (stream); #endif @@ -543,6 +552,12 @@ disassemble_init_for_target (struct disassemble_info * info) switch (info->arch) { +#ifdef ARCH_aarch64 + case bfd_arch_aarch64: + info->symbol_is_valid = aarch64_symbol_is_valid; + info->disassembler_needs_relocs = TRUE; + break; +#endif #ifdef ARCH_arm case bfd_arch_arm: info->symbol_is_valid = arm_symbol_is_valid; |