Unverified Commit cc7018ea authored by Peter Eastman's avatar Peter Eastman Committed by GitHub
Browse files

JIT compilation on ARM processors (#3517)

* Upgraded to new version of asmjit

* JIT compilation for ARM

* Updated CMake script
parent 0644f054
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_ARM_A64GLOBALS_H_INCLUDED
#define ASMJIT_ARM_A64GLOBALS_H_INCLUDED
#include "../arm/armglobals.h"
//! \namespace asmjit::a64
//! \ingroup asmjit_a64
//!
//! AArch64 backend.
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
// a64 uses everything from arm namespace and adds into it.
using namespace arm;
//! \addtogroup asmjit_a64
//! \{
//! AArch64 instruction.
//!
//! \note Only used to hold ARM-specific enumerations and static functions.
struct Inst {
//! Instruction id.
enum Id : uint32_t {
// ${InstId:Begin}
kIdNone = 0, //!< Instruction ''.
kIdAdc, //!< Instruction 'adc'.
kIdAdcs, //!< Instruction 'adcs'.
kIdAdd, //!< Instruction 'add'.
kIdAddg, //!< Instruction 'addg'.
kIdAdds, //!< Instruction 'adds'.
kIdAdr, //!< Instruction 'adr'.
kIdAdrp, //!< Instruction 'adrp'.
kIdAnd, //!< Instruction 'and'.
kIdAnds, //!< Instruction 'ands'.
kIdAsr, //!< Instruction 'asr'.
kIdAsrv, //!< Instruction 'asrv'.
kIdAt, //!< Instruction 'at'.
kIdAutda, //!< Instruction 'autda'.
kIdAutdza, //!< Instruction 'autdza'.
kIdAutdb, //!< Instruction 'autdb'.
kIdAutdzb, //!< Instruction 'autdzb'.
kIdAutia, //!< Instruction 'autia'.
kIdAutia1716, //!< Instruction 'autia1716'.
kIdAutiasp, //!< Instruction 'autiasp'.
kIdAutiaz, //!< Instruction 'autiaz'.
kIdAutib, //!< Instruction 'autib'.
kIdAutib1716, //!< Instruction 'autib1716'.
kIdAutibsp, //!< Instruction 'autibsp'.
kIdAutibz, //!< Instruction 'autibz'.
kIdAutiza, //!< Instruction 'autiza'.
kIdAutizb, //!< Instruction 'autizb'.
kIdAxflag, //!< Instruction 'axflag'.
kIdB, //!< Instruction 'b'.
kIdBfc, //!< Instruction 'bfc'.
kIdBfi, //!< Instruction 'bfi'.
kIdBfm, //!< Instruction 'bfm'.
kIdBfxil, //!< Instruction 'bfxil'.
kIdBic, //!< Instruction 'bic'.
kIdBics, //!< Instruction 'bics'.
kIdBl, //!< Instruction 'bl'.
kIdBlr, //!< Instruction 'blr'.
kIdBr, //!< Instruction 'br'.
kIdBrk, //!< Instruction 'brk'.
kIdCas, //!< Instruction 'cas'.
kIdCasa, //!< Instruction 'casa'.
kIdCasab, //!< Instruction 'casab'.
kIdCasah, //!< Instruction 'casah'.
kIdCasal, //!< Instruction 'casal'.
kIdCasalb, //!< Instruction 'casalb'.
kIdCasalh, //!< Instruction 'casalh'.
kIdCasb, //!< Instruction 'casb'.
kIdCash, //!< Instruction 'cash'.
kIdCasl, //!< Instruction 'casl'.
kIdCaslb, //!< Instruction 'caslb'.
kIdCaslh, //!< Instruction 'caslh'.
kIdCasp, //!< Instruction 'casp'.
kIdCaspa, //!< Instruction 'caspa'.
kIdCaspal, //!< Instruction 'caspal'.
kIdCaspl, //!< Instruction 'caspl'.
kIdCbnz, //!< Instruction 'cbnz'.
kIdCbz, //!< Instruction 'cbz'.
kIdCcmn, //!< Instruction 'ccmn'.
kIdCcmp, //!< Instruction 'ccmp'.
kIdCfinv, //!< Instruction 'cfinv'.
kIdCinc, //!< Instruction 'cinc'.
kIdCinv, //!< Instruction 'cinv'.
kIdClrex, //!< Instruction 'clrex'.
kIdCls, //!< Instruction 'cls'.
kIdClz, //!< Instruction 'clz'.
kIdCmn, //!< Instruction 'cmn'.
kIdCmp, //!< Instruction 'cmp'.
kIdCmpp, //!< Instruction 'cmpp'.
kIdCneg, //!< Instruction 'cneg'.
kIdCrc32b, //!< Instruction 'crc32b'.
kIdCrc32cb, //!< Instruction 'crc32cb'.
kIdCrc32ch, //!< Instruction 'crc32ch'.
kIdCrc32cw, //!< Instruction 'crc32cw'.
kIdCrc32cx, //!< Instruction 'crc32cx'.
kIdCrc32h, //!< Instruction 'crc32h'.
kIdCrc32w, //!< Instruction 'crc32w'.
kIdCrc32x, //!< Instruction 'crc32x'.
kIdCsdb, //!< Instruction 'csdb'.
kIdCsel, //!< Instruction 'csel'.
kIdCset, //!< Instruction 'cset'.
kIdCsetm, //!< Instruction 'csetm'.
kIdCsinc, //!< Instruction 'csinc'.
kIdCsinv, //!< Instruction 'csinv'.
kIdCsneg, //!< Instruction 'csneg'.
kIdDc, //!< Instruction 'dc'.
kIdDcps1, //!< Instruction 'dcps1'.
kIdDcps2, //!< Instruction 'dcps2'.
kIdDcps3, //!< Instruction 'dcps3'.
kIdDgh, //!< Instruction 'dgh'.
kIdDmb, //!< Instruction 'dmb'.
kIdDrps, //!< Instruction 'drps'.
kIdDsb, //!< Instruction 'dsb'.
kIdEon, //!< Instruction 'eon'.
kIdEor, //!< Instruction 'eor'.
kIdEsb, //!< Instruction 'esb'.
kIdExtr, //!< Instruction 'extr'.
kIdEret, //!< Instruction 'eret'.
kIdGmi, //!< Instruction 'gmi'.
kIdHint, //!< Instruction 'hint'.
kIdHlt, //!< Instruction 'hlt'.
kIdHvc, //!< Instruction 'hvc'.
kIdIc, //!< Instruction 'ic'.
kIdIsb, //!< Instruction 'isb'.
kIdLdadd, //!< Instruction 'ldadd'.
kIdLdadda, //!< Instruction 'ldadda'.
kIdLdaddab, //!< Instruction 'ldaddab'.
kIdLdaddah, //!< Instruction 'ldaddah'.
kIdLdaddal, //!< Instruction 'ldaddal'.
kIdLdaddalb, //!< Instruction 'ldaddalb'.
kIdLdaddalh, //!< Instruction 'ldaddalh'.
kIdLdaddb, //!< Instruction 'ldaddb'.
kIdLdaddh, //!< Instruction 'ldaddh'.
kIdLdaddl, //!< Instruction 'ldaddl'.
kIdLdaddlb, //!< Instruction 'ldaddlb'.
kIdLdaddlh, //!< Instruction 'ldaddlh'.
kIdLdar, //!< Instruction 'ldar'.
kIdLdarb, //!< Instruction 'ldarb'.
kIdLdarh, //!< Instruction 'ldarh'.
kIdLdaxp, //!< Instruction 'ldaxp'.
kIdLdaxr, //!< Instruction 'ldaxr'.
kIdLdaxrb, //!< Instruction 'ldaxrb'.
kIdLdaxrh, //!< Instruction 'ldaxrh'.
kIdLdclr, //!< Instruction 'ldclr'.
kIdLdclra, //!< Instruction 'ldclra'.
kIdLdclrab, //!< Instruction 'ldclrab'.
kIdLdclrah, //!< Instruction 'ldclrah'.
kIdLdclral, //!< Instruction 'ldclral'.
kIdLdclralb, //!< Instruction 'ldclralb'.
kIdLdclralh, //!< Instruction 'ldclralh'.
kIdLdclrb, //!< Instruction 'ldclrb'.
kIdLdclrh, //!< Instruction 'ldclrh'.
kIdLdclrl, //!< Instruction 'ldclrl'.
kIdLdclrlb, //!< Instruction 'ldclrlb'.
kIdLdclrlh, //!< Instruction 'ldclrlh'.
kIdLdeor, //!< Instruction 'ldeor'.
kIdLdeora, //!< Instruction 'ldeora'.
kIdLdeorab, //!< Instruction 'ldeorab'.
kIdLdeorah, //!< Instruction 'ldeorah'.
kIdLdeoral, //!< Instruction 'ldeoral'.
kIdLdeoralb, //!< Instruction 'ldeoralb'.
kIdLdeoralh, //!< Instruction 'ldeoralh'.
kIdLdeorb, //!< Instruction 'ldeorb'.
kIdLdeorh, //!< Instruction 'ldeorh'.
kIdLdeorl, //!< Instruction 'ldeorl'.
kIdLdeorlb, //!< Instruction 'ldeorlb'.
kIdLdeorlh, //!< Instruction 'ldeorlh'.
kIdLdg, //!< Instruction 'ldg'.
kIdLdgm, //!< Instruction 'ldgm'.
kIdLdlar, //!< Instruction 'ldlar'.
kIdLdlarb, //!< Instruction 'ldlarb'.
kIdLdlarh, //!< Instruction 'ldlarh'.
kIdLdnp, //!< Instruction 'ldnp'.
kIdLdp, //!< Instruction 'ldp'.
kIdLdpsw, //!< Instruction 'ldpsw'.
kIdLdr, //!< Instruction 'ldr'.
kIdLdraa, //!< Instruction 'ldraa'.
kIdLdrab, //!< Instruction 'ldrab'.
kIdLdrb, //!< Instruction 'ldrb'.
kIdLdrh, //!< Instruction 'ldrh'.
kIdLdrsb, //!< Instruction 'ldrsb'.
kIdLdrsh, //!< Instruction 'ldrsh'.
kIdLdrsw, //!< Instruction 'ldrsw'.
kIdLdset, //!< Instruction 'ldset'.
kIdLdseta, //!< Instruction 'ldseta'.
kIdLdsetab, //!< Instruction 'ldsetab'.
kIdLdsetah, //!< Instruction 'ldsetah'.
kIdLdsetal, //!< Instruction 'ldsetal'.
kIdLdsetalb, //!< Instruction 'ldsetalb'.
kIdLdsetalh, //!< Instruction 'ldsetalh'.
kIdLdsetb, //!< Instruction 'ldsetb'.
kIdLdseth, //!< Instruction 'ldseth'.
kIdLdsetl, //!< Instruction 'ldsetl'.
kIdLdsetlb, //!< Instruction 'ldsetlb'.
kIdLdsetlh, //!< Instruction 'ldsetlh'.
kIdLdsmax, //!< Instruction 'ldsmax'.
kIdLdsmaxa, //!< Instruction 'ldsmaxa'.
kIdLdsmaxab, //!< Instruction 'ldsmaxab'.
kIdLdsmaxah, //!< Instruction 'ldsmaxah'.
kIdLdsmaxal, //!< Instruction 'ldsmaxal'.
kIdLdsmaxalb, //!< Instruction 'ldsmaxalb'.
kIdLdsmaxalh, //!< Instruction 'ldsmaxalh'.
kIdLdsmaxb, //!< Instruction 'ldsmaxb'.
kIdLdsmaxh, //!< Instruction 'ldsmaxh'.
kIdLdsmaxl, //!< Instruction 'ldsmaxl'.
kIdLdsmaxlb, //!< Instruction 'ldsmaxlb'.
kIdLdsmaxlh, //!< Instruction 'ldsmaxlh'.
kIdLdsmin, //!< Instruction 'ldsmin'.
kIdLdsmina, //!< Instruction 'ldsmina'.
kIdLdsminab, //!< Instruction 'ldsminab'.
kIdLdsminah, //!< Instruction 'ldsminah'.
kIdLdsminal, //!< Instruction 'ldsminal'.
kIdLdsminalb, //!< Instruction 'ldsminalb'.
kIdLdsminalh, //!< Instruction 'ldsminalh'.
kIdLdsminb, //!< Instruction 'ldsminb'.
kIdLdsminh, //!< Instruction 'ldsminh'.
kIdLdsminl, //!< Instruction 'ldsminl'.
kIdLdsminlb, //!< Instruction 'ldsminlb'.
kIdLdsminlh, //!< Instruction 'ldsminlh'.
kIdLdtr, //!< Instruction 'ldtr'.
kIdLdtrb, //!< Instruction 'ldtrb'.
kIdLdtrh, //!< Instruction 'ldtrh'.
kIdLdtrsb, //!< Instruction 'ldtrsb'.
kIdLdtrsh, //!< Instruction 'ldtrsh'.
kIdLdtrsw, //!< Instruction 'ldtrsw'.
kIdLdumax, //!< Instruction 'ldumax'.
kIdLdumaxa, //!< Instruction 'ldumaxa'.
kIdLdumaxab, //!< Instruction 'ldumaxab'.
kIdLdumaxah, //!< Instruction 'ldumaxah'.
kIdLdumaxal, //!< Instruction 'ldumaxal'.
kIdLdumaxalb, //!< Instruction 'ldumaxalb'.
kIdLdumaxalh, //!< Instruction 'ldumaxalh'.
kIdLdumaxb, //!< Instruction 'ldumaxb'.
kIdLdumaxh, //!< Instruction 'ldumaxh'.
kIdLdumaxl, //!< Instruction 'ldumaxl'.
kIdLdumaxlb, //!< Instruction 'ldumaxlb'.
kIdLdumaxlh, //!< Instruction 'ldumaxlh'.
kIdLdumin, //!< Instruction 'ldumin'.
kIdLdumina, //!< Instruction 'ldumina'.
kIdLduminab, //!< Instruction 'lduminab'.
kIdLduminah, //!< Instruction 'lduminah'.
kIdLduminal, //!< Instruction 'lduminal'.
kIdLduminalb, //!< Instruction 'lduminalb'.
kIdLduminalh, //!< Instruction 'lduminalh'.
kIdLduminb, //!< Instruction 'lduminb'.
kIdLduminh, //!< Instruction 'lduminh'.
kIdLduminl, //!< Instruction 'lduminl'.
kIdLduminlb, //!< Instruction 'lduminlb'.
kIdLduminlh, //!< Instruction 'lduminlh'.
kIdLdur, //!< Instruction 'ldur'.
kIdLdurb, //!< Instruction 'ldurb'.
kIdLdurh, //!< Instruction 'ldurh'.
kIdLdursb, //!< Instruction 'ldursb'.
kIdLdursh, //!< Instruction 'ldursh'.
kIdLdursw, //!< Instruction 'ldursw'.
kIdLdxp, //!< Instruction 'ldxp'.
kIdLdxr, //!< Instruction 'ldxr'.
kIdLdxrb, //!< Instruction 'ldxrb'.
kIdLdxrh, //!< Instruction 'ldxrh'.
kIdLsl, //!< Instruction 'lsl'.
kIdLslv, //!< Instruction 'lslv'.
kIdLsr, //!< Instruction 'lsr'.
kIdLsrv, //!< Instruction 'lsrv'.
kIdMadd, //!< Instruction 'madd'.
kIdMneg, //!< Instruction 'mneg'.
kIdMov, //!< Instruction 'mov'.
kIdMovk, //!< Instruction 'movk'.
kIdMovn, //!< Instruction 'movn'.
kIdMovz, //!< Instruction 'movz'.
kIdMrs, //!< Instruction 'mrs'.
kIdMsr, //!< Instruction 'msr'.
kIdMsub, //!< Instruction 'msub'.
kIdMul, //!< Instruction 'mul'.
kIdMvn, //!< Instruction 'mvn'.
kIdNeg, //!< Instruction 'neg'.
kIdNegs, //!< Instruction 'negs'.
kIdNgc, //!< Instruction 'ngc'.
kIdNgcs, //!< Instruction 'ngcs'.
kIdNop, //!< Instruction 'nop'.
kIdOrn, //!< Instruction 'orn'.
kIdOrr, //!< Instruction 'orr'.
kIdPacda, //!< Instruction 'pacda'.
kIdPacdb, //!< Instruction 'pacdb'.
kIdPacdza, //!< Instruction 'pacdza'.
kIdPacdzb, //!< Instruction 'pacdzb'.
kIdPacga, //!< Instruction 'pacga'.
kIdPssbb, //!< Instruction 'pssbb'.
kIdRbit, //!< Instruction 'rbit'.
kIdRet, //!< Instruction 'ret'.
kIdRev, //!< Instruction 'rev'.
kIdRev16, //!< Instruction 'rev16'.
kIdRev32, //!< Instruction 'rev32'.
kIdRev64, //!< Instruction 'rev64'.
kIdRor, //!< Instruction 'ror'.
kIdRorv, //!< Instruction 'rorv'.
kIdSbc, //!< Instruction 'sbc'.
kIdSbcs, //!< Instruction 'sbcs'.
kIdSbfiz, //!< Instruction 'sbfiz'.
kIdSbfm, //!< Instruction 'sbfm'.
kIdSbfx, //!< Instruction 'sbfx'.
kIdSdiv, //!< Instruction 'sdiv'.
kIdSetf8, //!< Instruction 'setf8'.
kIdSetf16, //!< Instruction 'setf16'.
kIdSev, //!< Instruction 'sev'.
kIdSevl, //!< Instruction 'sevl'.
kIdSmaddl, //!< Instruction 'smaddl'.
kIdSmc, //!< Instruction 'smc'.
kIdSmnegl, //!< Instruction 'smnegl'.
kIdSmsubl, //!< Instruction 'smsubl'.
kIdSmulh, //!< Instruction 'smulh'.
kIdSmull, //!< Instruction 'smull'.
kIdSsbb, //!< Instruction 'ssbb'.
kIdSt2g, //!< Instruction 'st2g'.
kIdStadd, //!< Instruction 'stadd'.
kIdStaddl, //!< Instruction 'staddl'.
kIdStaddb, //!< Instruction 'staddb'.
kIdStaddlb, //!< Instruction 'staddlb'.
kIdStaddh, //!< Instruction 'staddh'.
kIdStaddlh, //!< Instruction 'staddlh'.
kIdStclr, //!< Instruction 'stclr'.
kIdStclrl, //!< Instruction 'stclrl'.
kIdStclrb, //!< Instruction 'stclrb'.
kIdStclrlb, //!< Instruction 'stclrlb'.
kIdStclrh, //!< Instruction 'stclrh'.
kIdStclrlh, //!< Instruction 'stclrlh'.
kIdSteor, //!< Instruction 'steor'.
kIdSteorl, //!< Instruction 'steorl'.
kIdSteorb, //!< Instruction 'steorb'.
kIdSteorlb, //!< Instruction 'steorlb'.
kIdSteorh, //!< Instruction 'steorh'.
kIdSteorlh, //!< Instruction 'steorlh'.
kIdStg, //!< Instruction 'stg'.
kIdStgm, //!< Instruction 'stgm'.
kIdStgp, //!< Instruction 'stgp'.
kIdStllr, //!< Instruction 'stllr'.
kIdStllrb, //!< Instruction 'stllrb'.
kIdStllrh, //!< Instruction 'stllrh'.
kIdStlr, //!< Instruction 'stlr'.
kIdStlrb, //!< Instruction 'stlrb'.
kIdStlrh, //!< Instruction 'stlrh'.
kIdStlxp, //!< Instruction 'stlxp'.
kIdStlxr, //!< Instruction 'stlxr'.
kIdStlxrb, //!< Instruction 'stlxrb'.
kIdStlxrh, //!< Instruction 'stlxrh'.
kIdStnp, //!< Instruction 'stnp'.
kIdStp, //!< Instruction 'stp'.
kIdStr, //!< Instruction 'str'.
kIdStrb, //!< Instruction 'strb'.
kIdStrh, //!< Instruction 'strh'.
kIdStset, //!< Instruction 'stset'.
kIdStsetl, //!< Instruction 'stsetl'.
kIdStsetb, //!< Instruction 'stsetb'.
kIdStsetlb, //!< Instruction 'stsetlb'.
kIdStseth, //!< Instruction 'stseth'.
kIdStsetlh, //!< Instruction 'stsetlh'.
kIdStsmax, //!< Instruction 'stsmax'.
kIdStsmaxl, //!< Instruction 'stsmaxl'.
kIdStsmaxb, //!< Instruction 'stsmaxb'.
kIdStsmaxlb, //!< Instruction 'stsmaxlb'.
kIdStsmaxh, //!< Instruction 'stsmaxh'.
kIdStsmaxlh, //!< Instruction 'stsmaxlh'.
kIdStsmin, //!< Instruction 'stsmin'.
kIdStsminl, //!< Instruction 'stsminl'.
kIdStsminb, //!< Instruction 'stsminb'.
kIdStsminlb, //!< Instruction 'stsminlb'.
kIdStsminh, //!< Instruction 'stsminh'.
kIdStsminlh, //!< Instruction 'stsminlh'.
kIdSttr, //!< Instruction 'sttr'.
kIdSttrb, //!< Instruction 'sttrb'.
kIdSttrh, //!< Instruction 'sttrh'.
kIdStumax, //!< Instruction 'stumax'.
kIdStumaxl, //!< Instruction 'stumaxl'.
kIdStumaxb, //!< Instruction 'stumaxb'.
kIdStumaxlb, //!< Instruction 'stumaxlb'.
kIdStumaxh, //!< Instruction 'stumaxh'.
kIdStumaxlh, //!< Instruction 'stumaxlh'.
kIdStumin, //!< Instruction 'stumin'.
kIdStuminl, //!< Instruction 'stuminl'.
kIdStuminb, //!< Instruction 'stuminb'.
kIdStuminlb, //!< Instruction 'stuminlb'.
kIdStuminh, //!< Instruction 'stuminh'.
kIdStuminlh, //!< Instruction 'stuminlh'.
kIdStur, //!< Instruction 'stur'.
kIdSturb, //!< Instruction 'sturb'.
kIdSturh, //!< Instruction 'sturh'.
kIdStxp, //!< Instruction 'stxp'.
kIdStxr, //!< Instruction 'stxr'.
kIdStxrb, //!< Instruction 'stxrb'.
kIdStxrh, //!< Instruction 'stxrh'.
kIdStz2g, //!< Instruction 'stz2g'.
kIdStzg, //!< Instruction 'stzg'.
kIdStzgm, //!< Instruction 'stzgm'.
kIdSub, //!< Instruction 'sub'.
kIdSubg, //!< Instruction 'subg'.
kIdSubp, //!< Instruction 'subp'.
kIdSubps, //!< Instruction 'subps'.
kIdSubs, //!< Instruction 'subs'.
kIdSvc, //!< Instruction 'svc'.
kIdSwp, //!< Instruction 'swp'.
kIdSwpa, //!< Instruction 'swpa'.
kIdSwpab, //!< Instruction 'swpab'.
kIdSwpah, //!< Instruction 'swpah'.
kIdSwpal, //!< Instruction 'swpal'.
kIdSwpalb, //!< Instruction 'swpalb'.
kIdSwpalh, //!< Instruction 'swpalh'.
kIdSwpb, //!< Instruction 'swpb'.
kIdSwph, //!< Instruction 'swph'.
kIdSwpl, //!< Instruction 'swpl'.
kIdSwplb, //!< Instruction 'swplb'.
kIdSwplh, //!< Instruction 'swplh'.
kIdSxtb, //!< Instruction 'sxtb'.
kIdSxth, //!< Instruction 'sxth'.
kIdSxtw, //!< Instruction 'sxtw'.
kIdSys, //!< Instruction 'sys'.
kIdTlbi, //!< Instruction 'tlbi'.
kIdTst, //!< Instruction 'tst'.
kIdTbnz, //!< Instruction 'tbnz'.
kIdTbz, //!< Instruction 'tbz'.
kIdUbfiz, //!< Instruction 'ubfiz'.
kIdUbfm, //!< Instruction 'ubfm'.
kIdUbfx, //!< Instruction 'ubfx'.
kIdUdf, //!< Instruction 'udf'.
kIdUdiv, //!< Instruction 'udiv'.
kIdUmaddl, //!< Instruction 'umaddl'.
kIdUmnegl, //!< Instruction 'umnegl'.
kIdUmull, //!< Instruction 'umull'.
kIdUmulh, //!< Instruction 'umulh'.
kIdUmsubl, //!< Instruction 'umsubl'.
kIdUxtb, //!< Instruction 'uxtb'.
kIdUxth, //!< Instruction 'uxth'.
kIdWfe, //!< Instruction 'wfe'.
kIdWfi, //!< Instruction 'wfi'.
kIdXaflag, //!< Instruction 'xaflag'.
kIdXpacd, //!< Instruction 'xpacd'.
kIdXpaci, //!< Instruction 'xpaci'.
kIdXpaclri, //!< Instruction 'xpaclri'.
kIdYield, //!< Instruction 'yield'.
kIdAbs_v, //!< Instruction 'abs' {ASIMD}.
kIdAdd_v, //!< Instruction 'add' {ASIMD}.
kIdAddhn_v, //!< Instruction 'addhn' {ASIMD}.
kIdAddhn2_v, //!< Instruction 'addhn2' {ASIMD}.
kIdAddp_v, //!< Instruction 'addp' {ASIMD}.
kIdAddv_v, //!< Instruction 'addv' {ASIMD}.
kIdAesd_v, //!< Instruction 'aesd' {ASIMD}.
kIdAese_v, //!< Instruction 'aese' {ASIMD}.
kIdAesimc_v, //!< Instruction 'aesimc' {ASIMD}.
kIdAesmc_v, //!< Instruction 'aesmc' {ASIMD}.
kIdAnd_v, //!< Instruction 'and' {ASIMD}.
kIdBcax_v, //!< Instruction 'bcax' {ASIMD}.
kIdBfcvt_v, //!< Instruction 'bfcvt' {ASIMD}.
kIdBfcvtn_v, //!< Instruction 'bfcvtn' {ASIMD}.
kIdBfcvtn2_v, //!< Instruction 'bfcvtn2' {ASIMD}.
kIdBfdot_v, //!< Instruction 'bfdot' {ASIMD}.
kIdBfmlalb_v, //!< Instruction 'bfmlalb' {ASIMD}.
kIdBfmlalt_v, //!< Instruction 'bfmlalt' {ASIMD}.
kIdBfmmla_v, //!< Instruction 'bfmmla' {ASIMD}.
kIdBic_v, //!< Instruction 'bic' {ASIMD}.
kIdBif_v, //!< Instruction 'bif' {ASIMD}.
kIdBit_v, //!< Instruction 'bit' {ASIMD}.
kIdBsl_v, //!< Instruction 'bsl' {ASIMD}.
kIdCls_v, //!< Instruction 'cls' {ASIMD}.
kIdClz_v, //!< Instruction 'clz' {ASIMD}.
kIdCmeq_v, //!< Instruction 'cmeq' {ASIMD}.
kIdCmge_v, //!< Instruction 'cmge' {ASIMD}.
kIdCmgt_v, //!< Instruction 'cmgt' {ASIMD}.
kIdCmhi_v, //!< Instruction 'cmhi' {ASIMD}.
kIdCmhs_v, //!< Instruction 'cmhs' {ASIMD}.
kIdCmle_v, //!< Instruction 'cmle' {ASIMD}.
kIdCmlt_v, //!< Instruction 'cmlt' {ASIMD}.
kIdCmtst_v, //!< Instruction 'cmtst' {ASIMD}.
kIdCnt_v, //!< Instruction 'cnt' {ASIMD}.
kIdDup_v, //!< Instruction 'dup' {ASIMD}.
kIdEor_v, //!< Instruction 'eor' {ASIMD}.
kIdEor3_v, //!< Instruction 'eor3' {ASIMD}.
kIdExt_v, //!< Instruction 'ext' {ASIMD}.
kIdFabd_v, //!< Instruction 'fabd' {ASIMD}.
kIdFabs_v, //!< Instruction 'fabs' {ASIMD}.
kIdFacge_v, //!< Instruction 'facge' {ASIMD}.
kIdFacgt_v, //!< Instruction 'facgt' {ASIMD}.
kIdFadd_v, //!< Instruction 'fadd' {ASIMD}.
kIdFaddp_v, //!< Instruction 'faddp' {ASIMD}.
kIdFcadd_v, //!< Instruction 'fcadd' {ASIMD}.
kIdFccmp_v, //!< Instruction 'fccmp' {ASIMD}.
kIdFccmpe_v, //!< Instruction 'fccmpe' {ASIMD}.
kIdFcmeq_v, //!< Instruction 'fcmeq' {ASIMD}.
kIdFcmge_v, //!< Instruction 'fcmge' {ASIMD}.
kIdFcmgt_v, //!< Instruction 'fcmgt' {ASIMD}.
kIdFcmla_v, //!< Instruction 'fcmla' {ASIMD}.
kIdFcmle_v, //!< Instruction 'fcmle' {ASIMD}.
kIdFcmlt_v, //!< Instruction 'fcmlt' {ASIMD}.
kIdFcmp_v, //!< Instruction 'fcmp' {ASIMD}.
kIdFcmpe_v, //!< Instruction 'fcmpe' {ASIMD}.
kIdFcsel_v, //!< Instruction 'fcsel' {ASIMD}.
kIdFcvt_v, //!< Instruction 'fcvt' {ASIMD}.
kIdFcvtas_v, //!< Instruction 'fcvtas' {ASIMD}.
kIdFcvtau_v, //!< Instruction 'fcvtau' {ASIMD}.
kIdFcvtl_v, //!< Instruction 'fcvtl' {ASIMD}.
kIdFcvtl2_v, //!< Instruction 'fcvtl2' {ASIMD}.
kIdFcvtms_v, //!< Instruction 'fcvtms' {ASIMD}.
kIdFcvtmu_v, //!< Instruction 'fcvtmu' {ASIMD}.
kIdFcvtn_v, //!< Instruction 'fcvtn' {ASIMD}.
kIdFcvtn2_v, //!< Instruction 'fcvtn2' {ASIMD}.
kIdFcvtns_v, //!< Instruction 'fcvtns' {ASIMD}.
kIdFcvtnu_v, //!< Instruction 'fcvtnu' {ASIMD}.
kIdFcvtps_v, //!< Instruction 'fcvtps' {ASIMD}.
kIdFcvtpu_v, //!< Instruction 'fcvtpu' {ASIMD}.
kIdFcvtxn_v, //!< Instruction 'fcvtxn' {ASIMD}.
kIdFcvtxn2_v, //!< Instruction 'fcvtxn2' {ASIMD}.
kIdFcvtzs_v, //!< Instruction 'fcvtzs' {ASIMD}.
kIdFcvtzu_v, //!< Instruction 'fcvtzu' {ASIMD}.
kIdFdiv_v, //!< Instruction 'fdiv' {ASIMD}.
kIdFjcvtzs_v, //!< Instruction 'fjcvtzs' {ASIMD}.
kIdFmadd_v, //!< Instruction 'fmadd' {ASIMD}.
kIdFmax_v, //!< Instruction 'fmax' {ASIMD}.
kIdFmaxnm_v, //!< Instruction 'fmaxnm' {ASIMD}.
kIdFmaxnmp_v, //!< Instruction 'fmaxnmp' {ASIMD}.
kIdFmaxnmv_v, //!< Instruction 'fmaxnmv' {ASIMD}.
kIdFmaxp_v, //!< Instruction 'fmaxp' {ASIMD}.
kIdFmaxv_v, //!< Instruction 'fmaxv' {ASIMD}.
kIdFmin_v, //!< Instruction 'fmin' {ASIMD}.
kIdFminnm_v, //!< Instruction 'fminnm' {ASIMD}.
kIdFminnmp_v, //!< Instruction 'fminnmp' {ASIMD}.
kIdFminnmv_v, //!< Instruction 'fminnmv' {ASIMD}.
kIdFminp_v, //!< Instruction 'fminp' {ASIMD}.
kIdFminv_v, //!< Instruction 'fminv' {ASIMD}.
kIdFmla_v, //!< Instruction 'fmla' {ASIMD}.
kIdFmlal_v, //!< Instruction 'fmlal' {ASIMD}.
kIdFmlal2_v, //!< Instruction 'fmlal2' {ASIMD}.
kIdFmls_v, //!< Instruction 'fmls' {ASIMD}.
kIdFmlsl_v, //!< Instruction 'fmlsl' {ASIMD}.
kIdFmlsl2_v, //!< Instruction 'fmlsl2' {ASIMD}.
kIdFmov_v, //!< Instruction 'fmov' {ASIMD}.
kIdFmsub_v, //!< Instruction 'fmsub' {ASIMD}.
kIdFmul_v, //!< Instruction 'fmul' {ASIMD}.
kIdFmulx_v, //!< Instruction 'fmulx' {ASIMD}.
kIdFneg_v, //!< Instruction 'fneg' {ASIMD}.
kIdFnmadd_v, //!< Instruction 'fnmadd' {ASIMD}.
kIdFnmsub_v, //!< Instruction 'fnmsub' {ASIMD}.
kIdFnmul_v, //!< Instruction 'fnmul' {ASIMD}.
kIdFrecpe_v, //!< Instruction 'frecpe' {ASIMD}.
kIdFrecps_v, //!< Instruction 'frecps' {ASIMD}.
kIdFrecpx_v, //!< Instruction 'frecpx' {ASIMD}.
kIdFrint32x_v, //!< Instruction 'frint32x' {ASIMD}.
kIdFrint32z_v, //!< Instruction 'frint32z' {ASIMD}.
kIdFrint64x_v, //!< Instruction 'frint64x' {ASIMD}.
kIdFrint64z_v, //!< Instruction 'frint64z' {ASIMD}.
kIdFrinta_v, //!< Instruction 'frinta' {ASIMD}.
kIdFrinti_v, //!< Instruction 'frinti' {ASIMD}.
kIdFrintm_v, //!< Instruction 'frintm' {ASIMD}.
kIdFrintn_v, //!< Instruction 'frintn' {ASIMD}.
kIdFrintp_v, //!< Instruction 'frintp' {ASIMD}.
kIdFrintx_v, //!< Instruction 'frintx' {ASIMD}.
kIdFrintz_v, //!< Instruction 'frintz' {ASIMD}.
kIdFrsqrte_v, //!< Instruction 'frsqrte' {ASIMD}.
kIdFrsqrts_v, //!< Instruction 'frsqrts' {ASIMD}.
kIdFsqrt_v, //!< Instruction 'fsqrt' {ASIMD}.
kIdFsub_v, //!< Instruction 'fsub' {ASIMD}.
kIdIns_v, //!< Instruction 'ins' {ASIMD}.
kIdLd1_v, //!< Instruction 'ld1' {ASIMD}.
kIdLd1r_v, //!< Instruction 'ld1r' {ASIMD}.
kIdLd2_v, //!< Instruction 'ld2' {ASIMD}.
kIdLd2r_v, //!< Instruction 'ld2r' {ASIMD}.
kIdLd3_v, //!< Instruction 'ld3' {ASIMD}.
kIdLd3r_v, //!< Instruction 'ld3r' {ASIMD}.
kIdLd4_v, //!< Instruction 'ld4' {ASIMD}.
kIdLd4r_v, //!< Instruction 'ld4r' {ASIMD}.
kIdLdnp_v, //!< Instruction 'ldnp' {ASIMD}.
kIdLdp_v, //!< Instruction 'ldp' {ASIMD}.
kIdLdr_v, //!< Instruction 'ldr' {ASIMD}.
kIdLdur_v, //!< Instruction 'ldur' {ASIMD}.
kIdMla_v, //!< Instruction 'mla' {ASIMD}.
kIdMls_v, //!< Instruction 'mls' {ASIMD}.
kIdMov_v, //!< Instruction 'mov' {ASIMD}.
kIdMovi_v, //!< Instruction 'movi' {ASIMD}.
kIdMul_v, //!< Instruction 'mul' {ASIMD}.
kIdMvn_v, //!< Instruction 'mvn' {ASIMD}.
kIdMvni_v, //!< Instruction 'mvni' {ASIMD}.
kIdNeg_v, //!< Instruction 'neg' {ASIMD}.
kIdNot_v, //!< Instruction 'not' {ASIMD}.
kIdOrn_v, //!< Instruction 'orn' {ASIMD}.
kIdOrr_v, //!< Instruction 'orr' {ASIMD}.
kIdPmul_v, //!< Instruction 'pmul' {ASIMD}.
kIdPmull_v, //!< Instruction 'pmull' {ASIMD}.
kIdPmull2_v, //!< Instruction 'pmull2' {ASIMD}.
kIdRaddhn_v, //!< Instruction 'raddhn' {ASIMD}.
kIdRaddhn2_v, //!< Instruction 'raddhn2' {ASIMD}.
kIdRax1_v, //!< Instruction 'rax1' {ASIMD}.
kIdRbit_v, //!< Instruction 'rbit' {ASIMD}.
kIdRev16_v, //!< Instruction 'rev16' {ASIMD}.
kIdRev32_v, //!< Instruction 'rev32' {ASIMD}.
kIdRev64_v, //!< Instruction 'rev64' {ASIMD}.
kIdRshrn_v, //!< Instruction 'rshrn' {ASIMD}.
kIdRshrn2_v, //!< Instruction 'rshrn2' {ASIMD}.
kIdRsubhn_v, //!< Instruction 'rsubhn' {ASIMD}.
kIdRsubhn2_v, //!< Instruction 'rsubhn2' {ASIMD}.
kIdSaba_v, //!< Instruction 'saba' {ASIMD}.
kIdSabal_v, //!< Instruction 'sabal' {ASIMD}.
kIdSabal2_v, //!< Instruction 'sabal2' {ASIMD}.
kIdSabd_v, //!< Instruction 'sabd' {ASIMD}.
kIdSabdl_v, //!< Instruction 'sabdl' {ASIMD}.
kIdSabdl2_v, //!< Instruction 'sabdl2' {ASIMD}.
kIdSadalp_v, //!< Instruction 'sadalp' {ASIMD}.
kIdSaddl_v, //!< Instruction 'saddl' {ASIMD}.
kIdSaddl2_v, //!< Instruction 'saddl2' {ASIMD}.
kIdSaddlp_v, //!< Instruction 'saddlp' {ASIMD}.
kIdSaddlv_v, //!< Instruction 'saddlv' {ASIMD}.
kIdSaddw_v, //!< Instruction 'saddw' {ASIMD}.
kIdSaddw2_v, //!< Instruction 'saddw2' {ASIMD}.
kIdScvtf_v, //!< Instruction 'scvtf' {ASIMD}.
kIdSdot_v, //!< Instruction 'sdot' {ASIMD}.
kIdSha1c_v, //!< Instruction 'sha1c' {ASIMD}.
kIdSha1h_v, //!< Instruction 'sha1h' {ASIMD}.
kIdSha1m_v, //!< Instruction 'sha1m' {ASIMD}.
kIdSha1p_v, //!< Instruction 'sha1p' {ASIMD}.
kIdSha1su0_v, //!< Instruction 'sha1su0' {ASIMD}.
kIdSha1su1_v, //!< Instruction 'sha1su1' {ASIMD}.
kIdSha256h_v, //!< Instruction 'sha256h' {ASIMD}.
kIdSha256h2_v, //!< Instruction 'sha256h2' {ASIMD}.
kIdSha256su0_v, //!< Instruction 'sha256su0' {ASIMD}.
kIdSha256su1_v, //!< Instruction 'sha256su1' {ASIMD}.
kIdSha512h_v, //!< Instruction 'sha512h' {ASIMD}.
kIdSha512h2_v, //!< Instruction 'sha512h2' {ASIMD}.
kIdSha512su0_v, //!< Instruction 'sha512su0' {ASIMD}.
kIdSha512su1_v, //!< Instruction 'sha512su1' {ASIMD}.
kIdShadd_v, //!< Instruction 'shadd' {ASIMD}.
kIdShl_v, //!< Instruction 'shl' {ASIMD}.
kIdShll_v, //!< Instruction 'shll' {ASIMD}.
kIdShll2_v, //!< Instruction 'shll2' {ASIMD}.
kIdShrn_v, //!< Instruction 'shrn' {ASIMD}.
kIdShrn2_v, //!< Instruction 'shrn2' {ASIMD}.
kIdShsub_v, //!< Instruction 'shsub' {ASIMD}.
kIdSli_v, //!< Instruction 'sli' {ASIMD}.
kIdSm3partw1_v, //!< Instruction 'sm3partw1' {ASIMD}.
kIdSm3partw2_v, //!< Instruction 'sm3partw2' {ASIMD}.
kIdSm3ss1_v, //!< Instruction 'sm3ss1' {ASIMD}.
kIdSm3tt1a_v, //!< Instruction 'sm3tt1a' {ASIMD}.
kIdSm3tt1b_v, //!< Instruction 'sm3tt1b' {ASIMD}.
kIdSm3tt2a_v, //!< Instruction 'sm3tt2a' {ASIMD}.
kIdSm3tt2b_v, //!< Instruction 'sm3tt2b' {ASIMD}.
kIdSm4e_v, //!< Instruction 'sm4e' {ASIMD}.
kIdSm4ekey_v, //!< Instruction 'sm4ekey' {ASIMD}.
kIdSmax_v, //!< Instruction 'smax' {ASIMD}.
kIdSmaxp_v, //!< Instruction 'smaxp' {ASIMD}.
kIdSmaxv_v, //!< Instruction 'smaxv' {ASIMD}.
kIdSmin_v, //!< Instruction 'smin' {ASIMD}.
kIdSminp_v, //!< Instruction 'sminp' {ASIMD}.
kIdSminv_v, //!< Instruction 'sminv' {ASIMD}.
kIdSmlal_v, //!< Instruction 'smlal' {ASIMD}.
kIdSmlal2_v, //!< Instruction 'smlal2' {ASIMD}.
kIdSmlsl_v, //!< Instruction 'smlsl' {ASIMD}.
kIdSmlsl2_v, //!< Instruction 'smlsl2' {ASIMD}.
kIdSmmla_v, //!< Instruction 'smmla' {ASIMD}.
kIdSmov_v, //!< Instruction 'smov' {ASIMD}.
kIdSmull_v, //!< Instruction 'smull' {ASIMD}.
kIdSmull2_v, //!< Instruction 'smull2' {ASIMD}.
kIdSqabs_v, //!< Instruction 'sqabs' {ASIMD}.
kIdSqadd_v, //!< Instruction 'sqadd' {ASIMD}.
kIdSqdmlal_v, //!< Instruction 'sqdmlal' {ASIMD}.
kIdSqdmlal2_v, //!< Instruction 'sqdmlal2' {ASIMD}.
kIdSqdmlsl_v, //!< Instruction 'sqdmlsl' {ASIMD}.
kIdSqdmlsl2_v, //!< Instruction 'sqdmlsl2' {ASIMD}.
kIdSqdmulh_v, //!< Instruction 'sqdmulh' {ASIMD}.
kIdSqdmull_v, //!< Instruction 'sqdmull' {ASIMD}.
kIdSqdmull2_v, //!< Instruction 'sqdmull2' {ASIMD}.
kIdSqneg_v, //!< Instruction 'sqneg' {ASIMD}.
kIdSqrdmlah_v, //!< Instruction 'sqrdmlah' {ASIMD}.
kIdSqrdmlsh_v, //!< Instruction 'sqrdmlsh' {ASIMD}.
kIdSqrdmulh_v, //!< Instruction 'sqrdmulh' {ASIMD}.
kIdSqrshl_v, //!< Instruction 'sqrshl' {ASIMD}.
kIdSqrshrn_v, //!< Instruction 'sqrshrn' {ASIMD}.
kIdSqrshrn2_v, //!< Instruction 'sqrshrn2' {ASIMD}.
kIdSqrshrun_v, //!< Instruction 'sqrshrun' {ASIMD}.
kIdSqrshrun2_v, //!< Instruction 'sqrshrun2' {ASIMD}.
kIdSqshl_v, //!< Instruction 'sqshl' {ASIMD}.
kIdSqshlu_v, //!< Instruction 'sqshlu' {ASIMD}.
kIdSqshrn_v, //!< Instruction 'sqshrn' {ASIMD}.
kIdSqshrn2_v, //!< Instruction 'sqshrn2' {ASIMD}.
kIdSqshrun_v, //!< Instruction 'sqshrun' {ASIMD}.
kIdSqshrun2_v, //!< Instruction 'sqshrun2' {ASIMD}.
kIdSqsub_v, //!< Instruction 'sqsub' {ASIMD}.
kIdSqxtn_v, //!< Instruction 'sqxtn' {ASIMD}.
kIdSqxtn2_v, //!< Instruction 'sqxtn2' {ASIMD}.
kIdSqxtun_v, //!< Instruction 'sqxtun' {ASIMD}.
kIdSqxtun2_v, //!< Instruction 'sqxtun2' {ASIMD}.
kIdSrhadd_v, //!< Instruction 'srhadd' {ASIMD}.
kIdSri_v, //!< Instruction 'sri' {ASIMD}.
kIdSrshl_v, //!< Instruction 'srshl' {ASIMD}.
kIdSrshr_v, //!< Instruction 'srshr' {ASIMD}.
kIdSrsra_v, //!< Instruction 'srsra' {ASIMD}.
kIdSshl_v, //!< Instruction 'sshl' {ASIMD}.
kIdSshll_v, //!< Instruction 'sshll' {ASIMD}.
kIdSshll2_v, //!< Instruction 'sshll2' {ASIMD}.
kIdSshr_v, //!< Instruction 'sshr' {ASIMD}.
kIdSsra_v, //!< Instruction 'ssra' {ASIMD}.
kIdSsubl_v, //!< Instruction 'ssubl' {ASIMD}.
kIdSsubl2_v, //!< Instruction 'ssubl2' {ASIMD}.
kIdSsubw_v, //!< Instruction 'ssubw' {ASIMD}.
kIdSsubw2_v, //!< Instruction 'ssubw2' {ASIMD}.
kIdSt1_v, //!< Instruction 'st1' {ASIMD}.
kIdSt2_v, //!< Instruction 'st2' {ASIMD}.
kIdSt3_v, //!< Instruction 'st3' {ASIMD}.
kIdSt4_v, //!< Instruction 'st4' {ASIMD}.
kIdStnp_v, //!< Instruction 'stnp' {ASIMD}.
kIdStp_v, //!< Instruction 'stp' {ASIMD}.
kIdStr_v, //!< Instruction 'str' {ASIMD}.
kIdStur_v, //!< Instruction 'stur' {ASIMD}.
kIdSub_v, //!< Instruction 'sub' {ASIMD}.
kIdSubhn_v, //!< Instruction 'subhn' {ASIMD}.
kIdSubhn2_v, //!< Instruction 'subhn2' {ASIMD}.
kIdSudot_v, //!< Instruction 'sudot' {ASIMD}.
kIdSuqadd_v, //!< Instruction 'suqadd' {ASIMD}.
kIdSxtl_v, //!< Instruction 'sxtl' {ASIMD}.
kIdSxtl2_v, //!< Instruction 'sxtl2' {ASIMD}.
kIdTbl_v, //!< Instruction 'tbl' {ASIMD}.
kIdTbx_v, //!< Instruction 'tbx' {ASIMD}.
kIdTrn1_v, //!< Instruction 'trn1' {ASIMD}.
kIdTrn2_v, //!< Instruction 'trn2' {ASIMD}.
kIdUaba_v, //!< Instruction 'uaba' {ASIMD}.
kIdUabal_v, //!< Instruction 'uabal' {ASIMD}.
kIdUabal2_v, //!< Instruction 'uabal2' {ASIMD}.
kIdUabd_v, //!< Instruction 'uabd' {ASIMD}.
kIdUabdl_v, //!< Instruction 'uabdl' {ASIMD}.
kIdUabdl2_v, //!< Instruction 'uabdl2' {ASIMD}.
kIdUadalp_v, //!< Instruction 'uadalp' {ASIMD}.
kIdUaddl_v, //!< Instruction 'uaddl' {ASIMD}.
kIdUaddl2_v, //!< Instruction 'uaddl2' {ASIMD}.
kIdUaddlp_v, //!< Instruction 'uaddlp' {ASIMD}.
kIdUaddlv_v, //!< Instruction 'uaddlv' {ASIMD}.
kIdUaddw_v, //!< Instruction 'uaddw' {ASIMD}.
kIdUaddw2_v, //!< Instruction 'uaddw2' {ASIMD}.
kIdUcvtf_v, //!< Instruction 'ucvtf' {ASIMD}.
kIdUdot_v, //!< Instruction 'udot' {ASIMD}.
kIdUhadd_v, //!< Instruction 'uhadd' {ASIMD}.
kIdUhsub_v, //!< Instruction 'uhsub' {ASIMD}.
kIdUmax_v, //!< Instruction 'umax' {ASIMD}.
kIdUmaxp_v, //!< Instruction 'umaxp' {ASIMD}.
kIdUmaxv_v, //!< Instruction 'umaxv' {ASIMD}.
kIdUmin_v, //!< Instruction 'umin' {ASIMD}.
kIdUminp_v, //!< Instruction 'uminp' {ASIMD}.
kIdUminv_v, //!< Instruction 'uminv' {ASIMD}.
kIdUmlal_v, //!< Instruction 'umlal' {ASIMD}.
kIdUmlal2_v, //!< Instruction 'umlal2' {ASIMD}.
kIdUmlsl_v, //!< Instruction 'umlsl' {ASIMD}.
kIdUmlsl2_v, //!< Instruction 'umlsl2' {ASIMD}.
kIdUmmla_v, //!< Instruction 'ummla' {ASIMD}.
kIdUmov_v, //!< Instruction 'umov' {ASIMD}.
kIdUmull_v, //!< Instruction 'umull' {ASIMD}.
kIdUmull2_v, //!< Instruction 'umull2' {ASIMD}.
kIdUqadd_v, //!< Instruction 'uqadd' {ASIMD}.
kIdUqrshl_v, //!< Instruction 'uqrshl' {ASIMD}.
kIdUqrshrn_v, //!< Instruction 'uqrshrn' {ASIMD}.
kIdUqrshrn2_v, //!< Instruction 'uqrshrn2' {ASIMD}.
kIdUqshl_v, //!< Instruction 'uqshl' {ASIMD}.
kIdUqshrn_v, //!< Instruction 'uqshrn' {ASIMD}.
kIdUqshrn2_v, //!< Instruction 'uqshrn2' {ASIMD}.
kIdUqsub_v, //!< Instruction 'uqsub' {ASIMD}.
kIdUqxtn_v, //!< Instruction 'uqxtn' {ASIMD}.
kIdUqxtn2_v, //!< Instruction 'uqxtn2' {ASIMD}.
kIdUrecpe_v, //!< Instruction 'urecpe' {ASIMD}.
kIdUrhadd_v, //!< Instruction 'urhadd' {ASIMD}.
kIdUrshl_v, //!< Instruction 'urshl' {ASIMD}.
kIdUrshr_v, //!< Instruction 'urshr' {ASIMD}.
kIdUrsqrte_v, //!< Instruction 'ursqrte' {ASIMD}.
kIdUrsra_v, //!< Instruction 'ursra' {ASIMD}.
kIdUsdot_v, //!< Instruction 'usdot' {ASIMD}.
kIdUshl_v, //!< Instruction 'ushl' {ASIMD}.
kIdUshll_v, //!< Instruction 'ushll' {ASIMD}.
kIdUshll2_v, //!< Instruction 'ushll2' {ASIMD}.
kIdUshr_v, //!< Instruction 'ushr' {ASIMD}.
kIdUsmmla_v, //!< Instruction 'usmmla' {ASIMD}.
kIdUsqadd_v, //!< Instruction 'usqadd' {ASIMD}.
kIdUsra_v, //!< Instruction 'usra' {ASIMD}.
kIdUsubl_v, //!< Instruction 'usubl' {ASIMD}.
kIdUsubl2_v, //!< Instruction 'usubl2' {ASIMD}.
kIdUsubw_v, //!< Instruction 'usubw' {ASIMD}.
kIdUsubw2_v, //!< Instruction 'usubw2' {ASIMD}.
kIdUxtl_v, //!< Instruction 'uxtl' {ASIMD}.
kIdUxtl2_v, //!< Instruction 'uxtl2' {ASIMD}.
kIdUzp1_v, //!< Instruction 'uzp1' {ASIMD}.
kIdUzp2_v, //!< Instruction 'uzp2' {ASIMD}.
kIdXar_v, //!< Instruction 'xar' {ASIMD}.
kIdXtn_v, //!< Instruction 'xtn' {ASIMD}.
kIdXtn2_v, //!< Instruction 'xtn2' {ASIMD}.
kIdZip1_v, //!< Instruction 'zip1' {ASIMD}.
kIdZip2_v, //!< Instruction 'zip2' {ASIMD}.
_kIdCount
// ${InstId:End}
};
//! Tests whether the `instId` is defined (counts also Inst::kIdNone, which must be zero).
static inline bool isDefinedId(InstId instId) noexcept { return (instId & uint32_t(InstIdParts::kRealId)) < _kIdCount; }
};
namespace Predicate {
//! Address translate options (AT).
namespace AT {
static inline constexpr uint32_t encode(uint32_t op1, uint32_t cRn, uint32_t cRm, uint32_t op2) noexcept {
return (op1 << 11) | (cRn << 7) | (cRm << 3) | (op2 << 0);
}
enum Value : uint32_t {
kS1E1R = encode(0b000, 0b0111, 0b1000, 0b000),
kS1E2R = encode(0b100, 0b0111, 0b1000, 0b000),
kS1E3R = encode(0b110, 0b0111, 0b1000, 0b000),
kS1E1W = encode(0b000, 0b0111, 0b1000, 0b001),
kS1E2W = encode(0b100, 0b0111, 0b1000, 0b001),
kS1E3W = encode(0b110, 0b0111, 0b1000, 0b001),
kS1E0R = encode(0b000, 0b0111, 0b1000, 0b010),
kS1E0W = encode(0b000, 0b0111, 0b1000, 0b011),
kS12E1R = encode(0b100, 0b0111, 0b1000, 0b100),
kS12E1W = encode(0b100, 0b0111, 0b1000, 0b101),
kS12E0R = encode(0b100, 0b0111, 0b1000, 0b110),
kS12E0W = encode(0b100, 0b0111, 0b1000, 0b111),
kS1E1RP = encode(0b000, 0b0111, 0b1001, 0b000),
kS1E1WP = encode(0b000, 0b0111, 0b1001, 0b001)
};
}
//! Data barrier options (DMB/DSB).
namespace DB {
//! Data barrier immediate values.
enum Value : uint32_t {
//! Waits only for loads to complete, and only applies to the outer shareable domain.
kOSHLD = 0x01u,
//! Waits only for stores to complete, and only applies to the outer shareable domain.
kOSHST = 0x02u,
//! Only applies to the outer shareable domain.
kOSH = 0x03u,
//! Waits only for loads to complete and only applies out to the point of unification.
kNSHLD = 0x05u,
//! Waits only for stores to complete and only applies out to the point of unification.
kNSHST = 0x06u,
//! Only applies out to the point of unification.
kNSH = 0x07u,
//! Waits only for loads to complete, and only applies to the inner shareable domain.
kISHLD = 0x09u,
//! Waits only for stores to complete, and only applies to the inner shareable domain.
kISHST = 0x0Au,
//! Only applies to the inner shareable domain.
kISH = 0x0Bu,
//! Waits only for loads to complete.
kLD = 0x0Du,
//! Waits only for stores to complete.
kST = 0x0Eu,
//! Full system memory barrier operation.
kSY = 0x0Fu
};
}
//! Data cache maintenance options.
namespace DC {
static inline constexpr uint32_t encode(uint32_t op1, uint32_t cRn, uint32_t cRm, uint32_t op2) noexcept {
return (op1 << 11) | (cRn << 7) | (cRm << 3) | (op2 << 0);
}
//! Data cache maintenance immediate values.
enum Value : uint32_t {
kZVA = encode(0b011, 0b0111, 0b0100, 0b001),
kIVAC = encode(0b000, 0b0111, 0b0110, 0b001),
kISW = encode(0b000, 0b0111, 0b0110, 0b010),
kCVAC = encode(0b011, 0b0111, 0b1010, 0b001),
kCSW = encode(0b000, 0b0111, 0b1010, 0b010),
kCVAU = encode(0b011, 0b0111, 0b1011, 0b001),
kCIVAC = encode(0b011, 0b0111, 0b1110, 0b001),
kCISW = encode(0b000, 0b0111, 0b1110, 0b010),
kCVAP = encode(0b011, 0b0111, 0b1100, 0b001),
kCVADP = encode(0b011, 0b0111, 0b1101, 0b001),
kIGVAC = encode(0b000, 0b0111, 0b0110, 0b011),
kIGSW = encode(0b000, 0b0111, 0b0110, 0b100),
kCGSW = encode(0b000, 0b0111, 0b1010, 0b100),
kCIGSW = encode(0b000, 0b0111, 0b1110, 0b100),
kCGVAC = encode(0b011, 0b0111, 0b1010, 0b011),
kCGVAP = encode(0b011, 0b0111, 0b1100, 0b011),
kCGVADP = encode(0b011, 0b0111, 0b1101, 0b011),
kCIGVAC = encode(0b011, 0b0111, 0b1110, 0b011),
kGVA = encode(0b011, 0b0111, 0b0100, 0b011),
kIGDVAC = encode(0b000, 0b0111, 0b0110, 0b101),
kIGDSW = encode(0b000, 0b0111, 0b0110, 0b110),
kCGDSW = encode(0b000, 0b0111, 0b1010, 0b110),
kCIGDSW = encode(0b000, 0b0111, 0b1110, 0b110),
kCGDVAC = encode(0b011, 0b0111, 0b1010, 0b101),
kCGDVAP = encode(0b011, 0b0111, 0b1100, 0b101),
kCGDVADP = encode(0b011, 0b0111, 0b1101, 0b101),
kCIGDVAC = encode(0b011, 0b0111, 0b1110, 0b101),
kGZVA = encode(0b011, 0b0111, 0b0100, 0b100)
};
}
//! Instruction cache maintenance options.
namespace IC {
static inline constexpr uint32_t encode(uint32_t op1, uint32_t cRn, uint32_t cRm, uint32_t op2) noexcept {
return (op1 << 11) | (cRn << 7) | (cRm << 3) | (op2 << 0);
}
//! Instruction cache maintenance immediate values.
enum Value : uint32_t {
kIALLUIS = encode(0b000, 0b0111, 0b0001, 0b000),
kIALLU = encode(0b000, 0b0111, 0b0101, 0b000),
kIVAU = encode(0b011, 0b0111, 0b0101, 0b001)
};
}
//! Instruction-fetch barrier options.
namespace ISB {
//! Instruction-fetch barrier immediate values.
enum Value : uint32_t {
kSY = 0xF
};
}
//! Prefetch options.
namespace PRFOp {
//! Prefetch immediate values.
enum Value : uint32_t {
kPLDL1KEEP = 0x00,
kPLDL1STRM = 0x01,
kPLDL2KEEP = 0x02,
kPLDL2STRM = 0x03,
kPLDL3KEEP = 0x04,
kPLDL3STRM = 0x05,
kPLIL1KEEP = 0x08,
kPLIL1STRM = 0x09,
kPLIL2KEEP = 0x0A,
kPLIL2STRM = 0x0B,
kPLIL3KEEP = 0x0C,
kPLIL3STRM = 0x0D,
kPSTL1KEEP = 0x10,
kPSTL1STRM = 0x11,
kPSTL2KEEP = 0x12,
kPSTL2STRM = 0x13,
kPSTL3KEEP = 0x14,
kPSTL3STRM = 0x15
};
}
//! PSB instruction options.
namespace PSB {
//! PSB immediate values.
enum Value : uint32_t {
kCSYNC = 0x11u
};
}
namespace TLBI {
static inline constexpr uint32_t encode(uint32_t op1, uint32_t cRn, uint32_t cRm, uint32_t op2) noexcept {
return (op1 << 11) | (cRn << 7) | (cRm << 3) | (op2 << 0);
}
enum Value : uint32_t {
kIPAS2E1IS = encode(0b100, 0b1000, 0b0000, 0b001),
kIPAS2LE1IS = encode(0b100, 0b1000, 0b0000, 0b101),
kVMALLE1IS = encode(0b000, 0b1000, 0b0011, 0b000),
kALLE2IS = encode(0b100, 0b1000, 0b0011, 0b000),
kALLE3IS = encode(0b110, 0b1000, 0b0011, 0b000),
kVAE1IS = encode(0b000, 0b1000, 0b0011, 0b001),
kVAE2IS = encode(0b100, 0b1000, 0b0011, 0b001),
kVAE3IS = encode(0b110, 0b1000, 0b0011, 0b001),
kASIDE1IS = encode(0b000, 0b1000, 0b0011, 0b010),
kVAAE1IS = encode(0b000, 0b1000, 0b0011, 0b011),
kALLE1IS = encode(0b100, 0b1000, 0b0011, 0b100),
kVALE1IS = encode(0b000, 0b1000, 0b0011, 0b101),
kVALE2IS = encode(0b100, 0b1000, 0b0011, 0b101),
kVALE3IS = encode(0b110, 0b1000, 0b0011, 0b101),
kVMALLS12E1IS = encode(0b100, 0b1000, 0b0011, 0b110),
kVAALE1IS = encode(0b000, 0b1000, 0b0011, 0b111),
kIPAS2E1 = encode(0b100, 0b1000, 0b0100, 0b001),
kIPAS2LE1 = encode(0b100, 0b1000, 0b0100, 0b101),
kVMALLE1 = encode(0b000, 0b1000, 0b0111, 0b000),
kALLE2 = encode(0b100, 0b1000, 0b0111, 0b000),
kALLE3 = encode(0b110, 0b1000, 0b0111, 0b000),
kVAE1 = encode(0b000, 0b1000, 0b0111, 0b001),
kVAE2 = encode(0b100, 0b1000, 0b0111, 0b001),
kVAE3 = encode(0b110, 0b1000, 0b0111, 0b001),
kASIDE1 = encode(0b000, 0b1000, 0b0111, 0b010),
kVAAE1 = encode(0b000, 0b1000, 0b0111, 0b011),
kALLE1 = encode(0b100, 0b1000, 0b0111, 0b100),
kVALE1 = encode(0b000, 0b1000, 0b0111, 0b101),
kVALE2 = encode(0b100, 0b1000, 0b0111, 0b101),
kVALE3 = encode(0b110, 0b1000, 0b0111, 0b101),
kVMALLS12E1 = encode(0b100, 0b1000, 0b0111, 0b110),
kVAALE1 = encode(0b000, 0b1000, 0b0111, 0b111),
kVMALLE1OS = encode(0b000, 0b1000, 0b0001, 0b000),
kVAE1OS = encode(0b000, 0b1000, 0b0001, 0b001),
kASIDE1OS = encode(0b000, 0b1000, 0b0001, 0b010),
kVAAE1OS = encode(0b000, 0b1000, 0b0001, 0b011),
kVALE1OS = encode(0b000, 0b1000, 0b0001, 0b101),
kVAALE1OS = encode(0b000, 0b1000, 0b0001, 0b111),
kIPAS2E1OS = encode(0b100, 0b1000, 0b0100, 0b000),
kIPAS2LE1OS = encode(0b100, 0b1000, 0b0100, 0b100),
kVAE2OS = encode(0b100, 0b1000, 0b0001, 0b001),
kVALE2OS = encode(0b100, 0b1000, 0b0001, 0b101),
kVMALLS12E1OS = encode(0b100, 0b1000, 0b0001, 0b110),
kVAE3OS = encode(0b110, 0b1000, 0b0001, 0b001),
kVALE3OS = encode(0b110, 0b1000, 0b0001, 0b101),
kALLE2OS = encode(0b100, 0b1000, 0b0001, 0b000),
kALLE1OS = encode(0b100, 0b1000, 0b0001, 0b100),
kALLE3OS = encode(0b110, 0b1000, 0b0001, 0b000),
kRVAE1 = encode(0b000, 0b1000, 0b0110, 0b001),
kRVAAE1 = encode(0b000, 0b1000, 0b0110, 0b011),
kRVALE1 = encode(0b000, 0b1000, 0b0110, 0b101),
kRVAALE1 = encode(0b000, 0b1000, 0b0110, 0b111),
kRVAE1IS = encode(0b000, 0b1000, 0b0010, 0b001),
kRVAAE1IS = encode(0b000, 0b1000, 0b0010, 0b011),
kRVALE1IS = encode(0b000, 0b1000, 0b0010, 0b101),
kRVAALE1IS = encode(0b000, 0b1000, 0b0010, 0b111),
kRVAE1OS = encode(0b000, 0b1000, 0b0101, 0b001),
kRVAAE1OS = encode(0b000, 0b1000, 0b0101, 0b011),
kRVALE1OS = encode(0b000, 0b1000, 0b0101, 0b101),
kRVAALE1OS = encode(0b000, 0b1000, 0b0101, 0b111),
kRIPAS2E1IS = encode(0b100, 0b1000, 0b0000, 0b010),
kRIPAS2LE1IS = encode(0b100, 0b1000, 0b0000, 0b110),
kRIPAS2E1 = encode(0b100, 0b1000, 0b0100, 0b010),
kRIPAS2LE1 = encode(0b100, 0b1000, 0b0100, 0b110),
kRIPAS2E1OS = encode(0b100, 0b1000, 0b0100, 0b011),
kRIPAS2LE1OS = encode(0b100, 0b1000, 0b0100, 0b111),
kRVAE2 = encode(0b100, 0b1000, 0b0110, 0b001),
kRVALE2 = encode(0b100, 0b1000, 0b0110, 0b101),
kRVAE2IS = encode(0b100, 0b1000, 0b0010, 0b001),
kRVALE2IS = encode(0b100, 0b1000, 0b0010, 0b101),
kRVAE2OS = encode(0b100, 0b1000, 0b0101, 0b001),
kRVALE2OS = encode(0b100, 0b1000, 0b0101, 0b101),
kRVAE3 = encode(0b110, 0b1000, 0b0110, 0b001),
kRVALE3 = encode(0b110, 0b1000, 0b0110, 0b101),
kRVAE3IS = encode(0b110, 0b1000, 0b0010, 0b001),
kRVALE3IS = encode(0b110, 0b1000, 0b0010, 0b101),
kRVAE3OS = encode(0b110, 0b1000, 0b0101, 0b001),
kRVALE3OS = encode(0b110, 0b1000, 0b0101, 0b101),
};
}
//! Trace synchronization barrier options.
namespace TSB {
//! Trace synchronization immediate values.
enum Value : uint32_t {
kCSYNC = 0
};
}
//! Processor state access through MSR.
namespace PState {
//! Encodes a pstate from `op0` and `op1`.
static inline constexpr uint32_t encode(uint32_t op0, uint32_t op1) noexcept {
return (op0 << 3) | (op1 << 0);
}
//! Processor state access immediates.
enum Value : uint32_t {
kSPSel = encode(0b000, 0b101),
kDAIFSet = encode(0b011, 0b110),
kDAIFClr = encode(0b011, 0b111),
kPAN = encode(0b000, 0b100),
kUAO = encode(0b000, 0b011),
kDIT = encode(0b011, 0b010),
kSSBS = encode(0b011, 0b001),
kTCO = encode(0b011, 0b100)
};
};
//! System register identifiers and utilities (MSR/MRS).
namespace SysReg {
//! System register fields.
struct Fields {
uint8_t op0;
uint8_t op1;
uint8_t cRn;
uint8_t cRm;
uint8_t op2;
};
//! Encodes a system register from `op0`, `op1`, `cRn`, `cRm`, and `op2` fields.
static inline constexpr uint32_t encode(uint32_t op0, uint32_t op1, uint32_t cRn, uint32_t cRm, uint32_t op2) noexcept {
return (op0 << 14) | (op1 << 11) | (cRn << 7) | (cRm << 3) | (op2 << 0);
}
//! Encodes a system register from `fields`.
static inline constexpr uint32_t encode(const Fields& fields) noexcept {
return encode(fields.op0, fields.op1, fields.cRn, fields.cRm, fields.op2);
}
//! Decodes a system register to \ref Fields.
static inline constexpr Fields decode(uint32_t id) noexcept {
return Fields {
uint8_t((id >> 14) & 0x3u),
uint8_t((id >> 11) & 0x7u),
uint8_t((id >> 7) & 0xFu),
uint8_t((id >> 3) & 0xFu),
uint8_t((id >> 0) & 0x7u)
};
}
//! System register identifiers.
enum Id : uint32_t {
kACTLR_EL1 = encode(0b11, 0b000, 0b0001, 0b0000, 0b001), // RW
kACTLR_EL2 = encode(0b11, 0b100, 0b0001, 0b0000, 0b001), // RW
kACTLR_EL3 = encode(0b11, 0b110, 0b0001, 0b0000, 0b001), // RW
kAFSR0_EL1 = encode(0b11, 0b000, 0b0101, 0b0001, 0b000), // RW
kAFSR0_EL12 = encode(0b11, 0b101, 0b0101, 0b0001, 0b000), // RW
kAFSR0_EL2 = encode(0b11, 0b100, 0b0101, 0b0001, 0b000), // RW
kAFSR0_EL3 = encode(0b11, 0b110, 0b0101, 0b0001, 0b000), // RW
kAFSR1_EL1 = encode(0b11, 0b000, 0b0101, 0b0001, 0b001), // RW
kAFSR1_EL12 = encode(0b11, 0b101, 0b0101, 0b0001, 0b001), // RW
kAFSR1_EL2 = encode(0b11, 0b100, 0b0101, 0b0001, 0b001), // RW
kAFSR1_EL3 = encode(0b11, 0b110, 0b0101, 0b0001, 0b001), // RW
kAIDR_EL1 = encode(0b11, 0b001, 0b0000, 0b0000, 0b111), // RO
kAMAIR_EL1 = encode(0b11, 0b000, 0b1010, 0b0011, 0b000), // RW
kAMAIR_EL12 = encode(0b11, 0b101, 0b1010, 0b0011, 0b000), // RW
kAMAIR_EL2 = encode(0b11, 0b100, 0b1010, 0b0011, 0b000), // RW
kAMAIR_EL3 = encode(0b11, 0b110, 0b1010, 0b0011, 0b000), // RW
kAMCFGR_EL0 = encode(0b11, 0b011, 0b1101, 0b0010, 0b001), // RO
kAMCGCR_EL0 = encode(0b11, 0b011, 0b1101, 0b0010, 0b010), // RO
kAMCNTENCLR0_EL0 = encode(0b11, 0b011, 0b1101, 0b0010, 0b100), // RW
kAMCNTENCLR1_EL0 = encode(0b11, 0b011, 0b1101, 0b0011, 0b000), // RW
kAMCNTENSET0_EL0 = encode(0b11, 0b011, 0b1101, 0b0010, 0b101), // RW
kAMCNTENSET1_EL0 = encode(0b11, 0b011, 0b1101, 0b0011, 0b001), // RW
kAMCR_EL0 = encode(0b11, 0b011, 0b1101, 0b0010, 0b000), // RW
kAMEVCNTR00_EL0 = encode(0b11, 0b011, 0b1101, 0b0100, 0b000), // RW
kAMEVCNTR01_EL0 = encode(0b11, 0b011, 0b1101, 0b0100, 0b001), // RW
kAMEVCNTR02_EL0 = encode(0b11, 0b011, 0b1101, 0b0100, 0b010), // RW
kAMEVCNTR03_EL0 = encode(0b11, 0b011, 0b1101, 0b0100, 0b011), // RW
kAMEVCNTR10_EL0 = encode(0b11, 0b011, 0b1101, 0b1100, 0b000), // RW
kAMEVCNTR110_EL0 = encode(0b11, 0b011, 0b1101, 0b1101, 0b010), // RW
kAMEVCNTR111_EL0 = encode(0b11, 0b011, 0b1101, 0b1101, 0b011), // RW
kAMEVCNTR112_EL0 = encode(0b11, 0b011, 0b1101, 0b1101, 0b100), // RW
kAMEVCNTR113_EL0 = encode(0b11, 0b011, 0b1101, 0b1101, 0b101), // RW
kAMEVCNTR114_EL0 = encode(0b11, 0b011, 0b1101, 0b1101, 0b110), // RW
kAMEVCNTR115_EL0 = encode(0b11, 0b011, 0b1101, 0b1101, 0b111), // RW
kAMEVCNTR11_EL0 = encode(0b11, 0b011, 0b1101, 0b1100, 0b001), // RW
kAMEVCNTR12_EL0 = encode(0b11, 0b011, 0b1101, 0b1100, 0b010), // RW
kAMEVCNTR13_EL0 = encode(0b11, 0b011, 0b1101, 0b1100, 0b011), // RW
kAMEVCNTR14_EL0 = encode(0b11, 0b011, 0b1101, 0b1100, 0b100), // RW
kAMEVCNTR15_EL0 = encode(0b11, 0b011, 0b1101, 0b1100, 0b101), // RW
kAMEVCNTR16_EL0 = encode(0b11, 0b011, 0b1101, 0b1100, 0b110), // RW
kAMEVCNTR17_EL0 = encode(0b11, 0b011, 0b1101, 0b1100, 0b111), // RW
kAMEVCNTR18_EL0 = encode(0b11, 0b011, 0b1101, 0b1101, 0b000), // RW
kAMEVCNTR19_EL0 = encode(0b11, 0b011, 0b1101, 0b1101, 0b001), // RW
kAMEVTYPER00_EL0 = encode(0b11, 0b011, 0b1101, 0b0110, 0b000), // RO
kAMEVTYPER01_EL0 = encode(0b11, 0b011, 0b1101, 0b0110, 0b001), // RO
kAMEVTYPER02_EL0 = encode(0b11, 0b011, 0b1101, 0b0110, 0b010), // RO
kAMEVTYPER03_EL0 = encode(0b11, 0b011, 0b1101, 0b0110, 0b011), // RO
kAMEVTYPER10_EL0 = encode(0b11, 0b011, 0b1101, 0b1110, 0b000), // RW
kAMEVTYPER110_EL0 = encode(0b11, 0b011, 0b1101, 0b1111, 0b010), // RW
kAMEVTYPER111_EL0 = encode(0b11, 0b011, 0b1101, 0b1111, 0b011), // RW
kAMEVTYPER112_EL0 = encode(0b11, 0b011, 0b1101, 0b1111, 0b100), // RW
kAMEVTYPER113_EL0 = encode(0b11, 0b011, 0b1101, 0b1111, 0b101), // RW
kAMEVTYPER114_EL0 = encode(0b11, 0b011, 0b1101, 0b1111, 0b110), // RW
kAMEVTYPER115_EL0 = encode(0b11, 0b011, 0b1101, 0b1111, 0b111), // RW
kAMEVTYPER11_EL0 = encode(0b11, 0b011, 0b1101, 0b1110, 0b001), // RW
kAMEVTYPER12_EL0 = encode(0b11, 0b011, 0b1101, 0b1110, 0b010), // RW
kAMEVTYPER13_EL0 = encode(0b11, 0b011, 0b1101, 0b1110, 0b011), // RW
kAMEVTYPER14_EL0 = encode(0b11, 0b011, 0b1101, 0b1110, 0b100), // RW
kAMEVTYPER15_EL0 = encode(0b11, 0b011, 0b1101, 0b1110, 0b101), // RW
kAMEVTYPER16_EL0 = encode(0b11, 0b011, 0b1101, 0b1110, 0b110), // RW
kAMEVTYPER17_EL0 = encode(0b11, 0b011, 0b1101, 0b1110, 0b111), // RW
kAMEVTYPER18_EL0 = encode(0b11, 0b011, 0b1101, 0b1111, 0b000), // RW
kAMEVTYPER19_EL0 = encode(0b11, 0b011, 0b1101, 0b1111, 0b001), // RW
kAMUSERENR_EL0 = encode(0b11, 0b011, 0b1101, 0b0010, 0b011), // RW
kAPDAKeyHi_EL1 = encode(0b11, 0b000, 0b0010, 0b0010, 0b001), // RW
kAPDAKeyLo_EL1 = encode(0b11, 0b000, 0b0010, 0b0010, 0b000), // RW
kAPDBKeyHi_EL1 = encode(0b11, 0b000, 0b0010, 0b0010, 0b011), // RW
kAPDBKeyLo_EL1 = encode(0b11, 0b000, 0b0010, 0b0010, 0b010), // RW
kAPGAKeyHi_EL1 = encode(0b11, 0b000, 0b0010, 0b0011, 0b001), // RW
kAPGAKeyLo_EL1 = encode(0b11, 0b000, 0b0010, 0b0011, 0b000), // RW
kAPIAKeyHi_EL1 = encode(0b11, 0b000, 0b0010, 0b0001, 0b001), // RW
kAPIAKeyLo_EL1 = encode(0b11, 0b000, 0b0010, 0b0001, 0b000), // RW
kAPIBKeyHi_EL1 = encode(0b11, 0b000, 0b0010, 0b0001, 0b011), // RW
kAPIBKeyLo_EL1 = encode(0b11, 0b000, 0b0010, 0b0001, 0b010), // RW
kCCSIDR2_EL1 = encode(0b11, 0b001, 0b0000, 0b0000, 0b010), // RO
kCCSIDR_EL1 = encode(0b11, 0b001, 0b0000, 0b0000, 0b000), // RO
kCLIDR_EL1 = encode(0b11, 0b001, 0b0000, 0b0000, 0b001), // RO
kCNTFRQ_EL0 = encode(0b11, 0b011, 0b1110, 0b0000, 0b000), // RW
kCNTHCTL_EL2 = encode(0b11, 0b100, 0b1110, 0b0001, 0b000), // RW
kCNTHPS_CTL_EL2 = encode(0b11, 0b100, 0b1110, 0b0101, 0b001), // RW
kCNTHPS_CVAL_EL2 = encode(0b11, 0b100, 0b1110, 0b0101, 0b010), // RW
kCNTHPS_TVAL_EL2 = encode(0b11, 0b100, 0b1110, 0b0101, 0b000), // RW
kCNTHP_CTL_EL2 = encode(0b11, 0b100, 0b1110, 0b0010, 0b001), // RW
kCNTHP_CVAL_EL2 = encode(0b11, 0b100, 0b1110, 0b0010, 0b010), // RW
kCNTHP_TVAL_EL2 = encode(0b11, 0b100, 0b1110, 0b0010, 0b000), // RW
kCNTHVS_CTL_EL2 = encode(0b11, 0b100, 0b1110, 0b0100, 0b001), // RW
kCNTHVS_CVAL_EL2 = encode(0b11, 0b100, 0b1110, 0b0100, 0b010), // RW
kCNTHVS_TVAL_EL2 = encode(0b11, 0b100, 0b1110, 0b0100, 0b000), // RW
kCNTHV_CTL_EL2 = encode(0b11, 0b100, 0b1110, 0b0011, 0b001), // RW
kCNTHV_CVAL_EL2 = encode(0b11, 0b100, 0b1110, 0b0011, 0b010), // RW
kCNTHV_TVAL_EL2 = encode(0b11, 0b100, 0b1110, 0b0011, 0b000), // RW
kCNTISCALE_EL2 = encode(0b11, 0b100, 0b1110, 0b0000, 0b101), // RW
kCNTKCTL_EL1 = encode(0b11, 0b000, 0b1110, 0b0001, 0b000), // RW
kCNTKCTL_EL12 = encode(0b11, 0b101, 0b1110, 0b0001, 0b000), // RW
kCNTPCTSS_EL0 = encode(0b11, 0b011, 0b1110, 0b0000, 0b101), // RW
kCNTPCT_EL0 = encode(0b11, 0b011, 0b1110, 0b0000, 0b001), // RO
kCNTPOFF_EL2 = encode(0b11, 0b100, 0b1110, 0b0000, 0b110), // RW
kCNTPS_CTL_EL1 = encode(0b11, 0b111, 0b1110, 0b0010, 0b001), // RW
kCNTPS_CVAL_EL1 = encode(0b11, 0b111, 0b1110, 0b0010, 0b010), // RW
kCNTPS_TVAL_EL1 = encode(0b11, 0b111, 0b1110, 0b0010, 0b000), // RW
kCNTP_CTL_EL0 = encode(0b11, 0b011, 0b1110, 0b0010, 0b001), // RW
kCNTP_CTL_EL02 = encode(0b11, 0b101, 0b1110, 0b0010, 0b001), // RW
kCNTP_CVAL_EL0 = encode(0b11, 0b011, 0b1110, 0b0010, 0b010), // RW
kCNTP_CVAL_EL02 = encode(0b11, 0b101, 0b1110, 0b0010, 0b010), // RW
kCNTP_TVAL_EL0 = encode(0b11, 0b011, 0b1110, 0b0010, 0b000), // RW
kCNTP_TVAL_EL02 = encode(0b11, 0b101, 0b1110, 0b0010, 0b000), // RW
kCNTSCALE_EL2 = encode(0b11, 0b100, 0b1110, 0b0000, 0b100), // RW
kCNTVCTSS_EL0 = encode(0b11, 0b011, 0b1110, 0b0000, 0b110), // RW
kCNTVCT_EL0 = encode(0b11, 0b011, 0b1110, 0b0000, 0b010), // RO
kCNTVFRQ_EL2 = encode(0b11, 0b100, 0b1110, 0b0000, 0b111), // RW
kCNTVOFF_EL2 = encode(0b11, 0b100, 0b1110, 0b0000, 0b011), // RW
kCNTV_CTL_EL0 = encode(0b11, 0b011, 0b1110, 0b0011, 0b001), // RW
kCNTV_CTL_EL02 = encode(0b11, 0b101, 0b1110, 0b0011, 0b001), // RW
kCNTV_CVAL_EL0 = encode(0b11, 0b011, 0b1110, 0b0011, 0b010), // RW
kCNTV_CVAL_EL02 = encode(0b11, 0b101, 0b1110, 0b0011, 0b010), // RW
kCNTV_TVAL_EL0 = encode(0b11, 0b011, 0b1110, 0b0011, 0b000), // RW
kCNTV_TVAL_EL02 = encode(0b11, 0b101, 0b1110, 0b0011, 0b000), // RW
kCONTEXTIDR_EL1 = encode(0b11, 0b000, 0b1101, 0b0000, 0b001), // RW
kCONTEXTIDR_EL12 = encode(0b11, 0b101, 0b1101, 0b0000, 0b001), // RW
kCONTEXTIDR_EL2 = encode(0b11, 0b100, 0b1101, 0b0000, 0b001), // RW
kCPACR_EL1 = encode(0b11, 0b000, 0b0001, 0b0000, 0b010), // RW
kCPACR_EL12 = encode(0b11, 0b101, 0b0001, 0b0000, 0b010), // RW
kCPM_IOACC_CTL_EL3 = encode(0b11, 0b111, 0b1111, 0b0010, 0b000), // RW
kCPTR_EL2 = encode(0b11, 0b100, 0b0001, 0b0001, 0b010), // RW
kCPTR_EL3 = encode(0b11, 0b110, 0b0001, 0b0001, 0b010), // RW
kCSSELR_EL1 = encode(0b11, 0b010, 0b0000, 0b0000, 0b000), // RW
kCTR_EL0 = encode(0b11, 0b011, 0b0000, 0b0000, 0b001), // RO
kCurrentEL = encode(0b11, 0b000, 0b0100, 0b0010, 0b010), // RO
kDACR32_EL2 = encode(0b11, 0b100, 0b0011, 0b0000, 0b000), // RW
kDAIF = encode(0b11, 0b011, 0b0100, 0b0010, 0b001), // RW
kDBGAUTHSTATUS_EL1 = encode(0b10, 0b000, 0b0111, 0b1110, 0b110), // RO
kDBGBCR0_EL1 = encode(0b10, 0b000, 0b0000, 0b0000, 0b101), // RW
kDBGBCR10_EL1 = encode(0b10, 0b000, 0b0000, 0b1010, 0b101), // RW
kDBGBCR11_EL1 = encode(0b10, 0b000, 0b0000, 0b1011, 0b101), // RW
kDBGBCR12_EL1 = encode(0b10, 0b000, 0b0000, 0b1100, 0b101), // RW
kDBGBCR13_EL1 = encode(0b10, 0b000, 0b0000, 0b1101, 0b101), // RW
kDBGBCR14_EL1 = encode(0b10, 0b000, 0b0000, 0b1110, 0b101), // RW
kDBGBCR15_EL1 = encode(0b10, 0b000, 0b0000, 0b1111, 0b101), // RW
kDBGBCR1_EL1 = encode(0b10, 0b000, 0b0000, 0b0001, 0b101), // RW
kDBGBCR2_EL1 = encode(0b10, 0b000, 0b0000, 0b0010, 0b101), // RW
kDBGBCR3_EL1 = encode(0b10, 0b000, 0b0000, 0b0011, 0b101), // RW
kDBGBCR4_EL1 = encode(0b10, 0b000, 0b0000, 0b0100, 0b101), // RW
kDBGBCR5_EL1 = encode(0b10, 0b000, 0b0000, 0b0101, 0b101), // RW
kDBGBCR6_EL1 = encode(0b10, 0b000, 0b0000, 0b0110, 0b101), // RW
kDBGBCR7_EL1 = encode(0b10, 0b000, 0b0000, 0b0111, 0b101), // RW
kDBGBCR8_EL1 = encode(0b10, 0b000, 0b0000, 0b1000, 0b101), // RW
kDBGBCR9_EL1 = encode(0b10, 0b000, 0b0000, 0b1001, 0b101), // RW
kDBGBVR0_EL1 = encode(0b10, 0b000, 0b0000, 0b0000, 0b100), // RW
kDBGBVR10_EL1 = encode(0b10, 0b000, 0b0000, 0b1010, 0b100), // RW
kDBGBVR11_EL1 = encode(0b10, 0b000, 0b0000, 0b1011, 0b100), // RW
kDBGBVR12_EL1 = encode(0b10, 0b000, 0b0000, 0b1100, 0b100), // RW
kDBGBVR13_EL1 = encode(0b10, 0b000, 0b0000, 0b1101, 0b100), // RW
kDBGBVR14_EL1 = encode(0b10, 0b000, 0b0000, 0b1110, 0b100), // RW
kDBGBVR15_EL1 = encode(0b10, 0b000, 0b0000, 0b1111, 0b100), // RW
kDBGBVR1_EL1 = encode(0b10, 0b000, 0b0000, 0b0001, 0b100), // RW
kDBGBVR2_EL1 = encode(0b10, 0b000, 0b0000, 0b0010, 0b100), // RW
kDBGBVR3_EL1 = encode(0b10, 0b000, 0b0000, 0b0011, 0b100), // RW
kDBGBVR4_EL1 = encode(0b10, 0b000, 0b0000, 0b0100, 0b100), // RW
kDBGBVR5_EL1 = encode(0b10, 0b000, 0b0000, 0b0101, 0b100), // RW
kDBGBVR6_EL1 = encode(0b10, 0b000, 0b0000, 0b0110, 0b100), // RW
kDBGBVR7_EL1 = encode(0b10, 0b000, 0b0000, 0b0111, 0b100), // RW
kDBGBVR8_EL1 = encode(0b10, 0b000, 0b0000, 0b1000, 0b100), // RW
kDBGBVR9_EL1 = encode(0b10, 0b000, 0b0000, 0b1001, 0b100), // RW
kDBGCLAIMCLR_EL1 = encode(0b10, 0b000, 0b0111, 0b1001, 0b110), // RW
kDBGCLAIMSET_EL1 = encode(0b10, 0b000, 0b0111, 0b1000, 0b110), // RW
kDBGDTRRX_EL0 = encode(0b10, 0b011, 0b0000, 0b0101, 0b000), // RO
kDBGDTRTX_EL0 = encode(0b10, 0b011, 0b0000, 0b0101, 0b000), // WO
kDBGDTR_EL0 = encode(0b10, 0b011, 0b0000, 0b0100, 0b000), // RW
kDBGPRCR_EL1 = encode(0b10, 0b000, 0b0001, 0b0100, 0b100), // RW
kDBGVCR32_EL2 = encode(0b10, 0b100, 0b0000, 0b0111, 0b000), // RW
kDBGWCR0_EL1 = encode(0b10, 0b000, 0b0000, 0b0000, 0b111), // RW
kDBGWCR10_EL1 = encode(0b10, 0b000, 0b0000, 0b1010, 0b111), // RW
kDBGWCR11_EL1 = encode(0b10, 0b000, 0b0000, 0b1011, 0b111), // RW
kDBGWCR12_EL1 = encode(0b10, 0b000, 0b0000, 0b1100, 0b111), // RW
kDBGWCR13_EL1 = encode(0b10, 0b000, 0b0000, 0b1101, 0b111), // RW
kDBGWCR14_EL1 = encode(0b10, 0b000, 0b0000, 0b1110, 0b111), // RW
kDBGWCR15_EL1 = encode(0b10, 0b000, 0b0000, 0b1111, 0b111), // RW
kDBGWCR1_EL1 = encode(0b10, 0b000, 0b0000, 0b0001, 0b111), // RW
kDBGWCR2_EL1 = encode(0b10, 0b000, 0b0000, 0b0010, 0b111), // RW
kDBGWCR3_EL1 = encode(0b10, 0b000, 0b0000, 0b0011, 0b111), // RW
kDBGWCR4_EL1 = encode(0b10, 0b000, 0b0000, 0b0100, 0b111), // RW
kDBGWCR5_EL1 = encode(0b10, 0b000, 0b0000, 0b0101, 0b111), // RW
kDBGWCR6_EL1 = encode(0b10, 0b000, 0b0000, 0b0110, 0b111), // RW
kDBGWCR7_EL1 = encode(0b10, 0b000, 0b0000, 0b0111, 0b111), // RW
kDBGWCR8_EL1 = encode(0b10, 0b000, 0b0000, 0b1000, 0b111), // RW
kDBGWCR9_EL1 = encode(0b10, 0b000, 0b0000, 0b1001, 0b111), // RW
kDBGWVR0_EL1 = encode(0b10, 0b000, 0b0000, 0b0000, 0b110), // RW
kDBGWVR10_EL1 = encode(0b10, 0b000, 0b0000, 0b1010, 0b110), // RW
kDBGWVR11_EL1 = encode(0b10, 0b000, 0b0000, 0b1011, 0b110), // RW
kDBGWVR12_EL1 = encode(0b10, 0b000, 0b0000, 0b1100, 0b110), // RW
kDBGWVR13_EL1 = encode(0b10, 0b000, 0b0000, 0b1101, 0b110), // RW
kDBGWVR14_EL1 = encode(0b10, 0b000, 0b0000, 0b1110, 0b110), // RW
kDBGWVR15_EL1 = encode(0b10, 0b000, 0b0000, 0b1111, 0b110), // RW
kDBGWVR1_EL1 = encode(0b10, 0b000, 0b0000, 0b0001, 0b110), // RW
kDBGWVR2_EL1 = encode(0b10, 0b000, 0b0000, 0b0010, 0b110), // RW
kDBGWVR3_EL1 = encode(0b10, 0b000, 0b0000, 0b0011, 0b110), // RW
kDBGWVR4_EL1 = encode(0b10, 0b000, 0b0000, 0b0100, 0b110), // RW
kDBGWVR5_EL1 = encode(0b10, 0b000, 0b0000, 0b0101, 0b110), // RW
kDBGWVR6_EL1 = encode(0b10, 0b000, 0b0000, 0b0110, 0b110), // RW
kDBGWVR7_EL1 = encode(0b10, 0b000, 0b0000, 0b0111, 0b110), // RW
kDBGWVR8_EL1 = encode(0b10, 0b000, 0b0000, 0b1000, 0b110), // RW
kDBGWVR9_EL1 = encode(0b10, 0b000, 0b0000, 0b1001, 0b110), // RW
kDCZID_EL0 = encode(0b11, 0b011, 0b0000, 0b0000, 0b111), // RO
kDISR_EL1 = encode(0b11, 0b000, 0b1100, 0b0001, 0b001), // RW
kDIT = encode(0b11, 0b011, 0b0100, 0b0010, 0b101), // RW
kDLR_EL0 = encode(0b11, 0b011, 0b0100, 0b0101, 0b001), // RW
kDSPSR_EL0 = encode(0b11, 0b011, 0b0100, 0b0101, 0b000), // RW
kELR_EL1 = encode(0b11, 0b000, 0b0100, 0b0000, 0b001), // RW
kELR_EL12 = encode(0b11, 0b101, 0b0100, 0b0000, 0b001), // RW
kELR_EL2 = encode(0b11, 0b100, 0b0100, 0b0000, 0b001), // RW
kELR_EL3 = encode(0b11, 0b110, 0b0100, 0b0000, 0b001), // RW
kERRIDR_EL1 = encode(0b11, 0b000, 0b0101, 0b0011, 0b000), // RO
kERRSELR_EL1 = encode(0b11, 0b000, 0b0101, 0b0011, 0b001), // RW
kERXADDR_EL1 = encode(0b11, 0b000, 0b0101, 0b0100, 0b011), // RW
kERXCTLR_EL1 = encode(0b11, 0b000, 0b0101, 0b0100, 0b001), // RW
kERXFR_EL1 = encode(0b11, 0b000, 0b0101, 0b0100, 0b000), // RO
kERXMISC0_EL1 = encode(0b11, 0b000, 0b0101, 0b0101, 0b000), // RW
kERXMISC1_EL1 = encode(0b11, 0b000, 0b0101, 0b0101, 0b001), // RW
kERXMISC2_EL1 = encode(0b11, 0b000, 0b0101, 0b0101, 0b010), // RW
kERXMISC3_EL1 = encode(0b11, 0b000, 0b0101, 0b0101, 0b011), // RW
kERXPFGCDN_EL1 = encode(0b11, 0b000, 0b0101, 0b0100, 0b110), // RW
kERXPFGCTL_EL1 = encode(0b11, 0b000, 0b0101, 0b0100, 0b101), // RW
kERXPFGF_EL1 = encode(0b11, 0b000, 0b0101, 0b0100, 0b100), // RO
kERXSTATUS_EL1 = encode(0b11, 0b000, 0b0101, 0b0100, 0b010), // RW
kESR_EL1 = encode(0b11, 0b000, 0b0101, 0b0010, 0b000), // RW
kESR_EL12 = encode(0b11, 0b101, 0b0101, 0b0010, 0b000), // RW
kESR_EL2 = encode(0b11, 0b100, 0b0101, 0b0010, 0b000), // RW
kESR_EL3 = encode(0b11, 0b110, 0b0101, 0b0010, 0b000), // RW
kFAR_EL1 = encode(0b11, 0b000, 0b0110, 0b0000, 0b000), // RW
kFAR_EL12 = encode(0b11, 0b101, 0b0110, 0b0000, 0b000), // RW
kFAR_EL2 = encode(0b11, 0b100, 0b0110, 0b0000, 0b000), // RW
kFAR_EL3 = encode(0b11, 0b110, 0b0110, 0b0000, 0b000), // RW
kFPCR = encode(0b11, 0b011, 0b0100, 0b0100, 0b000), // RW
kFPEXC32_EL2 = encode(0b11, 0b100, 0b0101, 0b0011, 0b000), // RW
kFPSR = encode(0b11, 0b011, 0b0100, 0b0100, 0b001), // RW
kGCR_EL1 = encode(0b11, 0b000, 0b0001, 0b0000, 0b110), // RW
kGMID_EL1 = encode(0b11, 0b001, 0b0000, 0b0000, 0b100), // RO
kHACR_EL2 = encode(0b11, 0b100, 0b0001, 0b0001, 0b111), // RW
kHCR_EL2 = encode(0b11, 0b100, 0b0001, 0b0001, 0b000), // RW
kHDFGRTR_EL2 = encode(0b11, 0b100, 0b0011, 0b0001, 0b100), // RW
kHDFGWTR_EL2 = encode(0b11, 0b100, 0b0011, 0b0001, 0b101), // RW
kHFGITR_EL2 = encode(0b11, 0b100, 0b0001, 0b0001, 0b110), // RW
kHFGRTR_EL2 = encode(0b11, 0b100, 0b0001, 0b0001, 0b100), // RW
kHFGWTR_EL2 = encode(0b11, 0b100, 0b0001, 0b0001, 0b101), // RW
kHPFAR_EL2 = encode(0b11, 0b100, 0b0110, 0b0000, 0b100), // RW
kHSTR_EL2 = encode(0b11, 0b100, 0b0001, 0b0001, 0b011), // RW
kICC_AP0R0_EL1 = encode(0b11, 0b000, 0b1100, 0b1000, 0b100), // RW
kICC_AP0R1_EL1 = encode(0b11, 0b000, 0b1100, 0b1000, 0b101), // RW
kICC_AP0R2_EL1 = encode(0b11, 0b000, 0b1100, 0b1000, 0b110), // RW
kICC_AP0R3_EL1 = encode(0b11, 0b000, 0b1100, 0b1000, 0b111), // RW
kICC_AP1R0_EL1 = encode(0b11, 0b000, 0b1100, 0b1001, 0b000), // RW
kICC_AP1R1_EL1 = encode(0b11, 0b000, 0b1100, 0b1001, 0b001), // RW
kICC_AP1R2_EL1 = encode(0b11, 0b000, 0b1100, 0b1001, 0b010), // RW
kICC_AP1R3_EL1 = encode(0b11, 0b000, 0b1100, 0b1001, 0b011), // RW
kICC_ASGI1R_EL1 = encode(0b11, 0b000, 0b1100, 0b1011, 0b110), // WO
kICC_BPR0_EL1 = encode(0b11, 0b000, 0b1100, 0b1000, 0b011), // RW
kICC_BPR1_EL1 = encode(0b11, 0b000, 0b1100, 0b1100, 0b011), // RW
kICC_CTLR_EL1 = encode(0b11, 0b000, 0b1100, 0b1100, 0b100), // RW
kICC_CTLR_EL3 = encode(0b11, 0b110, 0b1100, 0b1100, 0b100), // RW
kICC_DIR_EL1 = encode(0b11, 0b000, 0b1100, 0b1011, 0b001), // WO
kICC_EOIR0_EL1 = encode(0b11, 0b000, 0b1100, 0b1000, 0b001), // WO
kICC_EOIR1_EL1 = encode(0b11, 0b000, 0b1100, 0b1100, 0b001), // WO
kICC_HPPIR0_EL1 = encode(0b11, 0b000, 0b1100, 0b1000, 0b010), // RO
kICC_HPPIR1_EL1 = encode(0b11, 0b000, 0b1100, 0b1100, 0b010), // RO
kICC_IAR0_EL1 = encode(0b11, 0b000, 0b1100, 0b1000, 0b000), // RO
kICC_IAR1_EL1 = encode(0b11, 0b000, 0b1100, 0b1100, 0b000), // RO
kICC_IGRPEN0_EL1 = encode(0b11, 0b000, 0b1100, 0b1100, 0b110), // RW
kICC_IGRPEN1_EL1 = encode(0b11, 0b000, 0b1100, 0b1100, 0b111), // RW
kICC_IGRPEN1_EL3 = encode(0b11, 0b110, 0b1100, 0b1100, 0b111), // RW
kICC_PMR_EL1 = encode(0b11, 0b000, 0b0100, 0b0110, 0b000), // RW
kICC_RPR_EL1 = encode(0b11, 0b000, 0b1100, 0b1011, 0b011), // RO
kICC_SGI0R_EL1 = encode(0b11, 0b000, 0b1100, 0b1011, 0b111), // WO
kICC_SGI1R_EL1 = encode(0b11, 0b000, 0b1100, 0b1011, 0b101), // WO
kICC_SRE_EL1 = encode(0b11, 0b000, 0b1100, 0b1100, 0b101), // RW
kICC_SRE_EL2 = encode(0b11, 0b100, 0b1100, 0b1001, 0b101), // RW
kICC_SRE_EL3 = encode(0b11, 0b110, 0b1100, 0b1100, 0b101), // RW
kICH_AP0R0_EL2 = encode(0b11, 0b100, 0b1100, 0b1000, 0b000), // RW
kICH_AP0R1_EL2 = encode(0b11, 0b100, 0b1100, 0b1000, 0b001), // RW
kICH_AP0R2_EL2 = encode(0b11, 0b100, 0b1100, 0b1000, 0b010), // RW
kICH_AP0R3_EL2 = encode(0b11, 0b100, 0b1100, 0b1000, 0b011), // RW
kICH_AP1R0_EL2 = encode(0b11, 0b100, 0b1100, 0b1001, 0b000), // RW
kICH_AP1R1_EL2 = encode(0b11, 0b100, 0b1100, 0b1001, 0b001), // RW
kICH_AP1R2_EL2 = encode(0b11, 0b100, 0b1100, 0b1001, 0b010), // RW
kICH_AP1R3_EL2 = encode(0b11, 0b100, 0b1100, 0b1001, 0b011), // RW
kICH_EISR_EL2 = encode(0b11, 0b100, 0b1100, 0b1011, 0b011), // RO
kICH_ELRSR_EL2 = encode(0b11, 0b100, 0b1100, 0b1011, 0b101), // RO
kICH_HCR_EL2 = encode(0b11, 0b100, 0b1100, 0b1011, 0b000), // RW
kICH_LR0_EL2 = encode(0b11, 0b100, 0b1100, 0b1100, 0b000), // RW
kICH_LR10_EL2 = encode(0b11, 0b100, 0b1100, 0b1101, 0b010), // RW
kICH_LR11_EL2 = encode(0b11, 0b100, 0b1100, 0b1101, 0b011), // RW
kICH_LR12_EL2 = encode(0b11, 0b100, 0b1100, 0b1101, 0b100), // RW
kICH_LR13_EL2 = encode(0b11, 0b100, 0b1100, 0b1101, 0b101), // RW
kICH_LR14_EL2 = encode(0b11, 0b100, 0b1100, 0b1101, 0b110), // RW
kICH_LR15_EL2 = encode(0b11, 0b100, 0b1100, 0b1101, 0b111), // RW
kICH_LR1_EL2 = encode(0b11, 0b100, 0b1100, 0b1100, 0b001), // RW
kICH_LR2_EL2 = encode(0b11, 0b100, 0b1100, 0b1100, 0b010), // RW
kICH_LR3_EL2 = encode(0b11, 0b100, 0b1100, 0b1100, 0b011), // RW
kICH_LR4_EL2 = encode(0b11, 0b100, 0b1100, 0b1100, 0b100), // RW
kICH_LR5_EL2 = encode(0b11, 0b100, 0b1100, 0b1100, 0b101), // RW
kICH_LR6_EL2 = encode(0b11, 0b100, 0b1100, 0b1100, 0b110), // RW
kICH_LR7_EL2 = encode(0b11, 0b100, 0b1100, 0b1100, 0b111), // RW
kICH_LR8_EL2 = encode(0b11, 0b100, 0b1100, 0b1101, 0b000), // RW
kICH_LR9_EL2 = encode(0b11, 0b100, 0b1100, 0b1101, 0b001), // RW
kICH_MISR_EL2 = encode(0b11, 0b100, 0b1100, 0b1011, 0b010), // RO
kICH_VMCR_EL2 = encode(0b11, 0b100, 0b1100, 0b1011, 0b111), // RW
kICH_VTR_EL2 = encode(0b11, 0b100, 0b1100, 0b1011, 0b001), // RO
kID_AA64AFR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0101, 0b100), // RO
kID_AA64AFR1_EL1 = encode(0b11, 0b000, 0b0000, 0b0101, 0b101), // RO
kID_AA64DFR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0101, 0b000), // RO
kID_AA64DFR1_EL1 = encode(0b11, 0b000, 0b0000, 0b0101, 0b001), // RO
kID_AA64ISAR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0110, 0b000), // RO
kID_AA64ISAR1_EL1 = encode(0b11, 0b000, 0b0000, 0b0110, 0b001), // RO
kID_AA64MMFR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0111, 0b000), // RO
kID_AA64MMFR1_EL1 = encode(0b11, 0b000, 0b0000, 0b0111, 0b001), // RO
kID_AA64MMFR2_EL1 = encode(0b11, 0b000, 0b0000, 0b0111, 0b010), // RO
kID_AA64PFR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0100, 0b000), // RO
kID_AA64PFR1_EL1 = encode(0b11, 0b000, 0b0000, 0b0100, 0b001), // RO
kID_AA64ZFR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0100, 0b100), // RO
kID_AFR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0001, 0b011), // RO
kID_DFR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0001, 0b010), // RO
kID_ISAR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0010, 0b000), // RO
kID_ISAR1_EL1 = encode(0b11, 0b000, 0b0000, 0b0010, 0b001), // RO
kID_ISAR2_EL1 = encode(0b11, 0b000, 0b0000, 0b0010, 0b010), // RO
kID_ISAR3_EL1 = encode(0b11, 0b000, 0b0000, 0b0010, 0b011), // RO
kID_ISAR4_EL1 = encode(0b11, 0b000, 0b0000, 0b0010, 0b100), // RO
kID_ISAR5_EL1 = encode(0b11, 0b000, 0b0000, 0b0010, 0b101), // RO
kID_ISAR6_EL1 = encode(0b11, 0b000, 0b0000, 0b0010, 0b111), // RO
kID_MMFR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0001, 0b100), // RO
kID_MMFR1_EL1 = encode(0b11, 0b000, 0b0000, 0b0001, 0b101), // RO
kID_MMFR2_EL1 = encode(0b11, 0b000, 0b0000, 0b0001, 0b110), // RO
kID_MMFR3_EL1 = encode(0b11, 0b000, 0b0000, 0b0001, 0b111), // RO
kID_MMFR4_EL1 = encode(0b11, 0b000, 0b0000, 0b0010, 0b110), // RO
kID_MMFR5_EL1 = encode(0b11, 0b000, 0b0000, 0b0011, 0b110), // RO
kID_PFR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0001, 0b000), // RO
kID_PFR1_EL1 = encode(0b11, 0b000, 0b0000, 0b0001, 0b001), // RO
kID_PFR2_EL1 = encode(0b11, 0b000, 0b0000, 0b0011, 0b100), // RO
kIFSR32_EL2 = encode(0b11, 0b100, 0b0101, 0b0000, 0b001), // RW
kISR_EL1 = encode(0b11, 0b000, 0b1100, 0b0001, 0b000), // RO
kLORC_EL1 = encode(0b11, 0b000, 0b1010, 0b0100, 0b011), // RW
kLOREA_EL1 = encode(0b11, 0b000, 0b1010, 0b0100, 0b001), // RW
kLORID_EL1 = encode(0b11, 0b000, 0b1010, 0b0100, 0b111), // RO
kLORN_EL1 = encode(0b11, 0b000, 0b1010, 0b0100, 0b010), // RW
kLORSA_EL1 = encode(0b11, 0b000, 0b1010, 0b0100, 0b000), // RW
kMAIR_EL1 = encode(0b11, 0b000, 0b1010, 0b0010, 0b000), // RW
kMAIR_EL12 = encode(0b11, 0b101, 0b1010, 0b0010, 0b000), // RW
kMAIR_EL2 = encode(0b11, 0b100, 0b1010, 0b0010, 0b000), // RW
kMAIR_EL3 = encode(0b11, 0b110, 0b1010, 0b0010, 0b000), // RW
kMDCCINT_EL1 = encode(0b10, 0b000, 0b0000, 0b0010, 0b000), // RW
kMDCCSR_EL0 = encode(0b10, 0b011, 0b0000, 0b0001, 0b000), // RO
kMDCR_EL2 = encode(0b11, 0b100, 0b0001, 0b0001, 0b001), // RW
kMDCR_EL3 = encode(0b11, 0b110, 0b0001, 0b0011, 0b001), // RW
kMDRAR_EL1 = encode(0b10, 0b000, 0b0001, 0b0000, 0b000), // RO
kMDSCR_EL1 = encode(0b10, 0b000, 0b0000, 0b0010, 0b010), // RW
kMIDR_EL1 = encode(0b11, 0b000, 0b0000, 0b0000, 0b000), // RO
kMPAM0_EL1 = encode(0b11, 0b000, 0b1010, 0b0101, 0b001), // RW
kMPAM1_EL1 = encode(0b11, 0b000, 0b1010, 0b0101, 0b000), // RW
kMPAM1_EL12 = encode(0b11, 0b101, 0b1010, 0b0101, 0b000), // RW
kMPAM2_EL2 = encode(0b11, 0b100, 0b1010, 0b0101, 0b000), // RW
kMPAM3_EL3 = encode(0b11, 0b110, 0b1010, 0b0101, 0b000), // RW
kMPAMHCR_EL2 = encode(0b11, 0b100, 0b1010, 0b0100, 0b000), // RW
kMPAMIDR_EL1 = encode(0b11, 0b000, 0b1010, 0b0100, 0b100), // RO
kMPAMVPM0_EL2 = encode(0b11, 0b100, 0b1010, 0b0110, 0b000), // RW
kMPAMVPM1_EL2 = encode(0b11, 0b100, 0b1010, 0b0110, 0b001), // RW
kMPAMVPM2_EL2 = encode(0b11, 0b100, 0b1010, 0b0110, 0b010), // RW
kMPAMVPM3_EL2 = encode(0b11, 0b100, 0b1010, 0b0110, 0b011), // RW
kMPAMVPM4_EL2 = encode(0b11, 0b100, 0b1010, 0b0110, 0b100), // RW
kMPAMVPM5_EL2 = encode(0b11, 0b100, 0b1010, 0b0110, 0b101), // RW
kMPAMVPM6_EL2 = encode(0b11, 0b100, 0b1010, 0b0110, 0b110), // RW
kMPAMVPM7_EL2 = encode(0b11, 0b100, 0b1010, 0b0110, 0b111), // RW
kMPAMVPMV_EL2 = encode(0b11, 0b100, 0b1010, 0b0100, 0b001), // RW
kMPIDR_EL1 = encode(0b11, 0b000, 0b0000, 0b0000, 0b101), // RO
kMVFR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0011, 0b000), // RO
kMVFR1_EL1 = encode(0b11, 0b000, 0b0000, 0b0011, 0b001), // RO
kMVFR2_EL1 = encode(0b11, 0b000, 0b0000, 0b0011, 0b010), // RO
kNZCV = encode(0b11, 0b011, 0b0100, 0b0010, 0b000), // RW
kOSDLR_EL1 = encode(0b10, 0b000, 0b0001, 0b0011, 0b100), // RW
kOSDTRRX_EL1 = encode(0b10, 0b000, 0b0000, 0b0000, 0b010), // RW
kOSDTRTX_EL1 = encode(0b10, 0b000, 0b0000, 0b0011, 0b010), // RW
kOSECCR_EL1 = encode(0b10, 0b000, 0b0000, 0b0110, 0b010), // RW
kOSLAR_EL1 = encode(0b10, 0b000, 0b0001, 0b0000, 0b100), // WO
kOSLSR_EL1 = encode(0b10, 0b000, 0b0001, 0b0001, 0b100), // RO
kPAN = encode(0b11, 0b000, 0b0100, 0b0010, 0b011), // RW
kPAR_EL1 = encode(0b11, 0b000, 0b0111, 0b0100, 0b000), // RW
kPMBIDR_EL1 = encode(0b11, 0b000, 0b1001, 0b1010, 0b111), // RO
kPMBLIMITR_EL1 = encode(0b11, 0b000, 0b1001, 0b1010, 0b000), // RW
kPMBPTR_EL1 = encode(0b11, 0b000, 0b1001, 0b1010, 0b001), // RW
kPMBSR_EL1 = encode(0b11, 0b000, 0b1001, 0b1010, 0b011), // RW
kPMCCFILTR_EL0 = encode(0b11, 0b011, 0b1110, 0b1111, 0b111), // RW
kPMCCNTR_EL0 = encode(0b11, 0b011, 0b1001, 0b1101, 0b000), // RW
kPMCEID0_EL0 = encode(0b11, 0b011, 0b1001, 0b1100, 0b110), // RO
kPMCEID1_EL0 = encode(0b11, 0b011, 0b1001, 0b1100, 0b111), // RO
kPMCNTENCLR_EL0 = encode(0b11, 0b011, 0b1001, 0b1100, 0b010), // RW
kPMCNTENSET_EL0 = encode(0b11, 0b011, 0b1001, 0b1100, 0b001), // RW
kPMCR_EL0 = encode(0b11, 0b011, 0b1001, 0b1100, 0b000), // RW
kPMEVCNTR0_EL0 = encode(0b11, 0b011, 0b1110, 0b1000, 0b000), // RW
kPMEVCNTR10_EL0 = encode(0b11, 0b011, 0b1110, 0b1001, 0b010), // RW
kPMEVCNTR11_EL0 = encode(0b11, 0b011, 0b1110, 0b1001, 0b011), // RW
kPMEVCNTR12_EL0 = encode(0b11, 0b011, 0b1110, 0b1001, 0b100), // RW
kPMEVCNTR13_EL0 = encode(0b11, 0b011, 0b1110, 0b1001, 0b101), // RW
kPMEVCNTR14_EL0 = encode(0b11, 0b011, 0b1110, 0b1001, 0b110), // RW
kPMEVCNTR15_EL0 = encode(0b11, 0b011, 0b1110, 0b1001, 0b111), // RW
kPMEVCNTR16_EL0 = encode(0b11, 0b011, 0b1110, 0b1010, 0b000), // RW
kPMEVCNTR17_EL0 = encode(0b11, 0b011, 0b1110, 0b1010, 0b001), // RW
kPMEVCNTR18_EL0 = encode(0b11, 0b011, 0b1110, 0b1010, 0b010), // RW
kPMEVCNTR19_EL0 = encode(0b11, 0b011, 0b1110, 0b1010, 0b011), // RW
kPMEVCNTR1_EL0 = encode(0b11, 0b011, 0b1110, 0b1000, 0b001), // RW
kPMEVCNTR20_EL0 = encode(0b11, 0b011, 0b1110, 0b1010, 0b100), // RW
kPMEVCNTR21_EL0 = encode(0b11, 0b011, 0b1110, 0b1010, 0b101), // RW
kPMEVCNTR22_EL0 = encode(0b11, 0b011, 0b1110, 0b1010, 0b110), // RW
kPMEVCNTR23_EL0 = encode(0b11, 0b011, 0b1110, 0b1010, 0b111), // RW
kPMEVCNTR24_EL0 = encode(0b11, 0b011, 0b1110, 0b1011, 0b000), // RW
kPMEVCNTR25_EL0 = encode(0b11, 0b011, 0b1110, 0b1011, 0b001), // RW
kPMEVCNTR26_EL0 = encode(0b11, 0b011, 0b1110, 0b1011, 0b010), // RW
kPMEVCNTR27_EL0 = encode(0b11, 0b011, 0b1110, 0b1011, 0b011), // RW
kPMEVCNTR28_EL0 = encode(0b11, 0b011, 0b1110, 0b1011, 0b100), // RW
kPMEVCNTR29_EL0 = encode(0b11, 0b011, 0b1110, 0b1011, 0b101), // RW
kPMEVCNTR2_EL0 = encode(0b11, 0b011, 0b1110, 0b1000, 0b010), // RW
kPMEVCNTR30_EL0 = encode(0b11, 0b011, 0b1110, 0b1011, 0b110), // RW
kPMEVCNTR3_EL0 = encode(0b11, 0b011, 0b1110, 0b1000, 0b011), // RW
kPMEVCNTR4_EL0 = encode(0b11, 0b011, 0b1110, 0b1000, 0b100), // RW
kPMEVCNTR5_EL0 = encode(0b11, 0b011, 0b1110, 0b1000, 0b101), // RW
kPMEVCNTR6_EL0 = encode(0b11, 0b011, 0b1110, 0b1000, 0b110), // RW
kPMEVCNTR7_EL0 = encode(0b11, 0b011, 0b1110, 0b1000, 0b111), // RW
kPMEVCNTR8_EL0 = encode(0b11, 0b011, 0b1110, 0b1001, 0b000), // RW
kPMEVCNTR9_EL0 = encode(0b11, 0b011, 0b1110, 0b1001, 0b001), // RW
kPMEVTYPER0_EL0 = encode(0b11, 0b011, 0b1110, 0b1100, 0b000), // RW
kPMEVTYPER10_EL0 = encode(0b11, 0b011, 0b1110, 0b1101, 0b010), // RW
kPMEVTYPER11_EL0 = encode(0b11, 0b011, 0b1110, 0b1101, 0b011), // RW
kPMEVTYPER12_EL0 = encode(0b11, 0b011, 0b1110, 0b1101, 0b100), // RW
kPMEVTYPER13_EL0 = encode(0b11, 0b011, 0b1110, 0b1101, 0b101), // RW
kPMEVTYPER14_EL0 = encode(0b11, 0b011, 0b1110, 0b1101, 0b110), // RW
kPMEVTYPER15_EL0 = encode(0b11, 0b011, 0b1110, 0b1101, 0b111), // RW
kPMEVTYPER16_EL0 = encode(0b11, 0b011, 0b1110, 0b1110, 0b000), // RW
kPMEVTYPER17_EL0 = encode(0b11, 0b011, 0b1110, 0b1110, 0b001), // RW
kPMEVTYPER18_EL0 = encode(0b11, 0b011, 0b1110, 0b1110, 0b010), // RW
kPMEVTYPER19_EL0 = encode(0b11, 0b011, 0b1110, 0b1110, 0b011), // RW
kPMEVTYPER1_EL0 = encode(0b11, 0b011, 0b1110, 0b1100, 0b001), // RW
kPMEVTYPER20_EL0 = encode(0b11, 0b011, 0b1110, 0b1110, 0b100), // RW
kPMEVTYPER21_EL0 = encode(0b11, 0b011, 0b1110, 0b1110, 0b101), // RW
kPMEVTYPER22_EL0 = encode(0b11, 0b011, 0b1110, 0b1110, 0b110), // RW
kPMEVTYPER23_EL0 = encode(0b11, 0b011, 0b1110, 0b1110, 0b111), // RW
kPMEVTYPER24_EL0 = encode(0b11, 0b011, 0b1110, 0b1111, 0b000), // RW
kPMEVTYPER25_EL0 = encode(0b11, 0b011, 0b1110, 0b1111, 0b001), // RW
kPMEVTYPER26_EL0 = encode(0b11, 0b011, 0b1110, 0b1111, 0b010), // RW
kPMEVTYPER27_EL0 = encode(0b11, 0b011, 0b1110, 0b1111, 0b011), // RW
kPMEVTYPER28_EL0 = encode(0b11, 0b011, 0b1110, 0b1111, 0b100), // RW
kPMEVTYPER29_EL0 = encode(0b11, 0b011, 0b1110, 0b1111, 0b101), // RW
kPMEVTYPER2_EL0 = encode(0b11, 0b011, 0b1110, 0b1100, 0b010), // RW
kPMEVTYPER30_EL0 = encode(0b11, 0b011, 0b1110, 0b1111, 0b110), // RW
kPMEVTYPER3_EL0 = encode(0b11, 0b011, 0b1110, 0b1100, 0b011), // RW
kPMEVTYPER4_EL0 = encode(0b11, 0b011, 0b1110, 0b1100, 0b100), // RW
kPMEVTYPER5_EL0 = encode(0b11, 0b011, 0b1110, 0b1100, 0b101), // RW
kPMEVTYPER6_EL0 = encode(0b11, 0b011, 0b1110, 0b1100, 0b110), // RW
kPMEVTYPER7_EL0 = encode(0b11, 0b011, 0b1110, 0b1100, 0b111), // RW
kPMEVTYPER8_EL0 = encode(0b11, 0b011, 0b1110, 0b1101, 0b000), // RW
kPMEVTYPER9_EL0 = encode(0b11, 0b011, 0b1110, 0b1101, 0b001), // RW
kPMINTENCLR_EL1 = encode(0b11, 0b000, 0b1001, 0b1110, 0b010), // RW
kPMINTENSET_EL1 = encode(0b11, 0b000, 0b1001, 0b1110, 0b001), // RW
kPMMIR_EL1 = encode(0b11, 0b000, 0b1001, 0b1110, 0b110), // RW
kPMOVSCLR_EL0 = encode(0b11, 0b011, 0b1001, 0b1100, 0b011), // RW
kPMOVSSET_EL0 = encode(0b11, 0b011, 0b1001, 0b1110, 0b011), // RW
kPMSCR_EL1 = encode(0b11, 0b000, 0b1001, 0b1001, 0b000), // RW
kPMSCR_EL12 = encode(0b11, 0b101, 0b1001, 0b1001, 0b000), // RW
kPMSCR_EL2 = encode(0b11, 0b100, 0b1001, 0b1001, 0b000), // RW
kPMSELR_EL0 = encode(0b11, 0b011, 0b1001, 0b1100, 0b101), // RW
kPMSEVFR_EL1 = encode(0b11, 0b000, 0b1001, 0b1001, 0b101), // RW
kPMSFCR_EL1 = encode(0b11, 0b000, 0b1001, 0b1001, 0b100), // RW
kPMSICR_EL1 = encode(0b11, 0b000, 0b1001, 0b1001, 0b010), // RW
kPMSIDR_EL1 = encode(0b11, 0b000, 0b1001, 0b1001, 0b111), // RO
kPMSIRR_EL1 = encode(0b11, 0b000, 0b1001, 0b1001, 0b011), // RW
kPMSLATFR_EL1 = encode(0b11, 0b000, 0b1001, 0b1001, 0b110), // RW
kPMSWINC_EL0 = encode(0b11, 0b011, 0b1001, 0b1100, 0b100), // WO
kPMUSERENR_EL0 = encode(0b11, 0b011, 0b1001, 0b1110, 0b000), // RW
kPMXEVCNTR_EL0 = encode(0b11, 0b011, 0b1001, 0b1101, 0b010), // RW
kPMXEVTYPER_EL0 = encode(0b11, 0b011, 0b1001, 0b1101, 0b001), // RW
kREVIDR_EL1 = encode(0b11, 0b000, 0b0000, 0b0000, 0b110), // RO
kRGSR_EL1 = encode(0b11, 0b000, 0b0001, 0b0000, 0b101), // RW
kRMR_EL1 = encode(0b11, 0b000, 0b1100, 0b0000, 0b010), // RW
kRMR_EL2 = encode(0b11, 0b100, 0b1100, 0b0000, 0b010), // RW
kRMR_EL3 = encode(0b11, 0b110, 0b1100, 0b0000, 0b010), // RW
kRNDR = encode(0b11, 0b011, 0b0010, 0b0100, 0b000), // RO
kRNDRRS = encode(0b11, 0b011, 0b0010, 0b0100, 0b001), // RO
kRVBAR_EL1 = encode(0b11, 0b000, 0b1100, 0b0000, 0b001), // RO
kRVBAR_EL2 = encode(0b11, 0b100, 0b1100, 0b0000, 0b001), // RO
kRVBAR_EL3 = encode(0b11, 0b110, 0b1100, 0b0000, 0b001), // RO
kSCR_EL3 = encode(0b11, 0b110, 0b0001, 0b0001, 0b000), // RW
kSCTLR_EL1 = encode(0b11, 0b000, 0b0001, 0b0000, 0b000), // RW
kSCTLR_EL12 = encode(0b11, 0b101, 0b0001, 0b0000, 0b000), // RW
kSCTLR_EL2 = encode(0b11, 0b100, 0b0001, 0b0000, 0b000), // RW
kSCTLR_EL3 = encode(0b11, 0b110, 0b0001, 0b0000, 0b000), // RW
kSCXTNUM_EL0 = encode(0b11, 0b011, 0b1101, 0b0000, 0b111), // RW
kSCXTNUM_EL1 = encode(0b11, 0b000, 0b1101, 0b0000, 0b111), // RW
kSCXTNUM_EL12 = encode(0b11, 0b101, 0b1101, 0b0000, 0b111), // RW
kSCXTNUM_EL2 = encode(0b11, 0b100, 0b1101, 0b0000, 0b111), // RW
kSCXTNUM_EL3 = encode(0b11, 0b110, 0b1101, 0b0000, 0b111), // RW
kSDER32_EL2 = encode(0b11, 0b100, 0b0001, 0b0011, 0b001), // RW
kSDER32_EL3 = encode(0b11, 0b110, 0b0001, 0b0001, 0b001), // RW
kSPSR_EL1 = encode(0b11, 0b000, 0b0100, 0b0000, 0b000), // RW
kSPSR_EL12 = encode(0b11, 0b101, 0b0100, 0b0000, 0b000), // RW
kSPSR_EL2 = encode(0b11, 0b100, 0b0100, 0b0000, 0b000), // RW
kSPSR_EL3 = encode(0b11, 0b110, 0b0100, 0b0000, 0b000), // RW
kSPSR_abt = encode(0b11, 0b100, 0b0100, 0b0011, 0b001), // RW
kSPSR_fiq = encode(0b11, 0b100, 0b0100, 0b0011, 0b011), // RW
kSPSR_irq = encode(0b11, 0b100, 0b0100, 0b0011, 0b000), // RW
kSPSR_und = encode(0b11, 0b100, 0b0100, 0b0011, 0b010), // RW
kSPSel = encode(0b11, 0b000, 0b0100, 0b0010, 0b000), // RW
kSP_EL0 = encode(0b11, 0b000, 0b0100, 0b0001, 0b000), // RW
kSP_EL1 = encode(0b11, 0b100, 0b0100, 0b0001, 0b000), // RW
kSP_EL2 = encode(0b11, 0b110, 0b0100, 0b0001, 0b000), // RW
kSSBS = encode(0b11, 0b011, 0b0100, 0b0010, 0b110), // RW
kTCO = encode(0b11, 0b011, 0b0100, 0b0010, 0b111), // RW
kTCR_EL1 = encode(0b11, 0b000, 0b0010, 0b0000, 0b010), // RW
kTCR_EL12 = encode(0b11, 0b101, 0b0010, 0b0000, 0b010), // RW
kTCR_EL2 = encode(0b11, 0b100, 0b0010, 0b0000, 0b010), // RW
kTCR_EL3 = encode(0b11, 0b110, 0b0010, 0b0000, 0b010), // RW
kTEECR32_EL1 = encode(0b10, 0b010, 0b0000, 0b0000, 0b000), // RW
kTEEHBR32_EL1 = encode(0b10, 0b010, 0b0001, 0b0000, 0b000), // RW
kTFSRE0_EL1 = encode(0b11, 0b000, 0b0101, 0b0110, 0b001), // RW
kTFSR_EL1 = encode(0b11, 0b000, 0b0101, 0b0110, 0b000), // RW
kTFSR_EL12 = encode(0b11, 0b101, 0b0101, 0b0110, 0b000), // RW
kTFSR_EL2 = encode(0b11, 0b100, 0b0101, 0b0110, 0b000), // RW
kTFSR_EL3 = encode(0b11, 0b110, 0b0101, 0b0110, 0b000), // RW
kTPIDRRO_EL0 = encode(0b11, 0b011, 0b1101, 0b0000, 0b011), // RW
kTPIDR_EL0 = encode(0b11, 0b011, 0b1101, 0b0000, 0b010), // RW
kTPIDR_EL1 = encode(0b11, 0b000, 0b1101, 0b0000, 0b100), // RW
kTPIDR_EL2 = encode(0b11, 0b100, 0b1101, 0b0000, 0b010), // RW
kTPIDR_EL3 = encode(0b11, 0b110, 0b1101, 0b0000, 0b010), // RW
kTRBBASER_EL1 = encode(0b11, 0b000, 0b1001, 0b1011, 0b010), // RW
kTRBIDR_EL1 = encode(0b11, 0b000, 0b1001, 0b1011, 0b111), // RO
kTRBLIMITR_EL1 = encode(0b11, 0b000, 0b1001, 0b1011, 0b000), // RW
kTRBMAR_EL1 = encode(0b11, 0b000, 0b1001, 0b1011, 0b100), // RW
kTRBPTR_EL1 = encode(0b11, 0b000, 0b1001, 0b1011, 0b001), // RW
kTRBSR_EL1 = encode(0b11, 0b000, 0b1001, 0b1011, 0b011), // RW
kTRBTRG_EL1 = encode(0b11, 0b000, 0b1001, 0b1011, 0b110), // RW
kTRCACATR0 = encode(0b10, 0b001, 0b0010, 0b0000, 0b010), // RW
kTRCACATR1 = encode(0b10, 0b001, 0b0010, 0b0010, 0b010), // RW
kTRCACATR10 = encode(0b10, 0b001, 0b0010, 0b0100, 0b011), // RW
kTRCACATR11 = encode(0b10, 0b001, 0b0010, 0b0110, 0b011), // RW
kTRCACATR12 = encode(0b10, 0b001, 0b0010, 0b1000, 0b011), // RW
kTRCACATR13 = encode(0b10, 0b001, 0b0010, 0b1010, 0b011), // RW
kTRCACATR14 = encode(0b10, 0b001, 0b0010, 0b1100, 0b011), // RW
kTRCACATR15 = encode(0b10, 0b001, 0b0010, 0b1110, 0b011), // RW
kTRCACATR2 = encode(0b10, 0b001, 0b0010, 0b0100, 0b010), // RW
kTRCACATR3 = encode(0b10, 0b001, 0b0010, 0b0110, 0b010), // RW
kTRCACATR4 = encode(0b10, 0b001, 0b0010, 0b1000, 0b010), // RW
kTRCACATR5 = encode(0b10, 0b001, 0b0010, 0b1010, 0b010), // RW
kTRCACATR6 = encode(0b10, 0b001, 0b0010, 0b1100, 0b010), // RW
kTRCACATR7 = encode(0b10, 0b001, 0b0010, 0b1110, 0b010), // RW
kTRCACATR8 = encode(0b10, 0b001, 0b0010, 0b0000, 0b011), // RW
kTRCACATR9 = encode(0b10, 0b001, 0b0010, 0b0010, 0b011), // RW
kTRCACVR0 = encode(0b10, 0b001, 0b0010, 0b0000, 0b000), // RW
kTRCACVR1 = encode(0b10, 0b001, 0b0010, 0b0010, 0b000), // RW
kTRCACVR10 = encode(0b10, 0b001, 0b0010, 0b0100, 0b001), // RW
kTRCACVR11 = encode(0b10, 0b001, 0b0010, 0b0110, 0b001), // RW
kTRCACVR12 = encode(0b10, 0b001, 0b0010, 0b1000, 0b001), // RW
kTRCACVR13 = encode(0b10, 0b001, 0b0010, 0b1010, 0b001), // RW
kTRCACVR14 = encode(0b10, 0b001, 0b0010, 0b1100, 0b001), // RW
kTRCACVR15 = encode(0b10, 0b001, 0b0010, 0b1110, 0b001), // RW
kTRCACVR2 = encode(0b10, 0b001, 0b0010, 0b0100, 0b000), // RW
kTRCACVR3 = encode(0b10, 0b001, 0b0010, 0b0110, 0b000), // RW
kTRCACVR4 = encode(0b10, 0b001, 0b0010, 0b1000, 0b000), // RW
kTRCACVR5 = encode(0b10, 0b001, 0b0010, 0b1010, 0b000), // RW
kTRCACVR6 = encode(0b10, 0b001, 0b0010, 0b1100, 0b000), // RW
kTRCACVR7 = encode(0b10, 0b001, 0b0010, 0b1110, 0b000), // RW
kTRCACVR8 = encode(0b10, 0b001, 0b0010, 0b0000, 0b001), // RW
kTRCACVR9 = encode(0b10, 0b001, 0b0010, 0b0010, 0b001), // RW
kTRCAUTHSTATUS = encode(0b10, 0b001, 0b0111, 0b1110, 0b110), // RO
kTRCAUXCTLR = encode(0b10, 0b001, 0b0000, 0b0110, 0b000), // RW
kTRCBBCTLR = encode(0b10, 0b001, 0b0000, 0b1111, 0b000), // RW
kTRCCCCTLR = encode(0b10, 0b001, 0b0000, 0b1110, 0b000), // RW
kTRCCIDCCTLR0 = encode(0b10, 0b001, 0b0011, 0b0000, 0b010), // RW
kTRCCIDCCTLR1 = encode(0b10, 0b001, 0b0011, 0b0001, 0b010), // RW
kTRCCIDCVR0 = encode(0b10, 0b001, 0b0011, 0b0000, 0b000), // RW
kTRCCIDCVR1 = encode(0b10, 0b001, 0b0011, 0b0010, 0b000), // RW
kTRCCIDCVR2 = encode(0b10, 0b001, 0b0011, 0b0100, 0b000), // RW
kTRCCIDCVR3 = encode(0b10, 0b001, 0b0011, 0b0110, 0b000), // RW
kTRCCIDCVR4 = encode(0b10, 0b001, 0b0011, 0b1000, 0b000), // RW
kTRCCIDCVR5 = encode(0b10, 0b001, 0b0011, 0b1010, 0b000), // RW
kTRCCIDCVR6 = encode(0b10, 0b001, 0b0011, 0b1100, 0b000), // RW
kTRCCIDCVR7 = encode(0b10, 0b001, 0b0011, 0b1110, 0b000), // RW
kTRCCIDR0 = encode(0b10, 0b001, 0b0111, 0b1100, 0b111), // RO
kTRCCIDR1 = encode(0b10, 0b001, 0b0111, 0b1101, 0b111), // RO
kTRCCIDR2 = encode(0b10, 0b001, 0b0111, 0b1110, 0b111), // RO
kTRCCIDR3 = encode(0b10, 0b001, 0b0111, 0b1111, 0b111), // RO
kTRCCLAIMCLR = encode(0b10, 0b001, 0b0111, 0b1001, 0b110), // RW
kTRCCLAIMSET = encode(0b10, 0b001, 0b0111, 0b1000, 0b110), // RW
kTRCCNTCTLR0 = encode(0b10, 0b001, 0b0000, 0b0100, 0b101), // RW
kTRCCNTCTLR1 = encode(0b10, 0b001, 0b0000, 0b0101, 0b101), // RW
kTRCCNTCTLR2 = encode(0b10, 0b001, 0b0000, 0b0110, 0b101), // RW
kTRCCNTCTLR3 = encode(0b10, 0b001, 0b0000, 0b0111, 0b101), // RW
kTRCCNTRLDVR0 = encode(0b10, 0b001, 0b0000, 0b0000, 0b101), // RW
kTRCCNTRLDVR1 = encode(0b10, 0b001, 0b0000, 0b0001, 0b101), // RW
kTRCCNTRLDVR2 = encode(0b10, 0b001, 0b0000, 0b0010, 0b101), // RW
kTRCCNTRLDVR3 = encode(0b10, 0b001, 0b0000, 0b0011, 0b101), // RW
kTRCCNTVR0 = encode(0b10, 0b001, 0b0000, 0b1000, 0b101), // RW
kTRCCNTVR1 = encode(0b10, 0b001, 0b0000, 0b1001, 0b101), // RW
kTRCCNTVR2 = encode(0b10, 0b001, 0b0000, 0b1010, 0b101), // RW
kTRCCNTVR3 = encode(0b10, 0b001, 0b0000, 0b1011, 0b101), // RW
kTRCCONFIGR = encode(0b10, 0b001, 0b0000, 0b0100, 0b000), // RW
kTRCDEVAFF0 = encode(0b10, 0b001, 0b0111, 0b1010, 0b110), // RO
kTRCDEVAFF1 = encode(0b10, 0b001, 0b0111, 0b1011, 0b110), // RO
kTRCDEVARCH = encode(0b10, 0b001, 0b0111, 0b1111, 0b110), // RO
kTRCDEVID = encode(0b10, 0b001, 0b0111, 0b0010, 0b111), // RO
kTRCDEVTYPE = encode(0b10, 0b001, 0b0111, 0b0011, 0b111), // RO
kTRCDVCMR0 = encode(0b10, 0b001, 0b0010, 0b0000, 0b110), // RW
kTRCDVCMR1 = encode(0b10, 0b001, 0b0010, 0b0100, 0b110), // RW
kTRCDVCMR2 = encode(0b10, 0b001, 0b0010, 0b1000, 0b110), // RW
kTRCDVCMR3 = encode(0b10, 0b001, 0b0010, 0b1100, 0b110), // RW
kTRCDVCMR4 = encode(0b10, 0b001, 0b0010, 0b0000, 0b111), // RW
kTRCDVCMR5 = encode(0b10, 0b001, 0b0010, 0b0100, 0b111), // RW
kTRCDVCMR6 = encode(0b10, 0b001, 0b0010, 0b1000, 0b111), // RW
kTRCDVCMR7 = encode(0b10, 0b001, 0b0010, 0b1100, 0b111), // RW
kTRCDVCVR0 = encode(0b10, 0b001, 0b0010, 0b0000, 0b100), // RW
kTRCDVCVR1 = encode(0b10, 0b001, 0b0010, 0b0100, 0b100), // RW
kTRCDVCVR2 = encode(0b10, 0b001, 0b0010, 0b1000, 0b100), // RW
kTRCDVCVR3 = encode(0b10, 0b001, 0b0010, 0b1100, 0b100), // RW
kTRCDVCVR4 = encode(0b10, 0b001, 0b0010, 0b0000, 0b101), // RW
kTRCDVCVR5 = encode(0b10, 0b001, 0b0010, 0b0100, 0b101), // RW
kTRCDVCVR6 = encode(0b10, 0b001, 0b0010, 0b1000, 0b101), // RW
kTRCDVCVR7 = encode(0b10, 0b001, 0b0010, 0b1100, 0b101), // RW
kTRCEVENTCTL0R = encode(0b10, 0b001, 0b0000, 0b1000, 0b000), // RW
kTRCEVENTCTL1R = encode(0b10, 0b001, 0b0000, 0b1001, 0b000), // RW
kTRCEXTINSELR = encode(0b10, 0b001, 0b0000, 0b1000, 0b100), // RW
kTRCEXTINSELR0 = encode(0b10, 0b001, 0b0000, 0b1000, 0b100), // RW
kTRCEXTINSELR1 = encode(0b10, 0b001, 0b0000, 0b1001, 0b100), // RW
kTRCEXTINSELR2 = encode(0b10, 0b001, 0b0000, 0b1010, 0b100), // RW
kTRCEXTINSELR3 = encode(0b10, 0b001, 0b0000, 0b1011, 0b100), // RW
kTRCIDR0 = encode(0b10, 0b001, 0b0000, 0b1000, 0b111), // RO
kTRCIDR1 = encode(0b10, 0b001, 0b0000, 0b1001, 0b111), // RO
kTRCIDR10 = encode(0b10, 0b001, 0b0000, 0b0010, 0b110), // RO
kTRCIDR11 = encode(0b10, 0b001, 0b0000, 0b0011, 0b110), // RO
kTRCIDR12 = encode(0b10, 0b001, 0b0000, 0b0100, 0b110), // RO
kTRCIDR13 = encode(0b10, 0b001, 0b0000, 0b0101, 0b110), // RO
kTRCIDR2 = encode(0b10, 0b001, 0b0000, 0b1010, 0b111), // RO
kTRCIDR3 = encode(0b10, 0b001, 0b0000, 0b1011, 0b111), // RO
kTRCIDR4 = encode(0b10, 0b001, 0b0000, 0b1100, 0b111), // RO
kTRCIDR5 = encode(0b10, 0b001, 0b0000, 0b1101, 0b111), // RO
kTRCIDR6 = encode(0b10, 0b001, 0b0000, 0b1110, 0b111), // RO
kTRCIDR7 = encode(0b10, 0b001, 0b0000, 0b1111, 0b111), // RO
kTRCIDR8 = encode(0b10, 0b001, 0b0000, 0b0000, 0b110), // RO
kTRCIDR9 = encode(0b10, 0b001, 0b0000, 0b0001, 0b110), // RO
kTRCIMSPEC0 = encode(0b10, 0b001, 0b0000, 0b0000, 0b111), // RW
kTRCIMSPEC1 = encode(0b10, 0b001, 0b0000, 0b0001, 0b111), // RW
kTRCIMSPEC2 = encode(0b10, 0b001, 0b0000, 0b0010, 0b111), // RW
kTRCIMSPEC3 = encode(0b10, 0b001, 0b0000, 0b0011, 0b111), // RW
kTRCIMSPEC4 = encode(0b10, 0b001, 0b0000, 0b0100, 0b111), // RW
kTRCIMSPEC5 = encode(0b10, 0b001, 0b0000, 0b0101, 0b111), // RW
kTRCIMSPEC6 = encode(0b10, 0b001, 0b0000, 0b0110, 0b111), // RW
kTRCIMSPEC7 = encode(0b10, 0b001, 0b0000, 0b0111, 0b111), // RW
kTRCITCTRL = encode(0b10, 0b001, 0b0111, 0b0000, 0b100), // RW
kTRCLAR = encode(0b10, 0b001, 0b0111, 0b1100, 0b110), // WO
kTRCLSR = encode(0b10, 0b001, 0b0111, 0b1101, 0b110), // RO
kTRCOSLAR = encode(0b10, 0b001, 0b0001, 0b0000, 0b100), // WO
kTRCOSLSR = encode(0b10, 0b001, 0b0001, 0b0001, 0b100), // RO
kTRCPDCR = encode(0b10, 0b001, 0b0001, 0b0100, 0b100), // RW
kTRCPDSR = encode(0b10, 0b001, 0b0001, 0b0101, 0b100), // RO
kTRCPIDR0 = encode(0b10, 0b001, 0b0111, 0b1000, 0b111), // RO
kTRCPIDR1 = encode(0b10, 0b001, 0b0111, 0b1001, 0b111), // RO
kTRCPIDR2 = encode(0b10, 0b001, 0b0111, 0b1010, 0b111), // RO
kTRCPIDR3 = encode(0b10, 0b001, 0b0111, 0b1011, 0b111), // RO
kTRCPIDR4 = encode(0b10, 0b001, 0b0111, 0b0100, 0b111), // RO
kTRCPIDR5 = encode(0b10, 0b001, 0b0111, 0b0101, 0b111), // RO
kTRCPIDR6 = encode(0b10, 0b001, 0b0111, 0b0110, 0b111), // RO
kTRCPIDR7 = encode(0b10, 0b001, 0b0111, 0b0111, 0b111), // RO
kTRCPRGCTLR = encode(0b10, 0b001, 0b0000, 0b0001, 0b000), // RW
kTRCPROCSELR = encode(0b10, 0b001, 0b0000, 0b0010, 0b000), // RW
kTRCQCTLR = encode(0b10, 0b001, 0b0000, 0b0001, 0b001), // RW
kTRCRSCTLR10 = encode(0b10, 0b001, 0b0001, 0b1010, 0b000), // RW
kTRCRSCTLR11 = encode(0b10, 0b001, 0b0001, 0b1011, 0b000), // RW
kTRCRSCTLR12 = encode(0b10, 0b001, 0b0001, 0b1100, 0b000), // RW
kTRCRSCTLR13 = encode(0b10, 0b001, 0b0001, 0b1101, 0b000), // RW
kTRCRSCTLR14 = encode(0b10, 0b001, 0b0001, 0b1110, 0b000), // RW
kTRCRSCTLR15 = encode(0b10, 0b001, 0b0001, 0b1111, 0b000), // RW
kTRCRSCTLR16 = encode(0b10, 0b001, 0b0001, 0b0000, 0b001), // RW
kTRCRSCTLR17 = encode(0b10, 0b001, 0b0001, 0b0001, 0b001), // RW
kTRCRSCTLR18 = encode(0b10, 0b001, 0b0001, 0b0010, 0b001), // RW
kTRCRSCTLR19 = encode(0b10, 0b001, 0b0001, 0b0011, 0b001), // RW
kTRCRSCTLR2 = encode(0b10, 0b001, 0b0001, 0b0010, 0b000), // RW
kTRCRSCTLR20 = encode(0b10, 0b001, 0b0001, 0b0100, 0b001), // RW
kTRCRSCTLR21 = encode(0b10, 0b001, 0b0001, 0b0101, 0b001), // RW
kTRCRSCTLR22 = encode(0b10, 0b001, 0b0001, 0b0110, 0b001), // RW
kTRCRSCTLR23 = encode(0b10, 0b001, 0b0001, 0b0111, 0b001), // RW
kTRCRSCTLR24 = encode(0b10, 0b001, 0b0001, 0b1000, 0b001), // RW
kTRCRSCTLR25 = encode(0b10, 0b001, 0b0001, 0b1001, 0b001), // RW
kTRCRSCTLR26 = encode(0b10, 0b001, 0b0001, 0b1010, 0b001), // RW
kTRCRSCTLR27 = encode(0b10, 0b001, 0b0001, 0b1011, 0b001), // RW
kTRCRSCTLR28 = encode(0b10, 0b001, 0b0001, 0b1100, 0b001), // RW
kTRCRSCTLR29 = encode(0b10, 0b001, 0b0001, 0b1101, 0b001), // RW
kTRCRSCTLR3 = encode(0b10, 0b001, 0b0001, 0b0011, 0b000), // RW
kTRCRSCTLR30 = encode(0b10, 0b001, 0b0001, 0b1110, 0b001), // RW
kTRCRSCTLR31 = encode(0b10, 0b001, 0b0001, 0b1111, 0b001), // RW
kTRCRSCTLR4 = encode(0b10, 0b001, 0b0001, 0b0100, 0b000), // RW
kTRCRSCTLR5 = encode(0b10, 0b001, 0b0001, 0b0101, 0b000), // RW
kTRCRSCTLR6 = encode(0b10, 0b001, 0b0001, 0b0110, 0b000), // RW
kTRCRSCTLR7 = encode(0b10, 0b001, 0b0001, 0b0111, 0b000), // RW
kTRCRSCTLR8 = encode(0b10, 0b001, 0b0001, 0b1000, 0b000), // RW
kTRCRSCTLR9 = encode(0b10, 0b001, 0b0001, 0b1001, 0b000), // RW
kTRCRSR = encode(0b10, 0b001, 0b0000, 0b1010, 0b000), // RW
kTRCSEQEVR0 = encode(0b10, 0b001, 0b0000, 0b0000, 0b100), // RW
kTRCSEQEVR1 = encode(0b10, 0b001, 0b0000, 0b0001, 0b100), // RW
kTRCSEQEVR2 = encode(0b10, 0b001, 0b0000, 0b0010, 0b100), // RW
kTRCSEQRSTEVR = encode(0b10, 0b001, 0b0000, 0b0110, 0b100), // RW
kTRCSEQSTR = encode(0b10, 0b001, 0b0000, 0b0111, 0b100), // RW
kTRCSSCCR0 = encode(0b10, 0b001, 0b0001, 0b0000, 0b010), // RW
kTRCSSCCR1 = encode(0b10, 0b001, 0b0001, 0b0001, 0b010), // RW
kTRCSSCCR2 = encode(0b10, 0b001, 0b0001, 0b0010, 0b010), // RW
kTRCSSCCR3 = encode(0b10, 0b001, 0b0001, 0b0011, 0b010), // RW
kTRCSSCCR4 = encode(0b10, 0b001, 0b0001, 0b0100, 0b010), // RW
kTRCSSCCR5 = encode(0b10, 0b001, 0b0001, 0b0101, 0b010), // RW
kTRCSSCCR6 = encode(0b10, 0b001, 0b0001, 0b0110, 0b010), // RW
kTRCSSCCR7 = encode(0b10, 0b001, 0b0001, 0b0111, 0b010), // RW
kTRCSSCSR0 = encode(0b10, 0b001, 0b0001, 0b1000, 0b010), // RW
kTRCSSCSR1 = encode(0b10, 0b001, 0b0001, 0b1001, 0b010), // RW
kTRCSSCSR2 = encode(0b10, 0b001, 0b0001, 0b1010, 0b010), // RW
kTRCSSCSR3 = encode(0b10, 0b001, 0b0001, 0b1011, 0b010), // RW
kTRCSSCSR4 = encode(0b10, 0b001, 0b0001, 0b1100, 0b010), // RW
kTRCSSCSR5 = encode(0b10, 0b001, 0b0001, 0b1101, 0b010), // RW
kTRCSSCSR6 = encode(0b10, 0b001, 0b0001, 0b1110, 0b010), // RW
kTRCSSCSR7 = encode(0b10, 0b001, 0b0001, 0b1111, 0b010), // RW
kTRCSSPCICR0 = encode(0b10, 0b001, 0b0001, 0b0000, 0b011), // RW
kTRCSSPCICR1 = encode(0b10, 0b001, 0b0001, 0b0001, 0b011), // RW
kTRCSSPCICR2 = encode(0b10, 0b001, 0b0001, 0b0010, 0b011), // RW
kTRCSSPCICR3 = encode(0b10, 0b001, 0b0001, 0b0011, 0b011), // RW
kTRCSSPCICR4 = encode(0b10, 0b001, 0b0001, 0b0100, 0b011), // RW
kTRCSSPCICR5 = encode(0b10, 0b001, 0b0001, 0b0101, 0b011), // RW
kTRCSSPCICR6 = encode(0b10, 0b001, 0b0001, 0b0110, 0b011), // RW
kTRCSSPCICR7 = encode(0b10, 0b001, 0b0001, 0b0111, 0b011), // RW
kTRCSTALLCTLR = encode(0b10, 0b001, 0b0000, 0b1011, 0b000), // RW
kTRCSTATR = encode(0b10, 0b001, 0b0000, 0b0011, 0b000), // RO
kTRCSYNCPR = encode(0b10, 0b001, 0b0000, 0b1101, 0b000), // RW
kTRCTRACEIDR = encode(0b10, 0b001, 0b0000, 0b0000, 0b001), // RW
kTRCTSCTLR = encode(0b10, 0b001, 0b0000, 0b1100, 0b000), // RW
kTRCVDARCCTLR = encode(0b10, 0b001, 0b0000, 0b1010, 0b010), // RW
kTRCVDCTLR = encode(0b10, 0b001, 0b0000, 0b1000, 0b010), // RW
kTRCVDSACCTLR = encode(0b10, 0b001, 0b0000, 0b1001, 0b010), // RW
kTRCVICTLR = encode(0b10, 0b001, 0b0000, 0b0000, 0b010), // RW
kTRCVIIECTLR = encode(0b10, 0b001, 0b0000, 0b0001, 0b010), // RW
kTRCVIPCSSCTLR = encode(0b10, 0b001, 0b0000, 0b0011, 0b010), // RW
kTRCVISSCTLR = encode(0b10, 0b001, 0b0000, 0b0010, 0b010), // RW
kTRCVMIDCCTLR0 = encode(0b10, 0b001, 0b0011, 0b0010, 0b010), // RW
kTRCVMIDCCTLR1 = encode(0b10, 0b001, 0b0011, 0b0011, 0b010), // RW
kTRCVMIDCVR0 = encode(0b10, 0b001, 0b0011, 0b0000, 0b001), // RW
kTRCVMIDCVR1 = encode(0b10, 0b001, 0b0011, 0b0010, 0b001), // RW
kTRCVMIDCVR2 = encode(0b10, 0b001, 0b0011, 0b0100, 0b001), // RW
kTRCVMIDCVR3 = encode(0b10, 0b001, 0b0011, 0b0110, 0b001), // RW
kTRCVMIDCVR4 = encode(0b10, 0b001, 0b0011, 0b1000, 0b001), // RW
kTRCVMIDCVR5 = encode(0b10, 0b001, 0b0011, 0b1010, 0b001), // RW
kTRCVMIDCVR6 = encode(0b10, 0b001, 0b0011, 0b1100, 0b001), // RW
kTRCVMIDCVR7 = encode(0b10, 0b001, 0b0011, 0b1110, 0b001), // RW
kTRFCR_EL1 = encode(0b11, 0b000, 0b0001, 0b0010, 0b001), // RW
kTRFCR_EL12 = encode(0b11, 0b101, 0b0001, 0b0010, 0b001), // RW
kTRFCR_EL2 = encode(0b11, 0b100, 0b0001, 0b0010, 0b001), // RW
kTTBR0_EL1 = encode(0b11, 0b000, 0b0010, 0b0000, 0b000), // RW
kTTBR0_EL12 = encode(0b11, 0b101, 0b0010, 0b0000, 0b000), // RW
kTTBR0_EL2 = encode(0b11, 0b100, 0b0010, 0b0000, 0b000), // RW
kTTBR0_EL3 = encode(0b11, 0b110, 0b0010, 0b0000, 0b000), // RW
kTTBR1_EL1 = encode(0b11, 0b000, 0b0010, 0b0000, 0b001), // RW
kTTBR1_EL12 = encode(0b11, 0b101, 0b0010, 0b0000, 0b001), // RW
kTTBR1_EL2 = encode(0b11, 0b100, 0b0010, 0b0000, 0b001), // RW
kUAO = encode(0b11, 0b000, 0b0100, 0b0010, 0b100), // RW
kVBAR_EL1 = encode(0b11, 0b000, 0b1100, 0b0000, 0b000), // RW
kVBAR_EL12 = encode(0b11, 0b101, 0b1100, 0b0000, 0b000), // RW
kVBAR_EL2 = encode(0b11, 0b100, 0b1100, 0b0000, 0b000), // RW
kVBAR_EL3 = encode(0b11, 0b110, 0b1100, 0b0000, 0b000), // RW
kVDISR_EL2 = encode(0b11, 0b100, 0b1100, 0b0001, 0b001), // RW
kVMPIDR_EL2 = encode(0b11, 0b100, 0b0000, 0b0000, 0b101), // RW
kVNCR_EL2 = encode(0b11, 0b100, 0b0010, 0b0010, 0b000), // RW
kVPIDR_EL2 = encode(0b11, 0b100, 0b0000, 0b0000, 0b000), // RW
kVSESR_EL2 = encode(0b11, 0b100, 0b0101, 0b0010, 0b011), // RW
kVSTCR_EL2 = encode(0b11, 0b100, 0b0010, 0b0110, 0b010), // RW
kVSTTBR_EL2 = encode(0b11, 0b100, 0b0010, 0b0110, 0b000), // RW
kVTCR_EL2 = encode(0b11, 0b100, 0b0010, 0b0001, 0b010), // RW
kVTTBR_EL2 = encode(0b11, 0b100, 0b0010, 0b0001, 0b000), // RW
kZCR_EL1 = encode(0b11, 0b000, 0b0001, 0b0010, 0b000), // RW
kZCR_EL12 = encode(0b11, 0b101, 0b0001, 0b0010, 0b000), // RW
kZCR_EL2 = encode(0b11, 0b100, 0b0001, 0b0010, 0b000), // RW
kZCR_EL3 = encode(0b11, 0b110, 0b0001, 0b0010, 0b000) // RW
};
};
} // {Predicate}
//! \}
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_A64GLOBALS_H_INCLUDED
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#if !defined(ASMJIT_NO_AARCH64)
#include "../core/cpuinfo.h"
#include "../core/misc_p.h"
#include "../core/support.h"
#include "../arm/a64instapi_p.h"
#include "../arm/a64instdb_p.h"
#include "../arm/a64operand.h"
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
// a64::InstInternal - Text
// ========================
#ifndef ASMJIT_NO_TEXT
Error InstInternal::instIdToString(Arch arch, InstId instId, String& output) noexcept {
uint32_t realId = instId & uint32_t(InstIdParts::kRealId);
DebugUtils::unused(arch);
if (ASMJIT_UNLIKELY(!Inst::isDefinedId(realId)))
return DebugUtils::errored(kErrorInvalidInstruction);
const InstDB::InstInfo& info = InstDB::infoById(realId);
return output.append(InstDB::_nameData + info._nameDataIndex);
}
InstId InstInternal::stringToInstId(Arch arch, const char* s, size_t len) noexcept {
DebugUtils::unused(arch);
if (ASMJIT_UNLIKELY(!s))
return Inst::kIdNone;
if (len == SIZE_MAX)
len = strlen(s);
if (ASMJIT_UNLIKELY(len == 0 || len > InstDB::kMaxNameSize))
return Inst::kIdNone;
uint32_t prefix = uint32_t(s[0]) - 'a';
if (ASMJIT_UNLIKELY(prefix > 'z' - 'a'))
return Inst::kIdNone;
uint32_t index = InstDB::instNameIndex[prefix].start;
if (ASMJIT_UNLIKELY(!index))
return Inst::kIdNone;
const char* nameData = InstDB::_nameData;
const InstDB::InstInfo* table = InstDB::_instInfoTable;
const InstDB::InstInfo* base = table + index;
const InstDB::InstInfo* end = table + InstDB::instNameIndex[prefix].end;
for (size_t lim = (size_t)(end - base); lim != 0; lim >>= 1) {
const InstDB::InstInfo* cur = base + (lim >> 1);
int result = Support::cmpInstName(nameData + cur[0]._nameDataIndex, s, len);
if (result < 0) {
base = cur + 1;
lim--;
continue;
}
if (result > 0)
continue;
return uint32_t((size_t)(cur - table));
}
return Inst::kIdNone;
}
#endif // !ASMJIT_NO_TEXT
// a64::InstInternal - Validate
// ============================
#ifndef ASMJIT_NO_VALIDATION
ASMJIT_FAVOR_SIZE Error InstInternal::validate(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept {
// TODO:
DebugUtils::unused(arch, inst, operands, opCount, validationFlags);
return kErrorOk;
}
#endif // !ASMJIT_NO_VALIDATION
// a64::InstInternal - QueryRWInfo
// ===============================
#ifndef ASMJIT_NO_INTROSPECTION
struct InstRWInfoData {
uint8_t rwx[Globals::kMaxOpCount];
};
static const InstRWInfoData instRWInfoData[] = {
#define R uint8_t(OpRWFlags::kRead)
#define W uint8_t(OpRWFlags::kWrite)
#define X uint8_t(OpRWFlags::kRW)
{{ R, R, R, R, R, R }}, // kRWI_R
{{ R, W, R, R, R, R }}, // kRWI_RW
{{ R, X, R, R, R, R }}, // kRWI_RX
{{ R, R, W, R, R, R }}, // kRWI_RRW
{{ R, W, X, R, R, R }}, // kRWI_RWX
{{ W, R, R, R, R, R }}, // kRWI_W
{{ W, R, W, R, R, R }}, // kRWI_WRW
{{ W, R, X, R, R, R }}, // kRWI_WRX
{{ W, R, R, W, R, R }}, // kRWI_WRRW
{{ W, R, R, X, R, R }}, // kRWI_WRRX
{{ W, W, R, R, R, R }}, // kRWI_WW
{{ X, R, R, R, R, R }}, // kRWI_X
{{ X, R, X, R, R, R }}, // kRWI_XRX
{{ X, X, R, R, X, R }}, // kRWI_XXRRX
{{ W, R, R, R, R, R }}, // kRWI_LDn
{{ R, W, R, R, R, R }}, // kRWI_STn
{{ R, R, R, R, R, R }} // kRWI_TODO
#undef R
#undef W
#undef X
};
static const uint8_t elementTypeSize[8] = { 0, 1, 2, 4, 8, 4, 4, 0 };
Error InstInternal::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept {
// Unused in Release configuration as the assert is not compiled in.
DebugUtils::unused(arch);
// Only called when `arch` matches X86 family.
ASMJIT_ASSERT(Environment::isFamilyARM(arch));
// Get the instruction data.
uint32_t realId = inst.id() & uint32_t(InstIdParts::kRealId);
if (ASMJIT_UNLIKELY(!Inst::isDefinedId(realId)))
return DebugUtils::errored(kErrorInvalidInstruction);
out->_instFlags = 0;
out->_opCount = uint8_t(opCount);
out->_rmFeature = 0;
out->_extraReg.reset();
out->_readFlags = CpuRWFlags::kNone; // TODO: [ARM] Read PSTATUS.
out->_writeFlags = CpuRWFlags::kNone; // TODO: [ARM] Write PSTATUS
const InstDB::InstInfo& instInfo = InstDB::_instInfoTable[realId];
const InstRWInfoData& rwInfo = instRWInfoData[instInfo.rwInfoIndex()];
if (instInfo.hasFlag(InstDB::kInstFlagConsecutive) && opCount > 2) {
for (uint32_t i = 0; i < opCount; i++) {
OpRWInfo& op = out->_operands[i];
const Operand_& srcOp = operands[i];
if (!srcOp.isRegOrMem()) {
op.reset();
continue;
}
OpRWFlags rwFlags = i < opCount - 1 ? (OpRWFlags)rwInfo.rwx[0] : (OpRWFlags)rwInfo.rwx[1];
op._opFlags = rwFlags & ~(OpRWFlags::kZExt);
op._physId = BaseReg::kIdBad;
op._rmSize = 0;
op._resetReserved();
uint64_t rByteMask = op.isRead() ? 0xFFFFFFFFFFFFFFFFu : 0x0000000000000000u;
uint64_t wByteMask = op.isWrite() ? 0xFFFFFFFFFFFFFFFFu : 0x0000000000000000u;
op._readByteMask = rByteMask;
op._writeByteMask = wByteMask;
op._extendByteMask = 0;
op._consecutiveLeadCount = 0;
if (srcOp.isReg()) {
if (i == 0)
op._consecutiveLeadCount = uint8_t(opCount - 1);
else
op.addOpFlags(OpRWFlags::kConsecutive);
}
else {
const Mem& memOp = srcOp.as<Mem>();
if (memOp.hasBase()) {
op.addOpFlags(OpRWFlags::kMemBaseRead);
}
if (memOp.hasIndex()) {
op.addOpFlags(OpRWFlags::kMemIndexRead);
op.addOpFlags(memOp.isPreOrPost() ? OpRWFlags::kMemIndexWrite : OpRWFlags::kNone);
}
}
}
}
else {
for (uint32_t i = 0; i < opCount; i++) {
OpRWInfo& op = out->_operands[i];
const Operand_& srcOp = operands[i];
if (!srcOp.isRegOrMem()) {
op.reset();
continue;
}
OpRWFlags rwFlags = (OpRWFlags)rwInfo.rwx[i];
op._opFlags = rwFlags & ~(OpRWFlags::kZExt);
op._physId = BaseReg::kIdBad;
op._rmSize = 0;
op._resetReserved();
uint64_t rByteMask = op.isRead() ? 0xFFFFFFFFFFFFFFFFu : 0x0000000000000000u;
uint64_t wByteMask = op.isWrite() ? 0xFFFFFFFFFFFFFFFFu : 0x0000000000000000u;
op._readByteMask = rByteMask;
op._writeByteMask = wByteMask;
op._extendByteMask = 0;
op._consecutiveLeadCount = 0;
if (srcOp.isReg()) {
if (srcOp.as<Vec>().hasElementIndex()) {
// Only part of the vector is accessed if element index [] is used.
uint32_t elementType = srcOp.as<Vec>().elementType();
uint32_t elementIndex = srcOp.as<Vec>().elementIndex();
uint32_t elementSize = elementTypeSize[elementType];
uint64_t accessMask = uint64_t(Support::lsbMask<uint32_t>(elementSize)) << (elementIndex * elementSize);
op._readByteMask &= accessMask;
op._writeByteMask &= accessMask;
}
// TODO: [ARM] RW info is not finished.
}
else {
const Mem& memOp = srcOp.as<Mem>();
if (memOp.hasBase()) {
op.addOpFlags(OpRWFlags::kMemBaseRead);
}
if (memOp.hasIndex()) {
op.addOpFlags(OpRWFlags::kMemIndexRead);
op.addOpFlags(memOp.isPreOrPost() ? OpRWFlags::kMemIndexWrite : OpRWFlags::kNone);
}
}
}
}
return kErrorOk;
}
#endif // !ASMJIT_NO_INTROSPECTION
// a64::InstInternal - QueryFeatures
// =================================
#ifndef ASMJIT_NO_INTROSPECTION
Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, CpuFeatures* out) noexcept {
// TODO: [ARM] QueryFeatures not implemented yet.
DebugUtils::unused(arch, inst, operands, opCount, out);
return kErrorOk;
}
#endif // !ASMJIT_NO_INTROSPECTION
// a64::InstInternal - Unit
// ========================
#if defined(ASMJIT_TEST)
UNIT(arm_inst_api_text) {
// TODO:
}
#endif
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_AARCH64
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_ARM_A64INSTAPI_P_H_INCLUDED
#define ASMJIT_ARM_A64INSTAPI_P_H_INCLUDED
#include "../core/inst.h"
#include "../core/operand.h"
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
//! \cond INTERNAL
//! \addtogroup asmjit_a64
//! \{
namespace InstInternal {
#ifndef ASMJIT_NO_TEXT
Error ASMJIT_CDECL instIdToString(Arch arch, InstId instId, String& output) noexcept;
InstId ASMJIT_CDECL stringToInstId(Arch arch, const char* s, size_t len) noexcept;
#endif // !ASMJIT_NO_TEXT
#ifndef ASMJIT_NO_VALIDATION
Error ASMJIT_CDECL validate(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept;
#endif // !ASMJIT_NO_VALIDATION
#ifndef ASMJIT_NO_INTROSPECTION
Error ASMJIT_CDECL queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept;
Error ASMJIT_CDECL queryFeatures(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, CpuFeatures* out) noexcept;
#endif // !ASMJIT_NO_INTROSPECTION
} // {InstInternal}
//! \}
//! \endcond
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_A64INSTAPI_P_H_INCLUDED
This source diff could not be displayed because it is too large. You can view the blob instead.
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_ARM_A64INSTDB_H_INCLUDED
#define ASMJIT_ARM_A64INSTDB_H_INCLUDED
#include "../arm/a64globals.h"
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
//! \addtogroup asmjit_a64
//! \{
//! Instruction database (AArch64).
namespace InstDB {
//! Instruction flags.
enum InstFlags : uint32_t {
//! The instruction provides conditional execution.
kInstFlagCond = 0x00000001u,
//! SIMD instruction that processes elements in pairs.
kInstFlagPair = 0x00000002u,
//! SIMD instruction that does widening (Long).
kInstFlagLong = 0x00000004u,
//! SIMD instruction that does narrowing (Narrow).
kInstFlagNarrow = 0x00000008u,
//! SIMD element access of half-words can only be used with v0..15.
kInstFlagVH0_15 = 0x00000010u,
//! Instruction may consecutive registers if the number of operands is greater than 2.
kInstFlagConsecutive = 0x00000080u
};
//! Instruction information (AArch64).
struct InstInfo {
//! Instruction encoding type.
uint32_t _encoding : 8;
//! Index to data specific to each encoding type.
uint32_t _encodingDataIndex : 8;
uint32_t _reserved : 2;
//! Index to \ref _nameData.
uint32_t _nameDataIndex : 14;
uint16_t _rwInfoIndex;
uint16_t _flags;
//! \name Accessors
//! \{
inline uint32_t rwInfoIndex() const noexcept { return _rwInfoIndex; }
inline uint32_t flags() const noexcept { return _flags; }
inline bool hasFlag(uint32_t flag) const { return (_flags & flag) != 0; }
//! \}
};
ASMJIT_VARAPI const InstInfo _instInfoTable[];
static inline const InstInfo& infoById(InstId instId) noexcept {
instId &= uint32_t(InstIdParts::kRealId);
ASMJIT_ASSERT(Inst::isDefinedId(instId));
return _instInfoTable[instId];
}
} // {InstDB}
//! \}
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_A64INSTDB_H_INCLUDED
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_ARM_A64INSTDB_H_P_INCLUDED
#define ASMJIT_ARM_A64INSTDB_H_P_INCLUDED
#include "../core/codeholder.h"
#include "../arm/a64instdb.h"
#include "../arm/a64operand.h"
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
//! \cond INTERNAL
//! \addtogroup asmjit_a64
//! \{
namespace InstDB {
// a64::InstDB - Constants Used by Instructions
// ============================================
// GP register types supported by base instructions.
static constexpr uint32_t kW = 0x1;
static constexpr uint32_t kX = 0x2;
static constexpr uint32_t kWX = 0x3;
// GP high register IDs supported by the instruction.
static constexpr uint32_t kZR = Gp::kIdZr;
static constexpr uint32_t kSP = Gp::kIdSp;
// a64::InstDB - RWInfo
// ====================
enum RWInfoType : uint32_t {
kRWI_R,
kRWI_RW,
kRWI_RX,
kRWI_RRW,
kRWI_RWX,
kRWI_W,
kRWI_WRW,
kRWI_WRX,
kRWI_WRRW,
kRWI_WRRX,
kRWI_WW,
kRWI_X,
kRWI_XRX,
kRWI_XXRRX,
kRWI_LDn,
kRWI_STn,
kRWI_SpecialStart = kRWI_LDn
};
// a64::InstDB - ElementType
// =========================
enum ElementType : uint8_t {
kET_None = Vec::kElementTypeNone,
kET_B = Vec::kElementTypeB,
kET_H = Vec::kElementTypeH,
kET_S = Vec::kElementTypeS,
kET_D = Vec::kElementTypeD,
kET_2H = Vec::kElementTypeH2,
kET_4B = Vec::kElementTypeB4
};
// a64::InstDB - GpType
// ====================
enum GpType : uint8_t {
kGp_W,
kGp_X,
kGp_X_SP
};
// a64::InstDB - OPSig
// ===================
enum kOpSignature : uint32_t {
kOp_GpW = GpW::kSignature,
kOp_GpX = GpX::kSignature,
kOp_B = VecB::kSignature,
kOp_H = VecH::kSignature,
kOp_S = VecS::kSignature,
kOp_D = VecD::kSignature,
kOp_Q = VecV::kSignature,
kOp_V8B = VecD::kSignature | Vec::kSignatureElementB,
kOp_V4H = VecD::kSignature | Vec::kSignatureElementH,
kOp_V2S = VecD::kSignature | Vec::kSignatureElementS,
kOp_V16B = VecV::kSignature | Vec::kSignatureElementB,
kOp_V8H = VecV::kSignature | Vec::kSignatureElementH,
kOp_V4S = VecV::kSignature | Vec::kSignatureElementS,
kOp_V2D = VecV::kSignature | Vec::kSignatureElementD
};
// a64::InstDB - HFConv
// ====================
enum kHFConv : uint32_t {
//! FP16 version of the instruction is not available.
kHF_N,
//! Doesn't do any change to the opcode.
kHF_0,
kHF_A,
kHF_B,
kHF_C,
kHF_D,
kHF_Count
};
// a64::InstDB - VOType
// ====================
//! Vector operand type combinations used by FP&SIMD instructions.
enum VOType : uint32_t {
kVO_V_B,
kVO_V_BH,
kVO_V_BH_4S,
kVO_V_BHS,
kVO_V_BHS_D2,
kVO_V_HS,
kVO_V_S,
kVO_V_B8H4,
kVO_V_B8H4S2,
kVO_V_B8D1,
kVO_V_H4S2,
kVO_V_B16,
kVO_V_B16H8,
kVO_V_B16H8S4,
kVO_V_B16D2,
kVO_V_H8S4,
kVO_V_S4,
kVO_V_D2,
kVO_SV_BHS,
kVO_SV_B8H4S2,
kVO_SV_HS,
kVO_V_Any,
kVO_SV_Any,
kVO_Count
};
// a64::InstDB - EncodingId
// ========================
// ${EncodingId:Begin}
// ------------------- Automatically generated, do not edit -------------------
enum EncodingId : uint32_t {
kEncodingNone = 0,
kEncodingBaseAddSub,
kEncodingBaseAdr,
kEncodingBaseAtDcIcTlbi,
kEncodingBaseAtomicCasp,
kEncodingBaseAtomicOp,
kEncodingBaseAtomicSt,
kEncodingBaseBfc,
kEncodingBaseBfi,
kEncodingBaseBfm,
kEncodingBaseBfx,
kEncodingBaseBranchCmp,
kEncodingBaseBranchReg,
kEncodingBaseBranchRel,
kEncodingBaseBranchTst,
kEncodingBaseCCmp,
kEncodingBaseCInc,
kEncodingBaseCSel,
kEncodingBaseCSet,
kEncodingBaseCmpCmn,
kEncodingBaseExtend,
kEncodingBaseExtract,
kEncodingBaseLdSt,
kEncodingBaseLdpStp,
kEncodingBaseLdxp,
kEncodingBaseLogical,
kEncodingBaseMov,
kEncodingBaseMovKNZ,
kEncodingBaseMrs,
kEncodingBaseMsr,
kEncodingBaseMvnNeg,
kEncodingBaseOp,
kEncodingBaseOpImm,
kEncodingBaseR,
kEncodingBaseRM_NoImm,
kEncodingBaseRM_SImm10,
kEncodingBaseRM_SImm9,
kEncodingBaseRR,
kEncodingBaseRRII,
kEncodingBaseRRR,
kEncodingBaseRRRR,
kEncodingBaseRev,
kEncodingBaseShift,
kEncodingBaseStx,
kEncodingBaseStxp,
kEncodingBaseSys,
kEncodingBaseTst,
kEncodingFSimdPair,
kEncodingFSimdSV,
kEncodingFSimdVV,
kEncodingFSimdVVV,
kEncodingFSimdVVVV,
kEncodingFSimdVVVe,
kEncodingISimdPair,
kEncodingISimdSV,
kEncodingISimdVV,
kEncodingISimdVVV,
kEncodingISimdVVVI,
kEncodingISimdVVVV,
kEncodingISimdVVVVx,
kEncodingISimdVVVe,
kEncodingISimdVVVx,
kEncodingISimdVVx,
kEncodingISimdWWV,
kEncodingSimdBicOrr,
kEncodingSimdCmp,
kEncodingSimdDot,
kEncodingSimdDup,
kEncodingSimdFcadd,
kEncodingSimdFccmpFccmpe,
kEncodingSimdFcm,
kEncodingSimdFcmla,
kEncodingSimdFcmpFcmpe,
kEncodingSimdFcsel,
kEncodingSimdFcvt,
kEncodingSimdFcvtLN,
kEncodingSimdFcvtSV,
kEncodingSimdFmlal,
kEncodingSimdFmov,
kEncodingSimdIns,
kEncodingSimdLdNStN,
kEncodingSimdLdSt,
kEncodingSimdLdpStp,
kEncodingSimdLdurStur,
kEncodingSimdMov,
kEncodingSimdMoviMvni,
kEncodingSimdShift,
kEncodingSimdShiftES,
kEncodingSimdSm3tt,
kEncodingSimdSmovUmov,
kEncodingSimdSxtlUxtl,
kEncodingSimdTblTbx
};
// ----------------------------------------------------------------------------
// ${EncodingId:End}
// a64::InstDB::EncodingData
// =========================
namespace EncodingData {
#define M_OPCODE(field, bits) \
uint32_t _##field : bits; \
inline constexpr uint32_t field() const noexcept { return uint32_t(_##field) << (32 - bits); }
struct BaseOp {
uint32_t opcode;
};
struct BaseOpImm {
uint32_t opcode;
uint16_t immBits;
uint16_t immOffset;
};
struct BaseR {
uint32_t opcode;
uint32_t rType : 8;
uint32_t rHiId : 8;
uint32_t rShift : 8;
};
struct BaseRR {
uint32_t opcode;
uint32_t aType : 2;
uint32_t aHiId : 6;
uint32_t aShift : 5;
uint32_t bType : 2;
uint32_t bHiId : 6;
uint32_t bShift : 5;
uint32_t uniform : 1;
};
struct BaseRRR {
M_OPCODE(opcode, 22)
uint32_t aType : 2;
uint32_t aHiId : 6;
uint32_t bType : 2;
uint32_t bHiId : 6;
uint32_t cType : 2;
uint32_t cHiId : 6;
uint32_t uniform : 1;
};
struct BaseRRRR {
M_OPCODE(opcode, 22)
uint32_t aType : 2;
uint32_t aHiId : 6;
uint32_t bType : 2;
uint32_t bHiId : 6;
uint32_t cType : 2;
uint32_t cHiId : 6;
uint32_t dType : 2;
uint32_t dHiId : 6;
uint32_t uniform : 1;
};
struct BaseRRII {
M_OPCODE(opcode, 22)
uint32_t aType : 2;
uint32_t aHiId : 6;
uint32_t bType : 2;
uint32_t bHiId : 6;
uint32_t aImmSize : 6;
uint32_t aImmDiscardLsb : 5;
uint32_t aImmOffset : 5;
uint32_t bImmSize : 6;
uint32_t bImmDiscardLsb : 5;
uint32_t bImmOffset : 5;
};
struct BaseAtDcIcTlbi {
uint32_t immVerifyMask : 14;
uint32_t immVerifyData : 14;
uint32_t mandatoryReg : 1;
};
struct BaseAdcSbc {
uint32_t opcode;
};
struct BaseAddSub {
uint32_t shiftedOp : 10; // sf|.......|Sh|.|Rm| Imm:6 |Rn|Rd|
uint32_t extendedOp : 10; // sf|.......|..|.|Rm|Opt|Imm3|Rn|Rd|
uint32_t immediateOp: 10; // sf|.......|Sh| Imm:12 |Rn|Rd|
};
struct BaseAdr {
M_OPCODE(opcode, 22)
OffsetType offsetType : 8;
};
struct BaseBfm {
uint32_t opcode; // sf|........|N|ImmR:6|ImmS:6|Rn|Rd|
};
struct BaseCmpCmn {
uint32_t shiftedOp : 10; // sf|.......|Sh|.|Rm| Imm:6 |Rn|11111|
uint32_t extendedOp : 10; // sf|.......|..|.|Rm|Opt|Imm3|Rn|11111|
uint32_t immediateOp: 10; // sf|.......|Sh| Imm:12 |Rn|11111|
};
struct BaseExtend {
M_OPCODE(opcode, 22) // sf|........|N|......|......|Rn|Rd|
uint32_t rType : 2;
uint32_t u : 1;
};
struct BaseLogical {
uint32_t shiftedOp : 10; // sf|.......|Sh|.|Rm| Imm:6 |Rn|Rd|
uint32_t immediateOp: 10; // sf|........|N|ImmR:6|ImmS:6|Rn|Rd|
uint32_t negateImm : 1 ; // True if this is an operation that must negate IMM.
};
struct BaseMvnNeg {
uint32_t opcode;
};
struct BaseShift {
M_OPCODE(registerOp, 22)
M_OPCODE(immediateOp, 22)
uint32_t ror : 2;
};
struct BaseTst {
uint32_t shiftedOp : 10; // sf|.......|Sh|.|Rm| Imm:6 |Rn|11111|
uint32_t immediateOp: 10; // sf|........|N|ImmR:6|ImmS:6|Rn|11111|
};
struct BaseRM_NoImm {
M_OPCODE(opcode, 22)
uint32_t rType : 2;
uint32_t rHiId : 6;
uint32_t xOffset : 5;
};
struct BaseRM_SImm9 {
M_OPCODE(offsetOp, 22)
M_OPCODE(prePostOp, 22)
uint32_t rType : 2;
uint32_t rHiId : 6;
uint32_t xOffset : 5;
uint32_t immShift : 4;
};
struct BaseRM_SImm10 {
M_OPCODE(opcode, 22)
uint32_t rType : 2;
uint32_t rHiId : 6;
uint32_t xOffset : 5;
uint32_t immShift : 4;
};
struct BaseLdSt {
uint32_t uOffsetOp : 10;
uint32_t prePostOp : 11;
uint32_t registerOp : 11;
uint32_t literalOp : 8;
uint32_t rType : 2;
uint32_t xOffset : 5;
uint32_t uOffsetShift : 3;
uint32_t uAltInstId : 14;
};
struct BaseLdpStp {
uint32_t offsetOp : 10;
uint32_t prePostOp : 10;
uint32_t rType : 2;
uint32_t xOffset : 5;
uint32_t offsetShift : 3;
};
struct BaseStx {
M_OPCODE(opcode, 22)
uint32_t rType : 2;
uint32_t xOffset : 5;
};
struct BaseLdxp {
M_OPCODE(opcode, 22)
uint32_t rType : 2;
uint32_t xOffset : 5;
};
struct BaseStxp {
M_OPCODE(opcode, 22)
uint32_t rType : 2;
uint32_t xOffset : 5;
};
struct BaseAtomicOp {
M_OPCODE(opcode, 22)
uint32_t rType : 2;
uint32_t xOffset : 5;
uint32_t zr : 1;
};
struct BaseAtomicSt {
M_OPCODE(opcode, 22)
uint32_t rType : 2;
uint32_t xOffset : 5;
};
struct BaseAtomicCasp {
M_OPCODE(opcode, 22)
uint32_t rType : 2;
uint32_t xOffset : 5;
};
typedef BaseOp BaseBranchReg;
typedef BaseOp BaseBranchRel;
typedef BaseOp BaseBranchCmp;
typedef BaseOp BaseBranchTst;
typedef BaseOp BaseExtract;
typedef BaseOp BaseBfc;
typedef BaseOp BaseBfi;
typedef BaseOp BaseBfx;
typedef BaseOp BaseCCmp;
typedef BaseOp BaseCInc;
typedef BaseOp BaseCSet;
typedef BaseOp BaseCSel;
typedef BaseOp BaseMovKNZ;
typedef BaseOp BaseMull;
struct FSimdGeneric {
uint32_t _scalarOp : 28;
uint32_t _scalarHf : 4;
uint32_t _vectorOp : 28;
uint32_t _vectorHf : 4;
constexpr uint32_t scalarOp() const noexcept { return uint32_t(_scalarOp) << 10; }
constexpr uint32_t vectorOp() const noexcept { return uint32_t(_vectorOp) << 10; }
constexpr uint32_t scalarHf() const noexcept { return uint32_t(_scalarHf); }
constexpr uint32_t vectorHf() const noexcept { return uint32_t(_vectorHf); }
};
typedef FSimdGeneric FSimdVV;
typedef FSimdGeneric FSimdVVV;
typedef FSimdGeneric FSimdVVVV;
struct FSimdSV {
uint32_t opcode;
};
struct FSimdVVVe {
uint32_t _scalarOp : 28;
uint32_t _scalarHf : 4;
uint32_t _vectorOp;
uint32_t _elementOp;
constexpr uint32_t scalarOp() const noexcept { return uint32_t(_scalarOp) << 10; }
constexpr uint32_t scalarHf() const noexcept { return uint32_t(_scalarHf); };
constexpr uint32_t vectorOp() const noexcept { return uint32_t(_vectorOp) << 10; }
constexpr uint32_t vectorHf() const noexcept { return kHF_C; }
constexpr uint32_t elementScalarOp() const noexcept { return (uint32_t(_elementOp) << 10) | (0x5u << 28); }
constexpr uint32_t elementVectorOp() const noexcept { return (uint32_t(_elementOp) << 10); }
};
struct SimdFcadd {
uint32_t _opcode;
constexpr uint32_t opcode() const noexcept { return _opcode << 10; }
};
struct SimdFcmla {
uint32_t _regularOp;
uint32_t _elementOp;
constexpr uint32_t regularOp() const noexcept { return uint32_t(_regularOp) << 10; }
constexpr uint32_t elementOp() const noexcept { return (uint32_t(_elementOp) << 10); }
};
struct SimdFccmpFccmpe {
uint32_t _opcode;
constexpr uint32_t opcode() const noexcept { return _opcode; }
};
struct SimdFcm {
uint32_t _registerOp : 28;
uint32_t _registerHf : 4;
uint32_t _zeroOp : 28;
constexpr bool hasRegisterOp() const noexcept { return _registerOp != 0; }
constexpr bool hasZeroOp() const noexcept { return _zeroOp != 0; }
constexpr uint32_t registerScalarOp() const noexcept { return (uint32_t(_registerOp) << 10) | (0x5u << 28); }
constexpr uint32_t registerVectorOp() const noexcept { return uint32_t(_registerOp) << 10; }
constexpr uint32_t registerScalarHf() const noexcept { return uint32_t(_registerHf); }
constexpr uint32_t registerVectorHf() const noexcept { return uint32_t(_registerHf); }
constexpr uint32_t zeroScalarOp() const noexcept { return (uint32_t(_zeroOp) << 10) | (0x5u << 28); }
constexpr uint32_t zeroVectorOp() const noexcept { return (uint32_t(_zeroOp) << 10); }
};
struct SimdFcmpFcmpe {
uint32_t _opcode;
constexpr uint32_t opcode() const noexcept { return _opcode; }
};
struct SimdFcvtLN {
uint32_t _opcode : 22;
uint32_t _isCvtxn : 1;
uint32_t _hasScalar : 1;
constexpr uint32_t scalarOp() const noexcept { return (uint32_t(_opcode) << 10) | (0x5u << 28); }
constexpr uint32_t vectorOp() const noexcept { return (uint32_t(_opcode) << 10); }
constexpr uint32_t isCvtxn() const noexcept { return _isCvtxn; }
constexpr uint32_t hasScalar() const noexcept { return _hasScalar; }
};
struct SimdFcvtSV {
uint32_t _vectorIntOp;
uint32_t _vectorFpOp;
uint32_t _generalOp : 31;
uint32_t _isFloatToInt : 1;
constexpr uint32_t scalarIntOp() const noexcept { return (uint32_t(_vectorIntOp) << 10) | (0x5u << 28); }
constexpr uint32_t vectorIntOp() const noexcept { return uint32_t(_vectorIntOp) << 10; }
constexpr uint32_t scalarFpOp() const noexcept { return (uint32_t(_vectorFpOp) << 10) | (0x5u << 28); }
constexpr uint32_t vectorFpOp() const noexcept { return uint32_t(_vectorFpOp) << 10; }
constexpr uint32_t generalOp() const noexcept { return (uint32_t(_generalOp) << 10); }
constexpr uint32_t isFloatToInt() const noexcept { return _isFloatToInt; }
constexpr uint32_t isFixedPoint() const noexcept { return _vectorFpOp != 0; }
};
struct SimdFmlal {
uint32_t _vectorOp;
uint32_t _elementOp;
uint8_t _optionalQ;
uint8_t tA;
uint8_t tB;
uint8_t tElement;
constexpr uint32_t vectorOp() const noexcept { return uint32_t(_vectorOp) << 10; }
constexpr uint32_t elementOp() const noexcept { return uint32_t(_elementOp) << 10; }
constexpr uint32_t optionalQ() const noexcept { return _optionalQ; }
};
struct FSimdPair {
uint32_t _scalarOp;
uint32_t _vectorOp;
constexpr uint32_t scalarOp() const noexcept { return uint32_t(_scalarOp) << 10; }
constexpr uint32_t vectorOp() const noexcept { return uint32_t(_vectorOp) << 10; }
};
struct ISimdVV {
M_OPCODE(opcode, 22)
uint32_t vecOpType : 6;
};
struct ISimdVVx {
M_OPCODE(opcode, 22)
uint32_t op0Signature;
uint32_t op1Signature;
};
struct ISimdSV {
M_OPCODE(opcode, 22)
uint32_t vecOpType : 6;
};
struct ISimdVVV {
M_OPCODE(opcode, 22)
uint32_t vecOpType : 6;
};
struct ISimdVVVx {
M_OPCODE(opcode, 22)
uint32_t op0Signature;
uint32_t op1Signature;
uint32_t op2Signature;
};
struct ISimdWWV {
M_OPCODE(opcode, 22)
uint32_t vecOpType : 6;
};
struct ISimdVVVe {
uint32_t regularOp : 26; // 22 bits used.
uint32_t regularVecType : 6;
uint32_t elementOp : 26; // 22 bits used.
uint32_t elementVecType : 6;
};
struct ISimdVVVI {
M_OPCODE(opcode, 22)
uint32_t vecOpType : 6;
uint32_t immSize : 4;
uint32_t immShift : 4;
uint32_t imm64HasOneBitLess : 1;
};
struct ISimdVVVV {
uint32_t opcode : 22;
uint32_t vecOpType : 6;
};
struct ISimdVVVVx {
uint32_t opcode;
uint32_t op0Signature;
uint32_t op1Signature;
uint32_t op2Signature;
uint32_t op3Signature;
};
struct SimdBicOrr {
uint32_t registerOp; // 22 bits used.
uint32_t immediateOp; // 22 bits used.
};
struct SimdCmp {
uint32_t regOp;
uint32_t zeroOp : 22;
uint32_t vecOpType : 6;
};
struct SimdDot {
uint32_t vectorOp; // 22 bits used.
uint32_t elementOp; // 22 bits used.
uint8_t tA; // Element-type of the first operand.
uint8_t tB; // Element-type of the second and third operands.
uint8_t tElement; // Element-type of the element index[] operand.
};
struct SimdMoviMvni {
uint32_t opcode : 31;
uint32_t inverted : 1;
};
struct SimdLdSt {
uint32_t uOffsetOp : 10;
uint32_t prePostOp : 11;
uint32_t registerOp : 11;
uint32_t literalOp : 8;
uint32_t uAltInstId : 16;
};
struct SimdLdNStN {
uint32_t singleOp;
uint32_t multipleOp : 22;
uint32_t n : 3;
uint32_t replicate : 1;
};
struct SimdLdpStp {
uint32_t offsetOp : 10;
uint32_t prePostOp : 10;
};
struct SimdLdurStur {
uint32_t opcode;
};
struct ISimdPair {
uint32_t opcode2; // 22 bits used.
uint32_t opcode3 : 26; // 22 bits used.
uint32_t opType3 : 6;
};
struct SimdShift {
uint32_t registerOp; // 22 bits used.
uint32_t immediateOp : 22; // 22 bits used.
uint32_t invertedImm : 1;
uint32_t vecOpType : 6;
};
struct SimdShiftES {
uint32_t opcode : 22;
uint32_t vecOpType : 6;
};
struct SimdSm3tt {
uint32_t opcode;
};
struct SimdSmovUmov {
uint32_t opcode : 22;
uint32_t vecOpType : 6;
uint32_t isSigned : 1;
};
struct SimdSxtlUxtl {
uint32_t opcode : 22;
uint32_t vecOpType : 6;
};
struct SimdTblTbx {
uint32_t opcode;
};
#undef M_OPCODE
// ${EncodingDataForward:Begin}
// ------------------- Automatically generated, do not edit -------------------
extern const BaseAddSub baseAddSub[4];
extern const BaseAdr baseAdr[2];
extern const BaseAtDcIcTlbi baseAtDcIcTlbi[4];
extern const BaseAtomicCasp baseAtomicCasp[4];
extern const BaseAtomicOp baseAtomicOp[123];
extern const BaseAtomicSt baseAtomicSt[48];
extern const BaseBfc baseBfc[1];
extern const BaseBfi baseBfi[3];
extern const BaseBfm baseBfm[3];
extern const BaseBfx baseBfx[3];
extern const BaseBranchCmp baseBranchCmp[2];
extern const BaseBranchReg baseBranchReg[3];
extern const BaseBranchRel baseBranchRel[2];
extern const BaseBranchTst baseBranchTst[2];
extern const BaseCCmp baseCCmp[2];
extern const BaseCInc baseCInc[3];
extern const BaseCSel baseCSel[4];
extern const BaseCSet baseCSet[2];
extern const BaseCmpCmn baseCmpCmn[2];
extern const BaseExtend baseExtend[5];
extern const BaseExtract baseExtract[1];
extern const BaseLdSt baseLdSt[9];
extern const BaseLdpStp baseLdpStp[6];
extern const BaseLdxp baseLdxp[2];
extern const BaseLogical baseLogical[8];
extern const BaseMovKNZ baseMovKNZ[3];
extern const BaseMvnNeg baseMvnNeg[3];
extern const BaseOp baseOp[23];
extern const BaseOpImm baseOpImm[14];
extern const BaseR baseR[10];
extern const BaseRM_NoImm baseRM_NoImm[21];
extern const BaseRM_SImm10 baseRM_SImm10[2];
extern const BaseRM_SImm9 baseRM_SImm9[23];
extern const BaseRR baseRR[15];
extern const BaseRRII baseRRII[2];
extern const BaseRRR baseRRR[26];
extern const BaseRRRR baseRRRR[6];
extern const BaseShift baseShift[8];
extern const BaseStx baseStx[3];
extern const BaseStxp baseStxp[2];
extern const BaseTst baseTst[1];
extern const FSimdPair fSimdPair[5];
extern const FSimdSV fSimdSV[4];
extern const FSimdVV fSimdVV[17];
extern const FSimdVVV fSimdVVV[13];
extern const FSimdVVVV fSimdVVVV[4];
extern const FSimdVVVe fSimdVVVe[4];
extern const ISimdPair iSimdPair[1];
extern const ISimdSV iSimdSV[7];
extern const ISimdVV iSimdVV[29];
extern const ISimdVVV iSimdVVV[65];
extern const ISimdVVVI iSimdVVVI[2];
extern const ISimdVVVV iSimdVVVV[2];
extern const ISimdVVVVx iSimdVVVVx[1];
extern const ISimdVVVe iSimdVVVe[25];
extern const ISimdVVVx iSimdVVVx[17];
extern const ISimdVVx iSimdVVx[13];
extern const ISimdWWV iSimdWWV[8];
extern const SimdBicOrr simdBicOrr[2];
extern const SimdCmp simdCmp[7];
extern const SimdDot simdDot[5];
extern const SimdFcadd simdFcadd[1];
extern const SimdFccmpFccmpe simdFccmpFccmpe[2];
extern const SimdFcm simdFcm[5];
extern const SimdFcmla simdFcmla[1];
extern const SimdFcmpFcmpe simdFcmpFcmpe[2];
extern const SimdFcvtLN simdFcvtLN[6];
extern const SimdFcvtSV simdFcvtSV[12];
extern const SimdFmlal simdFmlal[6];
extern const SimdLdNStN simdLdNStN[12];
extern const SimdLdSt simdLdSt[2];
extern const SimdLdpStp simdLdpStp[4];
extern const SimdLdurStur simdLdurStur[2];
extern const SimdMoviMvni simdMoviMvni[2];
extern const SimdShift simdShift[40];
extern const SimdShiftES simdShiftES[2];
extern const SimdSm3tt simdSm3tt[4];
extern const SimdSmovUmov simdSmovUmov[2];
extern const SimdSxtlUxtl simdSxtlUxtl[4];
extern const SimdTblTbx simdTblTbx[2];
// ----------------------------------------------------------------------------
// ${EncodingDataForward:End}
} // {EncodingData}
// a64::InstDB - InstNameIndex
// ===========================
// ${NameLimits:Begin}
// ------------------- Automatically generated, do not edit -------------------
enum : uint32_t { kMaxNameSize = 9 };
// ----------------------------------------------------------------------------
// ${NameLimits:End}
struct InstNameIndex {
uint16_t start;
uint16_t end;
};
// a64::InstDB - Tables
// ====================
#ifndef ASMJIT_NO_TEXT
extern const char _nameData[];
extern const InstNameIndex instNameIndex[26];
#endif // !ASMJIT_NO_TEXT
} // {InstDB}
//! \}
//! \endcond
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_A64_ARMINSTDB_H_P_INCLUDED
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#if !defined(ASMJIT_NO_AARCH64)
#include "../core/misc_p.h"
#include "../arm/a64operand.h"
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
// a64::Operand - Tests
// ====================
#if defined(ASMJIT_TEST)
UNIT(a64_operand) {
INFO("Checking if a64::reg(...) matches built-in IDs");
EXPECT(w(5) == w5);
EXPECT(x(5) == x5);
INFO("Checking Gp register properties");
EXPECT(Gp().isReg() == true);
EXPECT(w0.isReg() == true);
EXPECT(x0.isReg() == true);
EXPECT(w0.id() == 0);
EXPECT(x0.id() == 0);
EXPECT(wzr.id() == Gp::kIdZr);
EXPECT(xzr.id() == Gp::kIdZr);
EXPECT(wsp.id() == Gp::kIdSp);
EXPECT(sp.id() == Gp::kIdSp);
EXPECT(w0.size() == 4);
EXPECT(x0.size() == 8);
EXPECT(w0.type() == RegType::kARM_GpW);
EXPECT(x0.type() == RegType::kARM_GpX);
EXPECT(w0.group() == RegGroup::kGp);
EXPECT(x0.group() == RegGroup::kGp);
INFO("Checking Vec register properties");
EXPECT(v0.type() == RegType::kARM_VecV);
EXPECT(d0.type() == RegType::kARM_VecD);
EXPECT(s0.type() == RegType::kARM_VecS);
EXPECT(h0.type() == RegType::kARM_VecH);
EXPECT(b0.type() == RegType::kARM_VecB);
EXPECT(v0.group() == RegGroup::kVec);
EXPECT(d0.group() == RegGroup::kVec);
EXPECT(s0.group() == RegGroup::kVec);
EXPECT(h0.group() == RegGroup::kVec);
EXPECT(b0.group() == RegGroup::kVec);
INFO("Checking Vec register element[] access");
Vec vd_1 = v15.d(1);
EXPECT(vd_1.type() == RegType::kARM_VecV);
EXPECT(vd_1.group() == RegGroup::kVec);
EXPECT(vd_1.id() == 15);
EXPECT(vd_1.isVecD2());
EXPECT(vd_1.elementType() == Vec::kElementTypeD);
EXPECT(vd_1.hasElementIndex());
EXPECT(vd_1.elementIndex() == 1);
Vec vs_3 = v15.s(3);
EXPECT(vs_3.type() == RegType::kARM_VecV);
EXPECT(vs_3.group() == RegGroup::kVec);
EXPECT(vs_3.id() == 15);
EXPECT(vs_3.isVecS4());
EXPECT(vs_3.elementType() == Vec::kElementTypeS);
EXPECT(vs_3.hasElementIndex());
EXPECT(vs_3.elementIndex() == 3);
Vec vb_4 = v15.b4(3);
EXPECT(vb_4.type() == RegType::kARM_VecV);
EXPECT(vb_4.group() == RegGroup::kVec);
EXPECT(vb_4.id() == 15);
EXPECT(vb_4.isVecB4x4());
EXPECT(vb_4.elementType() == Vec::kElementTypeB4);
EXPECT(vb_4.hasElementIndex());
EXPECT(vb_4.elementIndex() == 3);
}
#endif
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_AARCH64
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_ARM_A64OPERAND_H_INCLUDED
#define ASMJIT_ARM_A64OPERAND_H_INCLUDED
#include "../arm/armoperand.h"
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
//! \addtogroup asmjit_a64
//! \{
using arm::Reg;
using arm::Mem;
using arm::Gp;
using arm::GpW;
using arm::GpX;
using arm::Vec;
using arm::VecB;
using arm::VecH;
using arm::VecS;
using arm::VecD;
using arm::VecV;
#ifndef _DOXYGEN
namespace regs {
#endif
using namespace ::asmjit::arm::regs;
static constexpr GpW w0 = GpW(0);
static constexpr GpW w1 = GpW(1);
static constexpr GpW w2 = GpW(2);
static constexpr GpW w3 = GpW(3);
static constexpr GpW w4 = GpW(4);
static constexpr GpW w5 = GpW(5);
static constexpr GpW w6 = GpW(6);
static constexpr GpW w7 = GpW(7);
static constexpr GpW w8 = GpW(8);
static constexpr GpW w9 = GpW(9);
static constexpr GpW w10 = GpW(10);
static constexpr GpW w11 = GpW(11);
static constexpr GpW w12 = GpW(12);
static constexpr GpW w13 = GpW(13);
static constexpr GpW w14 = GpW(14);
static constexpr GpW w15 = GpW(15);
static constexpr GpW w16 = GpW(16);
static constexpr GpW w17 = GpW(17);
static constexpr GpW w18 = GpW(18);
static constexpr GpW w19 = GpW(19);
static constexpr GpW w20 = GpW(20);
static constexpr GpW w21 = GpW(21);
static constexpr GpW w22 = GpW(22);
static constexpr GpW w23 = GpW(23);
static constexpr GpW w24 = GpW(24);
static constexpr GpW w25 = GpW(25);
static constexpr GpW w26 = GpW(26);
static constexpr GpW w27 = GpW(27);
static constexpr GpW w28 = GpW(28);
static constexpr GpW w29 = GpW(29);
static constexpr GpW w30 = GpW(30);
static constexpr GpW wzr = GpW(Gp::kIdZr);
static constexpr GpW wsp = GpW(Gp::kIdSp);
static constexpr GpX x0 = GpX(0);
static constexpr GpX x1 = GpX(1);
static constexpr GpX x2 = GpX(2);
static constexpr GpX x3 = GpX(3);
static constexpr GpX x4 = GpX(4);
static constexpr GpX x5 = GpX(5);
static constexpr GpX x6 = GpX(6);
static constexpr GpX x7 = GpX(7);
static constexpr GpX x8 = GpX(8);
static constexpr GpX x9 = GpX(9);
static constexpr GpX x10 = GpX(10);
static constexpr GpX x11 = GpX(11);
static constexpr GpX x12 = GpX(12);
static constexpr GpX x13 = GpX(13);
static constexpr GpX x14 = GpX(14);
static constexpr GpX x15 = GpX(15);
static constexpr GpX x16 = GpX(16);
static constexpr GpX x17 = GpX(17);
static constexpr GpX x18 = GpX(18);
static constexpr GpX x19 = GpX(19);
static constexpr GpX x20 = GpX(20);
static constexpr GpX x21 = GpX(21);
static constexpr GpX x22 = GpX(22);
static constexpr GpX x23 = GpX(23);
static constexpr GpX x24 = GpX(24);
static constexpr GpX x25 = GpX(25);
static constexpr GpX x26 = GpX(26);
static constexpr GpX x27 = GpX(27);
static constexpr GpX x28 = GpX(28);
static constexpr GpX x29 = GpX(29);
static constexpr GpX x30 = GpX(30);
static constexpr GpX xzr = GpX(Gp::kIdZr);
static constexpr GpX sp = GpX(Gp::kIdSp);
static constexpr VecB b0 = VecB(0);
static constexpr VecB b1 = VecB(1);
static constexpr VecB b2 = VecB(2);
static constexpr VecB b3 = VecB(3);
static constexpr VecB b4 = VecB(4);
static constexpr VecB b5 = VecB(5);
static constexpr VecB b6 = VecB(6);
static constexpr VecB b7 = VecB(7);
static constexpr VecB b8 = VecB(8);
static constexpr VecB b9 = VecB(9);
static constexpr VecB b10 = VecB(10);
static constexpr VecB b11 = VecB(11);
static constexpr VecB b12 = VecB(12);
static constexpr VecB b13 = VecB(13);
static constexpr VecB b14 = VecB(14);
static constexpr VecB b15 = VecB(15);
static constexpr VecB b16 = VecB(16);
static constexpr VecB b17 = VecB(17);
static constexpr VecB b18 = VecB(18);
static constexpr VecB b19 = VecB(19);
static constexpr VecB b20 = VecB(20);
static constexpr VecB b21 = VecB(21);
static constexpr VecB b22 = VecB(22);
static constexpr VecB b23 = VecB(23);
static constexpr VecB b24 = VecB(24);
static constexpr VecB b25 = VecB(25);
static constexpr VecB b26 = VecB(26);
static constexpr VecB b27 = VecB(27);
static constexpr VecB b28 = VecB(28);
static constexpr VecB b29 = VecB(29);
static constexpr VecB b30 = VecB(30);
static constexpr VecB b31 = VecB(31);
static constexpr VecH h0 = VecH(0);
static constexpr VecH h1 = VecH(1);
static constexpr VecH h2 = VecH(2);
static constexpr VecH h3 = VecH(3);
static constexpr VecH h4 = VecH(4);
static constexpr VecH h5 = VecH(5);
static constexpr VecH h6 = VecH(6);
static constexpr VecH h7 = VecH(7);
static constexpr VecH h8 = VecH(8);
static constexpr VecH h9 = VecH(9);
static constexpr VecH h10 = VecH(10);
static constexpr VecH h11 = VecH(11);
static constexpr VecH h12 = VecH(12);
static constexpr VecH h13 = VecH(13);
static constexpr VecH h14 = VecH(14);
static constexpr VecH h15 = VecH(15);
static constexpr VecH h16 = VecH(16);
static constexpr VecH h17 = VecH(17);
static constexpr VecH h18 = VecH(18);
static constexpr VecH h19 = VecH(19);
static constexpr VecH h20 = VecH(20);
static constexpr VecH h21 = VecH(21);
static constexpr VecH h22 = VecH(22);
static constexpr VecH h23 = VecH(23);
static constexpr VecH h24 = VecH(24);
static constexpr VecH h25 = VecH(25);
static constexpr VecH h26 = VecH(26);
static constexpr VecH h27 = VecH(27);
static constexpr VecH h28 = VecH(28);
static constexpr VecH h29 = VecH(29);
static constexpr VecH h30 = VecH(30);
static constexpr VecH h31 = VecH(31);
static constexpr VecS s0 = VecS(0);
static constexpr VecS s1 = VecS(1);
static constexpr VecS s2 = VecS(2);
static constexpr VecS s3 = VecS(3);
static constexpr VecS s4 = VecS(4);
static constexpr VecS s5 = VecS(5);
static constexpr VecS s6 = VecS(6);
static constexpr VecS s7 = VecS(7);
static constexpr VecS s8 = VecS(8);
static constexpr VecS s9 = VecS(9);
static constexpr VecS s10 = VecS(10);
static constexpr VecS s11 = VecS(11);
static constexpr VecS s12 = VecS(12);
static constexpr VecS s13 = VecS(13);
static constexpr VecS s14 = VecS(14);
static constexpr VecS s15 = VecS(15);
static constexpr VecS s16 = VecS(16);
static constexpr VecS s17 = VecS(17);
static constexpr VecS s18 = VecS(18);
static constexpr VecS s19 = VecS(19);
static constexpr VecS s20 = VecS(20);
static constexpr VecS s21 = VecS(21);
static constexpr VecS s22 = VecS(22);
static constexpr VecS s23 = VecS(23);
static constexpr VecS s24 = VecS(24);
static constexpr VecS s25 = VecS(25);
static constexpr VecS s26 = VecS(26);
static constexpr VecS s27 = VecS(27);
static constexpr VecS s28 = VecS(28);
static constexpr VecS s29 = VecS(29);
static constexpr VecS s30 = VecS(30);
static constexpr VecS s31 = VecS(31);
static constexpr VecD d0 = VecD(0);
static constexpr VecD d1 = VecD(1);
static constexpr VecD d2 = VecD(2);
static constexpr VecD d3 = VecD(3);
static constexpr VecD d4 = VecD(4);
static constexpr VecD d5 = VecD(5);
static constexpr VecD d6 = VecD(6);
static constexpr VecD d7 = VecD(7);
static constexpr VecD d8 = VecD(8);
static constexpr VecD d9 = VecD(9);
static constexpr VecD d10 = VecD(10);
static constexpr VecD d11 = VecD(11);
static constexpr VecD d12 = VecD(12);
static constexpr VecD d13 = VecD(13);
static constexpr VecD d14 = VecD(14);
static constexpr VecD d15 = VecD(15);
static constexpr VecD d16 = VecD(16);
static constexpr VecD d17 = VecD(17);
static constexpr VecD d18 = VecD(18);
static constexpr VecD d19 = VecD(19);
static constexpr VecD d20 = VecD(20);
static constexpr VecD d21 = VecD(21);
static constexpr VecD d22 = VecD(22);
static constexpr VecD d23 = VecD(23);
static constexpr VecD d24 = VecD(24);
static constexpr VecD d25 = VecD(25);
static constexpr VecD d26 = VecD(26);
static constexpr VecD d27 = VecD(27);
static constexpr VecD d28 = VecD(28);
static constexpr VecD d29 = VecD(29);
static constexpr VecD d30 = VecD(30);
static constexpr VecD d31 = VecD(31);
static constexpr VecV q0 = VecV(0);
static constexpr VecV q1 = VecV(1);
static constexpr VecV q2 = VecV(2);
static constexpr VecV q3 = VecV(3);
static constexpr VecV q4 = VecV(4);
static constexpr VecV q5 = VecV(5);
static constexpr VecV q6 = VecV(6);
static constexpr VecV q7 = VecV(7);
static constexpr VecV q8 = VecV(8);
static constexpr VecV q9 = VecV(9);
static constexpr VecV q10 = VecV(10);
static constexpr VecV q11 = VecV(11);
static constexpr VecV q12 = VecV(12);
static constexpr VecV q13 = VecV(13);
static constexpr VecV q14 = VecV(14);
static constexpr VecV q15 = VecV(15);
static constexpr VecV q16 = VecV(16);
static constexpr VecV q17 = VecV(17);
static constexpr VecV q18 = VecV(18);
static constexpr VecV q19 = VecV(19);
static constexpr VecV q20 = VecV(20);
static constexpr VecV q21 = VecV(21);
static constexpr VecV q22 = VecV(22);
static constexpr VecV q23 = VecV(23);
static constexpr VecV q24 = VecV(24);
static constexpr VecV q25 = VecV(25);
static constexpr VecV q26 = VecV(26);
static constexpr VecV q27 = VecV(27);
static constexpr VecV q28 = VecV(28);
static constexpr VecV q29 = VecV(29);
static constexpr VecV q30 = VecV(30);
static constexpr VecV q31 = VecV(31);
static constexpr VecV v0 = VecV(0);
static constexpr VecV v1 = VecV(1);
static constexpr VecV v2 = VecV(2);
static constexpr VecV v3 = VecV(3);
static constexpr VecV v4 = VecV(4);
static constexpr VecV v5 = VecV(5);
static constexpr VecV v6 = VecV(6);
static constexpr VecV v7 = VecV(7);
static constexpr VecV v8 = VecV(8);
static constexpr VecV v9 = VecV(9);
static constexpr VecV v10 = VecV(10);
static constexpr VecV v11 = VecV(11);
static constexpr VecV v12 = VecV(12);
static constexpr VecV v13 = VecV(13);
static constexpr VecV v14 = VecV(14);
static constexpr VecV v15 = VecV(15);
static constexpr VecV v16 = VecV(16);
static constexpr VecV v17 = VecV(17);
static constexpr VecV v18 = VecV(18);
static constexpr VecV v19 = VecV(19);
static constexpr VecV v20 = VecV(20);
static constexpr VecV v21 = VecV(21);
static constexpr VecV v22 = VecV(22);
static constexpr VecV v23 = VecV(23);
static constexpr VecV v24 = VecV(24);
static constexpr VecV v25 = VecV(25);
static constexpr VecV v26 = VecV(26);
static constexpr VecV v27 = VecV(27);
static constexpr VecV v28 = VecV(28);
static constexpr VecV v29 = VecV(29);
static constexpr VecV v30 = VecV(30);
static constexpr VecV v31 = VecV(31);
#ifndef _DOXYGEN
} // {regs}
// Make `a64::regs` accessible through `a64` namespace as well.
using namespace regs;
#endif
//! \}
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_A64OPERAND_H_INCLUDED
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#if !defined(ASMJIT_NO_AARCH64) && !defined(ASMJIT_NO_COMPILER)
#include "../core/cpuinfo.h"
#include "../core/support.h"
#include "../core/type.h"
#include "../arm/a64assembler.h"
#include "../arm/a64compiler.h"
#include "../arm/a64emithelper_p.h"
#include "../arm/a64instapi_p.h"
#include "../arm/a64instdb_p.h"
#include "../arm/a64rapass_p.h"
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
// a64::ARMRAPass - Helpers
// ========================
// TODO: [ARM] These should be shared with all backends.
ASMJIT_MAYBE_UNUSED
static inline uint64_t raImmMaskFromSize(uint32_t size) noexcept {
ASMJIT_ASSERT(size > 0 && size < 256);
static const uint64_t masks[] = {
0x00000000000000FFu, // 1
0x000000000000FFFFu, // 2
0x00000000FFFFFFFFu, // 4
0xFFFFFFFFFFFFFFFFu, // 8
0x0000000000000000u, // 16
0x0000000000000000u, // 32
0x0000000000000000u, // 64
0x0000000000000000u, // 128
0x0000000000000000u // 256
};
return masks[Support::ctz(size)];
}
static const RegMask raConsecutiveLeadCountToRegMaskFilter[5] = {
0xFFFFFFFFu, // [0] No consecutive.
0x00000000u, // [1] Invalid, never used.
0x7FFFFFFFu, // [2] 2 consecutive registers.
0x3FFFFFFFu, // [3] 3 consecutive registers.
0x1FFFFFFFu // [4] 4 consecutive registers.
};
static inline RATiedFlags raUseOutFlagsFromRWFlags(OpRWFlags rwFlags) noexcept {
static constexpr RATiedFlags map[] = {
RATiedFlags::kNone,
RATiedFlags::kRead | RATiedFlags::kUse, // kRead
RATiedFlags::kWrite | RATiedFlags::kOut, // kWrite
RATiedFlags::kRW | RATiedFlags::kUse, // kRW
};
return map[uint32_t(rwFlags & OpRWFlags::kRW)];
}
static inline RATiedFlags raRegRwFlags(OpRWFlags flags) noexcept {
return raUseOutFlagsFromRWFlags(flags);
}
static inline RATiedFlags raMemBaseRwFlags(OpRWFlags flags) noexcept {
constexpr uint32_t shift = Support::ConstCTZ<uint32_t(OpRWFlags::kMemBaseRW)>::value;
return raUseOutFlagsFromRWFlags(OpRWFlags(uint32_t(flags) >> shift) & OpRWFlags::kRW);
}
static inline RATiedFlags raMemIndexRwFlags(OpRWFlags flags) noexcept {
constexpr uint32_t shift = Support::ConstCTZ<uint32_t(OpRWFlags::kMemIndexRW)>::value;
return raUseOutFlagsFromRWFlags(OpRWFlags(uint32_t(flags) >> shift) & OpRWFlags::kRW);
}
// a64::RACFGBuilder
// =================
class RACFGBuilder : public RACFGBuilderT<RACFGBuilder> {
public:
Arch _arch;
inline RACFGBuilder(ARMRAPass* pass) noexcept
: RACFGBuilderT<RACFGBuilder>(pass),
_arch(pass->cc()->arch()) {}
inline Compiler* cc() const noexcept { return static_cast<Compiler*>(_cc); }
Error onInst(InstNode* inst, InstControlFlow& controlType, RAInstBuilder& ib) noexcept;
Error onBeforeInvoke(InvokeNode* invokeNode) noexcept;
Error onInvoke(InvokeNode* invokeNode, RAInstBuilder& ib) noexcept;
Error moveImmToRegArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_, BaseReg* out) noexcept;
Error moveImmToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_) noexcept;
Error moveRegToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const BaseReg& reg) noexcept;
Error onBeforeRet(FuncRetNode* funcRet) noexcept;
Error onRet(FuncRetNode* funcRet, RAInstBuilder& ib) noexcept;
};
// a64::RACFGBuilder - OnInst
// ==========================
// TODO: [ARM] This is just a workaround...
static InstControlFlow getControlFlowType(InstId instId) noexcept {
switch (instId) {
case Inst::kIdB:
case Inst::kIdBr:
if (BaseInst::extractARMCondCode(instId) == CondCode::kAL)
return InstControlFlow::kJump;
else
return InstControlFlow::kBranch;
case Inst::kIdBl:
case Inst::kIdBlr:
return InstControlFlow::kCall;
case Inst::kIdCbz:
case Inst::kIdCbnz:
case Inst::kIdTbz:
case Inst::kIdTbnz:
return InstControlFlow::kBranch;
case Inst::kIdRet:
return InstControlFlow::kReturn;
default:
return InstControlFlow::kRegular;
}
}
Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& controlType, RAInstBuilder& ib) noexcept {
InstRWInfo rwInfo;
InstId instId = inst->id();
if (Inst::isDefinedId(instId)) {
uint32_t opCount = inst->opCount();
const Operand* opArray = inst->operands();
ASMJIT_PROPAGATE(InstInternal::queryRWInfo(_arch, inst->baseInst(), opArray, opCount, &rwInfo));
const InstDB::InstInfo& instInfo = InstDB::infoById(instId);
uint32_t singleRegOps = 0;
if (opCount) {
uint32_t consecutiveOffset = 0xFFFFFFFFu;
uint32_t consecutiveParent = Globals::kInvalidId;
for (uint32_t i = 0; i < opCount; i++) {
const Operand& op = opArray[i];
const OpRWInfo& opRwInfo = rwInfo.operand(i);
if (op.isReg()) {
// Register Operand
// ----------------
const Reg& reg = op.as<Reg>();
RATiedFlags flags = raRegRwFlags(opRwInfo.opFlags());
uint32_t vIndex = Operand::virtIdToIndex(reg.id());
if (vIndex < Operand::kVirtIdCount) {
RAWorkReg* workReg;
ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(vIndex, &workReg));
// Use RW instead of Write in case that not the whole register is overwritten. This is important for
// liveness as we cannot kill a register that will be used.
if ((flags & RATiedFlags::kRW) == RATiedFlags::kWrite) {
if (workReg->regByteMask() & ~(opRwInfo.writeByteMask() | opRwInfo.extendByteMask())) {
// Not write-only operation.
flags = (flags & ~RATiedFlags::kOut) | (RATiedFlags::kRead | RATiedFlags::kUse);
}
}
RegGroup group = workReg->group();
RegMask useRegs = _pass->_availableRegs[group];
RegMask outRegs = useRegs;
uint32_t useId = BaseReg::kIdBad;
uint32_t outId = BaseReg::kIdBad;
uint32_t useRewriteMask = 0;
uint32_t outRewriteMask = 0;
if (opRwInfo.consecutiveLeadCount()) {
// There must be a single consecutive register lead, otherwise the RW data is invalid.
if (consecutiveOffset != 0xFFFFFFFFu)
return DebugUtils::errored(kErrorInvalidState);
// A consecutive lead register cannot be used as a consecutive +1/+2/+3 register, the registers must be distinct.
if (RATiedReg::consecutiveDataFromFlags(flags) != 0)
return DebugUtils::errored(kErrorNotConsecutiveRegs);
flags |= RATiedFlags::kLeadConsecutive | RATiedReg::consecutiveDataToFlags(opRwInfo.consecutiveLeadCount() - 1);
consecutiveOffset = 0;
RegMask filter = raConsecutiveLeadCountToRegMaskFilter[opRwInfo.consecutiveLeadCount()];
if (Support::test(flags, RATiedFlags::kUse)) {
flags |= RATiedFlags::kUseConsecutive;
useRegs &= filter;
}
else {
flags |= RATiedFlags::kOutConsecutive;
outRegs &= filter;
}
}
if (Support::test(flags, RATiedFlags::kUse)) {
useRewriteMask = Support::bitMask(inst->getRewriteIndex(&reg._baseId));
if (opRwInfo.hasOpFlag(OpRWFlags::kRegPhysId)) {
useId = opRwInfo.physId();
flags |= RATiedFlags::kUseFixed;
}
else if (opRwInfo.hasOpFlag(OpRWFlags::kConsecutive)) {
if (consecutiveOffset == 0xFFFFFFFFu)
return DebugUtils::errored(kErrorInvalidState);
flags |= RATiedFlags::kUseConsecutive | RATiedReg::consecutiveDataToFlags(++consecutiveOffset);
}
}
else {
outRewriteMask = Support::bitMask(inst->getRewriteIndex(&reg._baseId));
if (opRwInfo.hasOpFlag(OpRWFlags::kRegPhysId)) {
outId = opRwInfo.physId();
flags |= RATiedFlags::kOutFixed;
}
else if (opRwInfo.hasOpFlag(OpRWFlags::kConsecutive)) {
if (consecutiveOffset == 0xFFFFFFFFu)
return DebugUtils::errored(kErrorInvalidState);
flags |= RATiedFlags::kOutConsecutive | RATiedReg::consecutiveDataToFlags(++consecutiveOffset);
}
}
// Special cases regarding element access.
if (reg.as<Vec>().hasElementIndex()) {
// Only the first 0..15 registers can be used if the register uses
// element accessor that accesses half-words (h[0..7] elements).
if (instInfo.hasFlag(InstDB::kInstFlagVH0_15) && reg.as<Vec>().elementType() == Vec::kElementTypeH) {
if (Support::test(flags, RATiedFlags::kUse))
useId &= 0x0000FFFFu;
else
outId &= 0x0000FFFFu;
}
}
ASMJIT_PROPAGATE(ib.add(workReg, flags, useRegs, useId, useRewriteMask, outRegs, outId, outRewriteMask, opRwInfo.rmSize(), consecutiveParent));
if (singleRegOps == i)
singleRegOps++;
if (Support::test(flags, RATiedFlags::kLeadConsecutive | RATiedFlags::kUseConsecutive | RATiedFlags::kOutConsecutive))
consecutiveParent = workReg->workId();
}
}
else if (op.isMem()) {
// Memory Operand
// --------------
const Mem& mem = op.as<Mem>();
if (mem.isRegHome()) {
RAWorkReg* workReg;
ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(Operand::virtIdToIndex(mem.baseId()), &workReg));
_pass->getOrCreateStackSlot(workReg);
}
else if (mem.hasBaseReg()) {
uint32_t vIndex = Operand::virtIdToIndex(mem.baseId());
if (vIndex < Operand::kVirtIdCount) {
RAWorkReg* workReg;
ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(vIndex, &workReg));
RATiedFlags flags = raMemBaseRwFlags(opRwInfo.opFlags());
RegGroup group = workReg->group();
RegMask allocable = _pass->_availableRegs[group];
// Base registers have never fixed id on ARM.
const uint32_t useId = BaseReg::kIdBad;
const uint32_t outId = BaseReg::kIdBad;
uint32_t useRewriteMask = 0;
uint32_t outRewriteMask = 0;
if (Support::test(flags, RATiedFlags::kUse))
useRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._baseId));
else
outRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._baseId));
ASMJIT_PROPAGATE(ib.add(workReg, flags, allocable, useId, useRewriteMask, allocable, outId, outRewriteMask));
}
}
if (mem.hasIndexReg()) {
uint32_t vIndex = Operand::virtIdToIndex(mem.indexId());
if (vIndex < Operand::kVirtIdCount) {
RAWorkReg* workReg;
ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(vIndex, &workReg));
RATiedFlags flags = raMemIndexRwFlags(opRwInfo.opFlags());
RegGroup group = workReg->group();
RegMask allocable = _pass->_availableRegs[group];
// Index registers have never fixed id on ARM.
const uint32_t useId = BaseReg::kIdBad;
const uint32_t outId = BaseReg::kIdBad;
uint32_t useRewriteMask = 0;
uint32_t outRewriteMask = 0;
if (Support::test(flags, RATiedFlags::kUse))
useRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._data[Operand::kDataMemIndexId]));
else
outRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._data[Operand::kDataMemIndexId]));
ASMJIT_PROPAGATE(ib.add(workReg, RATiedFlags::kUse | RATiedFlags::kRead, allocable, useId, useRewriteMask, allocable, outId, outRewriteMask));
}
}
}
}
}
controlType = getControlFlowType(instId);
}
return kErrorOk;
}
// a64::RACFGBuilder - OnInvoke
// ============================
Error RACFGBuilder::onBeforeInvoke(InvokeNode* invokeNode) noexcept {
const FuncDetail& fd = invokeNode->detail();
uint32_t argCount = invokeNode->argCount();
cc()->_setCursor(invokeNode->prev());
for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) {
const FuncValuePack& argPack = fd.argPack(argIndex);
for (uint32_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) {
if (!argPack[valueIndex])
break;
const FuncValue& arg = argPack[valueIndex];
const Operand& op = invokeNode->arg(argIndex, valueIndex);
if (op.isNone())
continue;
if (op.isReg()) {
const Reg& reg = op.as<Reg>();
RAWorkReg* workReg;
ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(Operand::virtIdToIndex(reg.id()), &workReg));
if (arg.isReg()) {
RegGroup regGroup = workReg->group();
RegGroup argGroup = Reg::groupOf(arg.regType());
if (regGroup != argGroup) {
// TODO: [ARM] Conversion is not supported.
return DebugUtils::errored(kErrorInvalidAssignment);
}
}
else {
ASMJIT_PROPAGATE(moveRegToStackArg(invokeNode, arg, reg));
}
}
else if (op.isImm()) {
if (arg.isReg()) {
BaseReg reg;
ASMJIT_PROPAGATE(moveImmToRegArg(invokeNode, arg, op.as<Imm>(), &reg));
invokeNode->_args[argIndex][valueIndex] = reg;
}
else {
ASMJIT_PROPAGATE(moveImmToStackArg(invokeNode, arg, op.as<Imm>()));
}
}
}
}
cc()->_setCursor(invokeNode);
if (fd.hasRet()) {
for (uint32_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) {
const FuncValue& ret = fd.ret(valueIndex);
if (!ret)
break;
const Operand& op = invokeNode->ret(valueIndex);
if (op.isReg()) {
const Reg& reg = op.as<Reg>();
RAWorkReg* workReg;
ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(Operand::virtIdToIndex(reg.id()), &workReg));
if (ret.isReg()) {
RegGroup regGroup = workReg->group();
RegGroup retGroup = Reg::groupOf(ret.regType());
if (regGroup != retGroup) {
// TODO: [ARM] Conversion is not supported.
return DebugUtils::errored(kErrorInvalidAssignment);
}
}
}
}
}
// This block has function call(s).
_curBlock->addFlags(RABlockFlags::kHasFuncCalls);
_pass->func()->frame().addAttributes(FuncAttributes::kHasFuncCalls);
_pass->func()->frame().updateCallStackSize(fd.argStackSize());
return kErrorOk;
}
Error RACFGBuilder::onInvoke(InvokeNode* invokeNode, RAInstBuilder& ib) noexcept {
uint32_t argCount = invokeNode->argCount();
const FuncDetail& fd = invokeNode->detail();
for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) {
const FuncValuePack& argPack = fd.argPack(argIndex);
for (uint32_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) {
if (!argPack[valueIndex])
continue;
const FuncValue& arg = argPack[valueIndex];
const Operand& op = invokeNode->arg(argIndex, valueIndex);
if (op.isNone())
continue;
if (op.isReg()) {
const Reg& reg = op.as<Reg>();
RAWorkReg* workReg;
ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(Operand::virtIdToIndex(reg.id()), &workReg));
if (arg.isIndirect()) {
RegGroup regGroup = workReg->group();
if (regGroup != RegGroup::kGp)
return DebugUtils::errored(kErrorInvalidState);
ASMJIT_PROPAGATE(ib.addCallArg(workReg, arg.regId()));
}
else if (arg.isReg()) {
RegGroup regGroup = workReg->group();
RegGroup argGroup = Reg::groupOf(arg.regType());
if (regGroup == argGroup) {
ASMJIT_PROPAGATE(ib.addCallArg(workReg, arg.regId()));
}
}
}
}
}
for (uint32_t retIndex = 0; retIndex < Globals::kMaxValuePack; retIndex++) {
const FuncValue& ret = fd.ret(retIndex);
if (!ret)
break;
const Operand& op = invokeNode->ret(retIndex);
if (op.isReg()) {
const Reg& reg = op.as<Reg>();
RAWorkReg* workReg;
ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(Operand::virtIdToIndex(reg.id()), &workReg));
if (ret.isReg()) {
RegGroup regGroup = workReg->group();
RegGroup retGroup = Reg::groupOf(ret.regType());
if (regGroup == retGroup) {
ASMJIT_PROPAGATE(ib.addCallRet(workReg, ret.regId()));
}
}
else {
return DebugUtils::errored(kErrorInvalidAssignment);
}
}
}
// Setup clobbered registers.
ib._clobbered[0] = Support::lsbMask<RegMask>(_pass->_physRegCount[RegGroup(0)]) & ~fd.preservedRegs(RegGroup(0));
ib._clobbered[1] = Support::lsbMask<RegMask>(_pass->_physRegCount[RegGroup(1)]) & ~fd.preservedRegs(RegGroup(1));
ib._clobbered[2] = Support::lsbMask<RegMask>(_pass->_physRegCount[RegGroup(2)]) & ~fd.preservedRegs(RegGroup(2));
ib._clobbered[3] = Support::lsbMask<RegMask>(_pass->_physRegCount[RegGroup(3)]) & ~fd.preservedRegs(RegGroup(3));
return kErrorOk;
}
// a64::RACFGBuilder - MoveImmToRegArg
// ===================================
Error RACFGBuilder::moveImmToRegArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_, BaseReg* out) noexcept {
DebugUtils::unused(invokeNode);
ASMJIT_ASSERT(arg.isReg());
Imm imm(imm_);
TypeId typeId = TypeId::kVoid;
switch (arg.typeId()) {
case TypeId::kInt8 : typeId = TypeId::kUInt64; imm.signExtend8Bits(); break;
case TypeId::kUInt8 : typeId = TypeId::kUInt64; imm.zeroExtend8Bits(); break;
case TypeId::kInt16 : typeId = TypeId::kUInt64; imm.signExtend16Bits(); break;
case TypeId::kUInt16: typeId = TypeId::kUInt64; imm.zeroExtend16Bits(); break;
case TypeId::kInt32 : typeId = TypeId::kUInt64; imm.signExtend32Bits(); break;
case TypeId::kUInt32: typeId = TypeId::kUInt64; imm.zeroExtend32Bits(); break;
case TypeId::kInt64 : typeId = TypeId::kUInt64; break;
case TypeId::kUInt64: typeId = TypeId::kUInt64; break;
default:
return DebugUtils::errored(kErrorInvalidAssignment);
}
ASMJIT_PROPAGATE(cc()->_newReg(out, typeId, nullptr));
cc()->virtRegById(out->id())->setWeight(BaseRAPass::kCallArgWeight);
return cc()->mov(out->as<Gp>(), imm);
}
// a64::RACFGBuilder - MoveImmToStackArg
// =====================================
Error RACFGBuilder::moveImmToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_) noexcept {
BaseReg reg;
ASMJIT_PROPAGATE(moveImmToRegArg(invokeNode, arg, imm_, &reg));
ASMJIT_PROPAGATE(moveRegToStackArg(invokeNode, arg, reg));
return kErrorOk;
}
// a64::RACFGBuilder - MoveRegToStackArg
// =====================================
Error RACFGBuilder::moveRegToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const BaseReg& reg) noexcept {
DebugUtils::unused(invokeNode);
Mem stackPtr = ptr(_pass->_sp.as<Gp>(), arg.stackOffset());
if (reg.isGp())
return cc()->str(reg.as<Gp>(), stackPtr);
if (reg.isVec())
return cc()->str(reg.as<Vec>(), stackPtr);
return DebugUtils::errored(kErrorInvalidState);
}
// a64::RACFGBuilder - OnReg
// =========================
Error RACFGBuilder::onBeforeRet(FuncRetNode* funcRet) noexcept {
DebugUtils::unused(funcRet);
return kErrorOk;
}
Error RACFGBuilder::onRet(FuncRetNode* funcRet, RAInstBuilder& ib) noexcept {
const FuncDetail& funcDetail = _pass->func()->detail();
const Operand* opArray = funcRet->operands();
uint32_t opCount = funcRet->opCount();
for (uint32_t i = 0; i < opCount; i++) {
const Operand& op = opArray[i];
if (op.isNone()) continue;
const FuncValue& ret = funcDetail.ret(i);
if (ASMJIT_UNLIKELY(!ret.isReg()))
return DebugUtils::errored(kErrorInvalidAssignment);
if (op.isReg()) {
// Register return value.
const Reg& reg = op.as<Reg>();
uint32_t vIndex = Operand::virtIdToIndex(reg.id());
if (vIndex < Operand::kVirtIdCount) {
RAWorkReg* workReg;
ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(vIndex, &workReg));
RegGroup group = workReg->group();
RegMask allocable = _pass->_availableRegs[group];
ASMJIT_PROPAGATE(ib.add(workReg, RATiedFlags::kUse | RATiedFlags::kRead, allocable, ret.regId(), 0, 0, BaseReg::kIdBad, 0));
}
}
else {
return DebugUtils::errored(kErrorInvalidAssignment);
}
}
return kErrorOk;
}
// a64::ARMRAPass - Construction & Destruction
// ===========================================
ARMRAPass::ARMRAPass() noexcept
: BaseRAPass() { _iEmitHelper = &_emitHelper; }
ARMRAPass::~ARMRAPass() noexcept {}
// a64::ARMRAPass - OnInit / OnDone
// ================================
void ARMRAPass::onInit() noexcept {
Arch arch = cc()->arch();
_emitHelper._emitter = _cb;
_archTraits = &ArchTraits::byArch(arch);
_physRegCount.set(RegGroup::kGp, 32);
_physRegCount.set(RegGroup::kVec, 32);
_physRegCount.set(RegGroup::kExtraVirt2, 0);
_physRegCount.set(RegGroup::kExtraVirt3, 0);
_buildPhysIndex();
_availableRegCount = _physRegCount;
_availableRegs[RegGroup::kGp] = Support::lsbMask<uint32_t>(_physRegCount.get(RegGroup::kGp));
_availableRegs[RegGroup::kVec] = Support::lsbMask<uint32_t>(_physRegCount.get(RegGroup::kVec));
_availableRegs[RegGroup::kExtraVirt3] = Support::lsbMask<uint32_t>(_physRegCount.get(RegGroup::kExtraVirt2));
_availableRegs[RegGroup::kExtraVirt3] = Support::lsbMask<uint32_t>(_physRegCount.get(RegGroup::kExtraVirt3));
_scratchRegIndexes[0] = uint8_t(27);
_scratchRegIndexes[1] = uint8_t(28);
// The architecture specific setup makes implicitly all registers available. So
// make unavailable all registers that are special and cannot be used in general.
bool hasFP = _func->frame().hasPreservedFP();
if (hasFP)
makeUnavailable(RegGroup::kGp, Gp::kIdFp);
makeUnavailable(RegGroup::kGp, Gp::kIdSp);
makeUnavailable(RegGroup::kGp, Gp::kIdOs); // OS-specific use, usually TLS.
_sp = sp;
_fp = x29;
}
void ARMRAPass::onDone() noexcept {}
// a64::ARMRAPass - BuildCFG
// =========================
Error ARMRAPass::buildCFG() noexcept {
return RACFGBuilder(this).run();
}
// a64::ARMRAPass - Rewrite
// ========================
ASMJIT_FAVOR_SPEED Error ARMRAPass::_rewrite(BaseNode* first, BaseNode* stop) noexcept {
uint32_t virtCount = cc()->_vRegArray.size();
BaseNode* node = first;
while (node != stop) {
BaseNode* next = node->next();
if (node->isInst()) {
InstNode* inst = node->as<InstNode>();
RAInst* raInst = node->passData<RAInst>();
Operand* operands = inst->operands();
uint32_t opCount = inst->opCount();
uint32_t i;
// Rewrite virtual registers into physical registers.
if (raInst) {
// If the instruction contains pass data (raInst) then it was a subject
// for register allocation and must be rewritten to use physical regs.
RATiedReg* tiedRegs = raInst->tiedRegs();
uint32_t tiedCount = raInst->tiedCount();
for (i = 0; i < tiedCount; i++) {
RATiedReg* tiedReg = &tiedRegs[i];
Support::BitWordIterator<uint32_t> useIt(tiedReg->useRewriteMask());
uint32_t useId = tiedReg->useId();
while (useIt.hasNext())
inst->rewriteIdAtIndex(useIt.next(), useId);
Support::BitWordIterator<uint32_t> outIt(tiedReg->outRewriteMask());
uint32_t outId = tiedReg->outId();
while (outIt.hasNext())
inst->rewriteIdAtIndex(outIt.next(), outId);
}
// This data is allocated by Zone passed to `runOnFunction()`, which
// will be reset after the RA pass finishes. So reset this data to
// prevent having a dead pointer after the RA pass is complete.
node->resetPassData();
if (ASMJIT_UNLIKELY(node->type() != NodeType::kInst)) {
// FuncRet terminates the flow, it must either be removed if the exit
// label is next to it (optimization) or patched to an architecture
// dependent jump instruction that jumps to the function's exit before
// the epilog.
if (node->type() == NodeType::kFuncRet) {
RABlock* block = raInst->block();
if (!isNextTo(node, _func->exitNode())) {
cc()->_setCursor(node->prev());
ASMJIT_PROPAGATE(emitJump(_func->exitNode()->label()));
}
BaseNode* prev = node->prev();
cc()->removeNode(node);
block->setLast(prev);
}
}
}
// Rewrite stack slot addresses.
for (i = 0; i < opCount; i++) {
Operand& op = operands[i];
if (op.isMem()) {
BaseMem& mem = op.as<BaseMem>();
if (mem.isRegHome()) {
uint32_t virtIndex = Operand::virtIdToIndex(mem.baseId());
if (ASMJIT_UNLIKELY(virtIndex >= virtCount))
return DebugUtils::errored(kErrorInvalidVirtId);
VirtReg* virtReg = cc()->virtRegByIndex(virtIndex);
RAWorkReg* workReg = virtReg->workReg();
ASMJIT_ASSERT(workReg != nullptr);
RAStackSlot* slot = workReg->stackSlot();
int32_t offset = slot->offset();
mem._setBase(_sp.type(), slot->baseRegId());
mem.clearRegHome();
mem.addOffsetLo32(offset);
}
}
}
}
node = next;
}
return kErrorOk;
}
// a64::ARMRAPass - Prolog & Epilog
// ================================
Error ARMRAPass::updateStackFrame() noexcept {
if (_func->frame().hasFuncCalls())
_func->frame().addDirtyRegs(RegGroup::kGp, Support::bitMask(Gp::kIdLr));
return BaseRAPass::updateStackFrame();
}
// a64::ARMRAPass - OnEmit
// =======================
Error ARMRAPass::emitMove(uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept {
RAWorkReg* wReg = workRegById(workId);
BaseReg dst(wReg->signature(), dstPhysId);
BaseReg src(wReg->signature(), srcPhysId);
const char* comment = nullptr;
#ifndef ASMJIT_NO_LOGGING
if (hasDiagnosticOption(DiagnosticOptions::kRAAnnotate)) {
_tmpString.assignFormat("<MOVE> %s", workRegById(workId)->name());
comment = _tmpString.data();
}
#endif
return _emitHelper.emitRegMove(dst, src, wReg->typeId(), comment);
}
Error ARMRAPass::emitSwap(uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId, uint32_t bPhysId) noexcept {
DebugUtils::unused(aWorkId, aPhysId, bWorkId, bPhysId);
return DebugUtils::errored(kErrorInvalidState);
}
Error ARMRAPass::emitLoad(uint32_t workId, uint32_t dstPhysId) noexcept {
RAWorkReg* wReg = workRegById(workId);
BaseReg dstReg(wReg->signature(), dstPhysId);
BaseMem srcMem(workRegAsMem(wReg));
const char* comment = nullptr;
#ifndef ASMJIT_NO_LOGGING
if (hasDiagnosticOption(DiagnosticOptions::kRAAnnotate)) {
_tmpString.assignFormat("<LOAD> %s", workRegById(workId)->name());
comment = _tmpString.data();
}
#endif
return _emitHelper.emitRegMove(dstReg, srcMem, wReg->typeId(), comment);
}
Error ARMRAPass::emitSave(uint32_t workId, uint32_t srcPhysId) noexcept {
RAWorkReg* wReg = workRegById(workId);
BaseMem dstMem(workRegAsMem(wReg));
BaseReg srcReg(wReg->signature(), srcPhysId);
const char* comment = nullptr;
#ifndef ASMJIT_NO_LOGGING
if (hasDiagnosticOption(DiagnosticOptions::kRAAnnotate)) {
_tmpString.assignFormat("<SAVE> %s", workRegById(workId)->name());
comment = _tmpString.data();
}
#endif
return _emitHelper.emitRegMove(dstMem, srcReg, wReg->typeId(), comment);
}
Error ARMRAPass::emitJump(const Label& label) noexcept {
return cc()->b(label);
}
Error ARMRAPass::emitPreCall(InvokeNode* invokeNode) noexcept {
DebugUtils::unused(invokeNode);
return kErrorOk;
}
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_AARCH64 && !ASMJIT_NO_COMPILER
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_ARM_A64RAPASS_P_H_INCLUDED
#define ASMJIT_ARM_A64RAPASS_P_H_INCLUDED
#include "../core/api-config.h"
#ifndef ASMJIT_NO_COMPILER
#include "../core/compiler.h"
#include "../core/rabuilders_p.h"
#include "../core/rapass_p.h"
#include "../arm/a64assembler.h"
#include "../arm/a64compiler.h"
#include "../arm/a64emithelper_p.h"
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
//! \cond INTERNAL
//! \addtogroup asmjit_a64
//! \{
//! ARM register allocation pass.
//!
//! Takes care of generating function prologs and epilogs, and also performs
//! register allocation.
class ARMRAPass : public BaseRAPass {
public:
ASMJIT_NONCOPYABLE(ARMRAPass)
typedef BaseRAPass Base;
EmitHelper _emitHelper;
//! \name Construction & Destruction
//! \{
ARMRAPass() noexcept;
virtual ~ARMRAPass() noexcept;
//! \}
//! \name Accessors
//! \{
//! Returns the compiler casted to `arm::Compiler`.
inline Compiler* cc() const noexcept { return static_cast<Compiler*>(_cb); }
//! Returns emit helper.
inline EmitHelper* emitHelper() noexcept { return &_emitHelper; }
//! \}
//! \name Events
//! \{
void onInit() noexcept override;
void onDone() noexcept override;
//! \}
//! \name CFG
//! \{
Error buildCFG() noexcept override;
//! \}
//! \name Rewrite
//! \{
Error _rewrite(BaseNode* first, BaseNode* stop) noexcept override;
//! \}
//! \name Prolog & Epilog
//! \{
Error updateStackFrame() noexcept override;
//! \}
//! \name Emit Helpers
//! \{
Error emitMove(uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept override;
Error emitSwap(uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId, uint32_t bPhysId) noexcept override;
Error emitLoad(uint32_t workId, uint32_t dstPhysId) noexcept override;
Error emitSave(uint32_t workId, uint32_t srcPhysId) noexcept override;
Error emitJump(const Label& label) noexcept override;
Error emitPreCall(InvokeNode* invokeNode) noexcept override;
//! \}
};
//! \}
//! \endcond
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_COMPILER
#endif // ASMJIT_ARM_A64RAPASS_P_H_INCLUDED
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_ARM_A64UTILS_H_INCLUDED
#define ASMJIT_ARM_A64UTILS_H_INCLUDED
#include "../arm/a64globals.h"
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
//! \addtogroup asmjit_a64
//! \{
//! Public utilities and helpers for targeting AArch64 architecture.
namespace Utils {
//! Decomposed fields of a logical immediate value (AArch64).
struct LogicalImm {
uint32_t n;
uint32_t s;
uint32_t r;
};
//! Encodes the given `imm` value of the given `width` to a logical immediate value represented as N, S, and R fields
//! and writes these fields to `out`.
//!
//! Encoding Table:
//!
//! ```
//! +---+--------+--------+------+
//! | N | ImmS | ImmR | Size |
//! +---+--------+--------+------+
//! | 1 | ssssss | rrrrrr | 64 |
//! | 0 | 0sssss | .rrrrr | 32 |
//! | 0 | 10ssss | ..rrrr | 16 |
//! | 0 | 110sss | ...rrr | 8 |
//! | 0 | 1110ss | ....rr | 4 |
//! | 0 | 11110s | .....r | 2 |
//! +---+--------+--------+------+
//! ```
ASMJIT_MAYBE_UNUSED
static bool encodeLogicalImm(uint64_t imm, uint32_t width, a64::Utils::LogicalImm* out) noexcept {
// Determine the element width, which must be 2, 4, 8, 16, 32, or 64 bits.
do {
width /= 2;
uint64_t mask = (uint64_t(1) << width) - 1u;
if ((imm & mask) != ((imm >> width) & mask)) {
width *= 2;
break;
}
} while (width > 2);
// Patterns of all zeros and all ones are not encodable.
uint64_t lsbMask = Support::lsbMask<uint64_t>(width);
imm &= lsbMask;
if (imm == 0 || imm == lsbMask)
return false;
// Inspect the pattern and get the most important bit indexes.
//
// oIndex <-+ +-> zIndex
// | |
// |..zeros..|oCount|zCount|..ones..|
// |000000000|111111|000000|11111111|
uint32_t zIndex = Support::ctz(~imm);
uint64_t zImm = imm ^ ((uint64_t(1) << zIndex) - 1);
uint32_t zCount = (zImm ? Support::ctz(zImm) : width) - zIndex;
uint32_t oIndex = zIndex + zCount;
uint64_t oImm = ~(zImm ^ Support::lsbMask<uint64_t>(oIndex));
uint32_t oCount = (oImm ? Support::ctz(oImm) : width) - (oIndex);
// Verify whether the bit-pattern is encodable.
uint64_t mustBeZero = oImm ^ ~Support::lsbMask<uint64_t>(oIndex + oCount);
if (mustBeZero != 0 || (zIndex > 0 && width - (oIndex + oCount) != 0))
return false;
out->n = width == 64;
out->s = (oCount + zIndex - 1) | (Support::neg(width * 2) & 0x3F);
out->r = width - oIndex;
return true;
}
//! Returns true if the given `imm` value is encodable as a logical immediate. The `width` argument describes the
//! width of the operation, and must be either 32 or 64. This function can be used to test whether an immediate
//! value can be used with AND, ANDS, BIC, BICS, EON, EOR, ORN, and ORR instruction.
ASMJIT_MAYBE_UNUSED
static inline bool isLogicalImm(uint64_t imm, uint32_t width) noexcept {
LogicalImm dummy;
return encodeLogicalImm(imm, width, &dummy);
}
//! Returns true if the given `imm` value is a byte mask. Byte mask has each byte part of the value set to either
//! 0x00 or 0xFF. Some ARM instructions accept immediates that form a byte-mask and this function can be used to
//! verify that the immediate is encodable before using the value.
template<typename T>
static inline bool isByteMaskImm8(const T& imm) noexcept {
constexpr T kMask = T(0x0101010101010101 & Support::allOnes<T>());
return imm == (imm & kMask) * T(255);
}
//! \cond
//! A generic implementation that checjs whether a floating point value can be converted to ARM Imm8.
template<typename T, uint32_t kNumBBits, uint32_t kNumCDEFGHBits, uint32_t kNumZeroBits>
static inline bool isFPImm8Generic(T val) noexcept {
constexpr uint32_t kAllBsMask = Support::lsbMask<uint32_t>(kNumBBits);
constexpr uint32_t kB0Pattern = Support::bitMask(kNumBBits - 1);
constexpr uint32_t kB1Pattern = kAllBsMask ^ kB0Pattern;
T immZ = val & Support::lsbMask<T>(kNumZeroBits);
uint32_t immB = uint32_t(val >> (kNumZeroBits + kNumCDEFGHBits)) & kAllBsMask;
// ImmZ must be all zeros and ImmB must either be B0 or B1 pattern.
return immZ == 0 && (immB == kB0Pattern || immB == kB1Pattern);
}
//! \endcond
//! Returns true if the given half precision floating point `val` can be encoded as ARM IMM8 value, which represents
//! a limited set of floating point immediate values, which can be used with FMOV instruction.
//!
//! The floating point must have bits distributed in the following way:
//!
//! ```
//! [aBbbcdef|gh000000]
//! ```
static inline bool isFP16Imm8(uint32_t val) noexcept { return isFPImm8Generic<uint32_t, 3, 6, 6>(val); }
//! Returns true if the given single precision floating point `val` can be encoded as ARM IMM8 value, which represents
//! a limited set of floating point immediate values, which can be used with FMOV instruction.
//!
//! The floating point must have bits distributed in the following way:
//!
//! ```
//! [aBbbbbbc|defgh000|00000000|00000000]
//! ```
static inline bool isFP32Imm8(uint32_t val) noexcept { return isFPImm8Generic<uint32_t, 6, 6, 19>(val); }
//! \overload
static inline bool isFP32Imm8(float val) noexcept { return isFP32Imm8(Support::bitCast<uint32_t>(val)); }
//! Returns true if the given double precision floating point `val` can be encoded as ARM IMM8 value, which represents
//! a limited set of floating point immediate values, which can be used with FMOV instruction.
//!
//! The floating point must have bits distributed in the following way:
//!
//! ```
//! [aBbbbbbb|bbcdefgh|00000000|00000000|00000000|00000000|00000000|00000000]
//! ```
static inline bool isFP64Imm8(uint64_t val) noexcept { return isFPImm8Generic<uint64_t, 9, 6, 48>(val); }
//! \overload
static inline bool isFP64Imm8(double val) noexcept { return isFP64Imm8(Support::bitCast<uint64_t>(val)); }
//! \cond
template<typename T, uint32_t kNumBBits, uint32_t kNumCDEFGHBits, uint32_t kNumZeroBits>
static inline uint32_t encodeFPToImm8Generic(T val) noexcept {
uint32_t bits = uint32_t(val >> kNumZeroBits);
return ((bits >> (kNumBBits + kNumCDEFGHBits - 7)) & 0x80u) | (bits & 0x7F);
}
//! \endcond
//! Encodes a double precision floating point value into IMM8 format.
//!
//! \note This function expects that `isFP64Imm8(val) == true` so it doesn't perform any checks of the value and just
//! rearranges some bits into Imm8 order.
static inline uint32_t encodeFP64ToImm8(uint64_t val) noexcept { return encodeFPToImm8Generic<uint64_t, 9, 6, 48>(val); }
//! \overload
static inline uint32_t encodeFP64ToImm8(double val) noexcept { return encodeFP64ToImm8(Support::bitCast<uint64_t>(val)); }
} // {Utils}
//! \}
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_A64UTILS_H_INCLUDED
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#ifndef ASMJIT_NO_LOGGING
#include "../core/misc_p.h"
#include "../core/support.h"
#include "../arm/armformatter_p.h"
#include "../arm/armoperand.h"
#include "../arm/a64instapi_p.h"
#include "../arm/a64instdb_p.h"
#ifndef ASMJIT_NO_COMPILER
#include "../core/compiler.h"
#endif
ASMJIT_BEGIN_SUB_NAMESPACE(arm)
// arm::FormatterInternal - Format Feature
// =======================================
Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept {
// @EnumStringBegin{"enum": "CpuFeatures::ARM", "output": "sFeature", "strip": "k"}@
static const char sFeatureString[] =
"None\0"
"THUMB\0"
"THUMBv2\0"
"ARMv6\0"
"ARMv7\0"
"ARMv8a\0"
"ARMv8_1a\0"
"ARMv8_2a\0"
"ARMv8_3a\0"
"ARMv8_4a\0"
"ARMv8_5a\0"
"ARMv8_6a\0"
"ARMv8_7a\0"
"VFPv2\0"
"VFPv3\0"
"VFPv4\0"
"VFP_D32\0"
"AES\0"
"ALTNZCV\0"
"ASIMD\0"
"BF16\0"
"BTI\0"
"CPUID\0"
"CRC32\0"
"DGH\0"
"DIT\0"
"DOTPROD\0"
"EDSP\0"
"FCMA\0"
"FJCVTZS\0"
"FLAGM\0"
"FP16CONV\0"
"FP16FML\0"
"FP16FULL\0"
"FRINT\0"
"I8MM\0"
"IDIVA\0"
"IDIVT\0"
"LSE\0"
"MTE\0"
"RCPC_IMMO\0"
"RDM\0"
"PMU\0"
"PMULL\0"
"RNG\0"
"SB\0"
"SHA1\0"
"SHA2\0"
"SHA3\0"
"SHA512\0"
"SM3\0"
"SM4\0"
"SSBS\0"
"SVE\0"
"SVE_BF16\0"
"SVE_F32MM\0"
"SVE_F64MM\0"
"SVE_I8MM\0"
"SVE_PMULL\0"
"SVE2\0"
"SVE2_AES\0"
"SVE2_BITPERM\0"
"SVE2_SHA3\0"
"SVE2_SM4\0"
"TME\0"
"<Unknown>\0";
static const uint16_t sFeatureIndex[] = {
0, 5, 11, 19, 25, 31, 38, 47, 56, 65, 74, 83, 92, 101, 107, 113, 119, 127,
131, 139, 145, 150, 154, 160, 166, 170, 174, 182, 187, 192, 200, 206, 215,
223, 232, 238, 243, 249, 255, 259, 263, 273, 277, 281, 287, 291, 294, 299,
304, 309, 316, 320, 324, 329, 333, 342, 352, 362, 371, 381, 386, 395, 408,
418, 427, 431
};
// @EnumStringEnd@
return sb.append(sFeatureString + sFeatureIndex[Support::min<uint32_t>(featureId, uint32_t(CpuFeatures::ARM::kMaxValue) + 1)]);
}
// arm::FormatterInternal - Format Constants
// =========================================
ASMJIT_FAVOR_SIZE Error FormatterInternal::formatCondCode(String& sb, CondCode cc) noexcept {
static const char condCodeData[] =
"al\0" "na\0"
"eq\0" "ne\0"
"cs\0" "cc\0" "mi\0" "pl\0" "vs\0" "vc\0"
"hi\0" "ls\0" "ge\0" "lt\0" "gt\0" "le\0"
"<Unknown>";
return sb.append(condCodeData + Support::min<uint32_t>(uint32_t(cc), 16u) * 3);
}
ASMJIT_FAVOR_SIZE Error FormatterInternal::formatShiftOp(String& sb, ShiftOp shiftOp) noexcept {
const char* str = "<Unknown>";
switch (shiftOp) {
case ShiftOp::kLSL: str = "lsl"; break;
case ShiftOp::kLSR: str = "lsr"; break;
case ShiftOp::kASR: str = "asr"; break;
case ShiftOp::kROR: str = "ror"; break;
case ShiftOp::kRRX: str = "rrx"; break;
case ShiftOp::kMSL: str = "msl"; break;
case ShiftOp::kUXTB: str = "uxtb"; break;
case ShiftOp::kUXTH: str = "uxth"; break;
case ShiftOp::kUXTW: str = "uxtw"; break;
case ShiftOp::kUXTX: str = "uxtx"; break;
case ShiftOp::kSXTB: str = "sxtb"; break;
case ShiftOp::kSXTH: str = "sxth"; break;
case ShiftOp::kSXTW: str = "sxtw"; break;
case ShiftOp::kSXTX: str = "sxtx"; break;
}
return sb.append(str);
}
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_LOGGING
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_ARM_ARMFORMATTER_P_H_INCLUDED
#define ASMJIT_ARM_ARMFORMATTER_P_H_INCLUDED
#include "../core/api-config.h"
#ifndef ASMJIT_NO_LOGGING
#include "../core/formatter.h"
#include "../core/string.h"
#include "../arm/armglobals.h"
ASMJIT_BEGIN_SUB_NAMESPACE(arm)
//! \cond INTERNAL
//! \addtogroup asmjit_arm
//! \{
namespace FormatterInternal {
Error ASMJIT_CDECL formatFeature(
String& sb,
uint32_t featureId) noexcept;
Error ASMJIT_CDECL formatCondCode(
String& sb,
CondCode cc) noexcept;
Error ASMJIT_CDECL formatShiftOp(
String& sb,
ShiftOp shiftOp) noexcept;
} // {FormatterInternal}
//! \}
//! \endcond
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_LOGGING
#endif // ASMJIT_ARM_ARMFORMATTER_P_H_INCLUDED
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_ARM_ARMGLOBALS_H_INCLUDED
#define ASMJIT_ARM_ARMGLOBALS_H_INCLUDED
#include "../core/archcommons.h"
#include "../core/inst.h"
//! \namespace asmjit::arm
//! \ingroup asmjit_arm
//!
//! API shared between AArch32 & AArch64 backends.
ASMJIT_BEGIN_SUB_NAMESPACE(arm)
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_ARMGLOBALS_H_INCLUDED
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_ARM_ARMOPERAND_H_INCLUDED
#define ASMJIT_ARM_ARMOPERAND_H_INCLUDED
#include "../core/archtraits.h"
#include "../core/operand.h"
#include "../core/type.h"
#include "../arm/armglobals.h"
ASMJIT_BEGIN_SUB_NAMESPACE(arm)
//! \addtogroup asmjit_arm
//! \{
class Reg;
class Mem;
class Gp;
class GpW;
class GpX;
class Vec;
class VecB;
class VecH;
class VecS;
class VecD;
class VecV;
//! Register traits (ARM/AArch64).
//!
//! Register traits contains information about a particular register type. It's used by asmjit to setup register
//! information on-the-fly and to populate tables that contain register information (this way it's possible to
//! change register types and groups without having to reorder these tables).
template<RegType kRegType>
struct RegTraits : public BaseRegTraits {};
//! \cond
// <--------------------+-----+-------------------------+------------------------+---+---+------------------+
// | Reg | Reg-Type | Reg-Group |Sz |Cnt| TypeId |
// <--------------------+-----+-------------------------+------------------------+---+---+------------------+
ASMJIT_DEFINE_REG_TRAITS(GpW , RegType::kARM_GpW , RegGroup::kGp , 4 , 32, TypeId::kInt32 );
ASMJIT_DEFINE_REG_TRAITS(GpX , RegType::kARM_GpX , RegGroup::kGp , 8 , 32, TypeId::kInt64 );
ASMJIT_DEFINE_REG_TRAITS(VecB , RegType::kARM_VecB , RegGroup::kVec , 1 , 32, TypeId::kVoid );
ASMJIT_DEFINE_REG_TRAITS(VecH , RegType::kARM_VecH , RegGroup::kVec , 2 , 32, TypeId::kVoid );
ASMJIT_DEFINE_REG_TRAITS(VecS , RegType::kARM_VecS , RegGroup::kVec , 4 , 32, TypeId::kInt32x1 );
ASMJIT_DEFINE_REG_TRAITS(VecD , RegType::kARM_VecD , RegGroup::kVec , 8 , 32, TypeId::kInt32x2 );
ASMJIT_DEFINE_REG_TRAITS(VecV , RegType::kARM_VecV , RegGroup::kVec , 16, 32, TypeId::kInt32x4 );
//! \endcond
//! Register (ARM).
class Reg : public BaseReg {
public:
ASMJIT_DEFINE_ABSTRACT_REG(Reg, BaseReg)
//! Gets whether the register is a `R|W` register (32-bit).
inline constexpr bool isGpW() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpW>::kSignature; }
//! Gets whether the register is an `X` register (64-bit).
inline constexpr bool isGpX() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpX>::kSignature; }
//! Gets whether the register is a VEC-B register (8-bit).
inline constexpr bool isVecB() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecB>::kSignature; }
//! Gets whether the register is a VEC-H register (16-bit).
inline constexpr bool isVecH() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecH>::kSignature; }
//! Gets whether the register is a VEC-S register (32-bit).
inline constexpr bool isVecS() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecS>::kSignature; }
//! Gets whether the register is a VEC-D register (64-bit).
inline constexpr bool isVecD() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecD>::kSignature; }
//! Gets whether the register is a VEC-Q register (128-bit).
inline constexpr bool isVecQ() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
//! Gets whether the register is either VEC-D (64-bit) or VEC-Q (128-bit).
inline constexpr bool isVecDOrQ() const noexcept { return uint32_t(type()) - uint32_t(RegType::kARM_VecD) <= 1u; }
//! Gets whether the register is a VEC-V register (128-bit).
inline constexpr bool isVecV() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
template<RegType kRegType>
inline void setRegT(uint32_t id) noexcept {
setSignature(RegTraits<kRegType>::kSignature);
setId(id);
}
inline void setTypeAndId(RegType type, uint32_t id) noexcept {
setSignature(signatureOf(type));
setId(id);
}
static inline RegGroup groupOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToGroup(type); }
static inline TypeId typeIdOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToTypeId(type); }
static inline OperandSignature signatureOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToSignature(type); }
template<RegType kRegType>
static inline RegGroup groupOfT() noexcept { return RegTraits<kRegType>::kGroup; }
template<RegType kRegType>
static inline TypeId typeIdOfT() noexcept { return RegTraits<kRegType>::kTypeId; }
template<RegType kRegType>
static inline OperandSignature signatureOfT() noexcept { return RegTraits<kRegType>::kSignature; }
static inline bool isGpW(const Operand_& op) noexcept { return op.as<Reg>().isGpW(); }
static inline bool isGpX(const Operand_& op) noexcept { return op.as<Reg>().isGpX(); }
static inline bool isVecB(const Operand_& op) noexcept { return op.as<Reg>().isVecB(); }
static inline bool isVecH(const Operand_& op) noexcept { return op.as<Reg>().isVecH(); }
static inline bool isVecS(const Operand_& op) noexcept { return op.as<Reg>().isVecS(); }
static inline bool isVecD(const Operand_& op) noexcept { return op.as<Reg>().isVecD(); }
static inline bool isVecQ(const Operand_& op) noexcept { return op.as<Reg>().isVecQ(); }
static inline bool isVecV(const Operand_& op) noexcept { return op.as<Reg>().isVecV(); }
static inline bool isGpW(const Operand_& op, uint32_t id) noexcept { return isGpW(op) & (op.id() == id); }
static inline bool isGpX(const Operand_& op, uint32_t id) noexcept { return isGpX(op) & (op.id() == id); }
static inline bool isVecB(const Operand_& op, uint32_t id) noexcept { return isVecB(op) & (op.id() == id); }
static inline bool isVecH(const Operand_& op, uint32_t id) noexcept { return isVecH(op) & (op.id() == id); }
static inline bool isVecS(const Operand_& op, uint32_t id) noexcept { return isVecS(op) & (op.id() == id); }
static inline bool isVecD(const Operand_& op, uint32_t id) noexcept { return isVecD(op) & (op.id() == id); }
static inline bool isVecQ(const Operand_& op, uint32_t id) noexcept { return isVecQ(op) & (op.id() == id); }
static inline bool isVecV(const Operand_& op, uint32_t id) noexcept { return isVecV(op) & (op.id() == id); }
};
//! General purpose register (ARM).
class Gp : public Reg {
public:
ASMJIT_DEFINE_ABSTRACT_REG(Gp, Reg)
//! Special register id.
enum Id : uint32_t {
//! Register that depends on OS, could be used as TLS offset.
kIdOs = 18,
//! Frame pointer.
kIdFp = 29,
//! Link register.
kIdLr = 30,
//! Stack register id.
kIdSp = 31,
//! Zero register id.
//!
//! Although zero register has the same id as stack register it has a special treatment, because we need to be
//! able to distinguish between these two at API level. Some intructions were designed to be used with SP and
//! some other with ZR - so we need a way to distinguish these two to make sure we emit the right thing.
//!
//! The number 63 is not random, when you perform `id & 31` you would always get 31 for both SP and ZR inputs,
//! which is the identifier used by AArch64 ISA to encode either SP or ZR depending on the instruction.
kIdZr = 63
};
inline constexpr bool isZR() const noexcept { return id() == kIdZr; }
inline constexpr bool isSP() const noexcept { return id() == kIdSp; }
//! Cast this register to a 32-bit R|W.
inline GpW w() const noexcept;
//! Cast this register to a 64-bit X.
inline GpX x() const noexcept;
};
//! Vector register (ARM).
class Vec : public Reg {
public:
ASMJIT_DEFINE_ABSTRACT_REG(Vec, Reg)
//! Additional signature bits used by arm::Vec.
enum AdditionalBits : uint32_t {
// Register element type (3 bits).
// |........|........|.XXX....|........|
kSignatureRegElementTypeShift = 12,
kSignatureRegElementTypeMask = 0x07 << kSignatureRegElementTypeShift,
// Register has element index (1 bit).
// |........|........|X.......|........|
kSignatureRegElementFlagShift = 15,
kSignatureRegElementFlagMask = 0x01 << kSignatureRegElementFlagShift,
// Register element index (4 bits).
// |........|....XXXX|........|........|
kSignatureRegElementIndexShift = 16,
kSignatureRegElementIndexMask = 0x0F << kSignatureRegElementIndexShift
};
//! Element type.
enum ElementType : uint32_t {
//! No element type specified.
kElementTypeNone = 0,
//! Byte elements (B8 or B16).
kElementTypeB,
//! Halfword elements (H4 or H8).
kElementTypeH,
//! Singleword elements (S2 or S4).
kElementTypeS,
//! Doubleword elements (D2).
kElementTypeD,
//! Byte elements grouped by 4 bytes (B4).
//!
//! \note This element-type is only used by few instructions.
kElementTypeB4,
//! Halfword elements grouped by 2 halfwords (H2).
//!
//! \note This element-type is only used by few instructions.
kElementTypeH2,
//! Count of element types.
kElementTypeCount
};
//! \cond
//! Shortcuts.
enum SignatureReg : uint32_t {
kSignatureElementB = kElementTypeB << kSignatureRegElementTypeShift,
kSignatureElementH = kElementTypeH << kSignatureRegElementTypeShift,
kSignatureElementS = kElementTypeS << kSignatureRegElementTypeShift,
kSignatureElementD = kElementTypeD << kSignatureRegElementTypeShift,
kSignatureElementB4 = kElementTypeB4 << kSignatureRegElementTypeShift,
kSignatureElementH2 = kElementTypeH2 << kSignatureRegElementTypeShift
};
//! \endcond
//! Returns whether the register has associated an element type.
inline constexpr bool hasElementType() const noexcept { return _signature.hasField<kSignatureRegElementTypeMask>(); }
//! Returns whether the register has element index (it's an element index access).
inline constexpr bool hasElementIndex() const noexcept { return _signature.hasField<kSignatureRegElementFlagMask>(); }
//! Returns whether the reggister has element type or element index (or both).
inline constexpr bool hasElementTypeOrIndex() const noexcept { return _signature.hasField<kSignatureRegElementTypeMask | kSignatureRegElementFlagMask>(); }
//! Returns element type of the register.
inline constexpr uint32_t elementType() const noexcept { return _signature.getField<kSignatureRegElementTypeMask>(); }
//! Sets element type of the register to `elementType`.
inline void setElementType(uint32_t elementType) noexcept { _signature.setField<kSignatureRegElementTypeMask>(elementType); }
//! Resets element type to none.
inline void resetElementType() noexcept { _signature.setField<kSignatureRegElementTypeMask>(0); }
//! Returns element index of the register.
inline constexpr uint32_t elementIndex() const noexcept { return _signature.getField<kSignatureRegElementIndexMask>(); }
//! Sets element index of the register to `elementType`.
inline void setElementIndex(uint32_t elementIndex) noexcept {
_signature |= kSignatureRegElementFlagMask;
_signature.setField<kSignatureRegElementIndexMask>(elementIndex);
}
//! Resets element index of the register.
inline void resetElementIndex() noexcept {
_signature &= ~(kSignatureRegElementFlagMask | kSignatureRegElementIndexMask);
}
inline constexpr bool isVecB8() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature | kSignatureElementB); }
inline constexpr bool isVecH4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature | kSignatureElementH); }
inline constexpr bool isVecS2() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature | kSignatureElementS); }
inline constexpr bool isVecD1() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature); }
inline constexpr bool isVecB16() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementB); }
inline constexpr bool isVecH8() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementH); }
inline constexpr bool isVecS4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementS); }
inline constexpr bool isVecD2() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementD); }
inline constexpr bool isVecB4x4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementB4); }
inline constexpr bool isVecH2x4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementH2); }
//! Creates a cloned register with element access.
inline Vec at(uint32_t elementIndex) const noexcept {
return Vec((signature() & ~kSignatureRegElementIndexMask) | (elementIndex << kSignatureRegElementIndexShift) | kSignatureRegElementFlagMask, id());
}
//! Cast this register to an 8-bit B register (scalar).
inline VecB b() const noexcept;
//! Cast this register to a 16-bit H register (scalar).
inline VecH h() const noexcept;
//! Cast this register to a 32-bit S register (scalar).
inline VecS s() const noexcept;
//! Cast this register to a 64-bit D register (scalar).
inline VecD d() const noexcept;
//! Cast this register to a 128-bit Q register (scalar).
inline VecV q() const noexcept;
//! Cast this register to a 128-bit V register.
inline VecV v() const noexcept;
//! Cast this register to a 128-bit V.B[elementIndex] register.
inline VecV b(uint32_t elementIndex) const noexcept;
//! Cast this register to a 128-bit V.H[elementIndex] register.
inline VecV h(uint32_t elementIndex) const noexcept;
//! Cast this register to a 128-bit V.S[elementIndex] register.
inline VecV s(uint32_t elementIndex) const noexcept;
//! Cast this register to a 128-bit V.D[elementIndex] register.
inline VecV d(uint32_t elementIndex) const noexcept;
//! Cast this register to a 128-bit V.H2[elementIndex] register.
inline VecV h2(uint32_t elementIndex) const noexcept;
//! Cast this register to a 128-bit V.B4[elementIndex] register.
inline VecV b4(uint32_t elementIndex) const noexcept;
//! Cast this register to V.8B.
inline VecD b8() const noexcept;
//! Cast this register to V.16B.
inline VecV b16() const noexcept;
//! Cast this register to V.2H.
inline VecS h2() const noexcept;
//! Cast this register to V.4H.
inline VecD h4() const noexcept;
//! Cast this register to V.8H.
inline VecV h8() const noexcept;
//! Cast this register to V.2S.
inline VecD s2() const noexcept;
//! Cast this register to V.4S.
inline VecV s4() const noexcept;
//! Cast this register to V.2D.
inline VecV d2() const noexcept;
static inline constexpr OperandSignature _makeElementAccessSignature(uint32_t elementType, uint32_t elementIndex) noexcept {
return OperandSignature{
uint32_t(RegTraits<RegType::kARM_VecV>::kSignature) |
uint32_t(kSignatureRegElementFlagMask) |
uint32_t(elementType << kSignatureRegElementTypeShift) |
uint32_t(elementIndex << kSignatureRegElementIndexShift)};
}
};
//! 32-bit GPW (AArch64) and/or GPR (ARM/AArch32) register.
class GpW : public Gp { ASMJIT_DEFINE_FINAL_REG(GpW, Gp, RegTraits<RegType::kARM_GpW>) };
//! 64-bit GPX (AArch64) register.
class GpX : public Gp { ASMJIT_DEFINE_FINAL_REG(GpX, Gp, RegTraits<RegType::kARM_GpX>) };
//! 8-bit view (S) of VFP/SIMD register.
class VecB : public Vec { ASMJIT_DEFINE_FINAL_REG(VecB, Vec, RegTraits<RegType::kARM_VecB>) };
//! 16-bit view (S) of VFP/SIMD register.
class VecH : public Vec { ASMJIT_DEFINE_FINAL_REG(VecH, Vec, RegTraits<RegType::kARM_VecH>) };
//! 32-bit view (S) of VFP/SIMD register.
class VecS : public Vec { ASMJIT_DEFINE_FINAL_REG(VecS, Vec, RegTraits<RegType::kARM_VecS>) };
//! 64-bit view (D) of VFP/SIMD register.
class VecD : public Vec { ASMJIT_DEFINE_FINAL_REG(VecD, Vec, RegTraits<RegType::kARM_VecD>) };
//! 128-bit vector register (Q or V).
class VecV : public Vec { ASMJIT_DEFINE_FINAL_REG(VecV, Vec, RegTraits<RegType::kARM_VecV>) };
inline GpW Gp::w() const noexcept { return GpW(id()); }
inline GpX Gp::x() const noexcept { return GpX(id()); }
inline VecB Vec::b() const noexcept { return VecB(id()); }
inline VecH Vec::h() const noexcept { return VecH(id()); }
inline VecS Vec::s() const noexcept { return VecS(id()); }
inline VecD Vec::d() const noexcept { return VecD(id()); }
inline VecV Vec::q() const noexcept { return VecV(id()); }
inline VecV Vec::v() const noexcept { return VecV(id()); }
inline VecV Vec::b(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeB, elementIndex), id()); }
inline VecV Vec::h(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeH, elementIndex), id()); }
inline VecV Vec::s(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeS, elementIndex), id()); }
inline VecV Vec::d(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeD, elementIndex), id()); }
inline VecV Vec::h2(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeH2, elementIndex), id()); }
inline VecV Vec::b4(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeB4, elementIndex), id()); }
inline VecD Vec::b8() const noexcept { return VecD(OperandSignature{VecD::kSignature | kSignatureElementB}, id()); }
inline VecS Vec::h2() const noexcept { return VecS(OperandSignature{VecS::kSignature | kSignatureElementH}, id()); }
inline VecD Vec::h4() const noexcept { return VecD(OperandSignature{VecD::kSignature | kSignatureElementH}, id()); }
inline VecD Vec::s2() const noexcept { return VecD(OperandSignature{VecD::kSignature | kSignatureElementS}, id()); }
inline VecV Vec::b16() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementB}, id()); }
inline VecV Vec::h8() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementH}, id()); }
inline VecV Vec::s4() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementS}, id()); }
inline VecV Vec::d2() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementD}, id()); }
#ifndef _DOXYGEN
namespace regs {
#endif
//! Creates a 32-bit W register operand (ARM/AArch64).
static inline constexpr GpW w(uint32_t id) noexcept { return GpW(id); }
//! Creates a 64-bit X register operand (AArch64).
static inline constexpr GpX x(uint32_t id) noexcept { return GpX(id); }
//! Creates a 32-bit S register operand (ARM/AArch64).
static inline constexpr VecS s(uint32_t id) noexcept { return VecS(id); }
//! Creates a 64-bit D register operand (ARM/AArch64).
static inline constexpr VecD d(uint32_t id) noexcept { return VecD(id); }
//! Creates a 1282-bit V register operand (ARM/AArch64).
static inline constexpr VecV v(uint32_t id) noexcept { return VecV(id); }
#ifndef _DOXYGEN
} // {regs}
// Make `arm::regs` accessible through `arm` namespace as well.
using namespace regs;
#endif
//! Memory operand (ARM).
class Mem : public BaseMem {
public:
//! \cond INTERNAL
//! Additional bits of operand's signature used by `arm::Mem`.
enum AdditionalBits : uint32_t {
// Index shift value (5 bits).
// |........|.....XXX|XX......|........|
kSignatureMemShiftValueShift = 14,
kSignatureMemShiftValueMask = 0x1Fu << kSignatureMemShiftValueShift,
// Shift operation type (4 bits).
// |........|XXXX....|........|........|
kSignatureMemPredicateShift = 20,
kSignatureMemPredicateMask = 0x0Fu << kSignatureMemPredicateShift
};
//! \endcond
//! Memory offset mode.
//!
//! Additional constants that can be used with the `predicate`.
enum OffsetMode : uint32_t {
//! Pre-index "[BASE, #Offset {, <shift>}]!" with write-back.
kOffsetPreIndex = 0xE,
//! Post-index "[BASE], #Offset {, <shift>}" with write-back.
kOffsetPostIndex = 0xF
};
//! \name Construction & Destruction
//! \{
//! Construct a default `Mem` operand, that points to [0].
inline constexpr Mem() noexcept
: BaseMem() {}
inline constexpr Mem(const Mem& other) noexcept
: BaseMem(other) {}
inline explicit Mem(Globals::NoInit_) noexcept
: BaseMem(Globals::NoInit) {}
inline constexpr Mem(const Signature& signature, uint32_t baseId, uint32_t indexId, int32_t offset) noexcept
: BaseMem(signature, baseId, indexId, offset) {}
inline constexpr explicit Mem(const Label& base, int32_t off = 0, Signature signature = Signature{0}) noexcept
: BaseMem(Signature::fromOpType(OperandType::kMem) |
Signature::fromMemBaseType(RegType::kLabelTag) |
signature, base.id(), 0, off) {}
inline constexpr explicit Mem(const BaseReg& base, int32_t off = 0, Signature signature = Signature{0}) noexcept
: BaseMem(Signature::fromOpType(OperandType::kMem) |
Signature::fromMemBaseType(base.type()) |
signature, base.id(), 0, off) {}
inline constexpr Mem(const BaseReg& base, const BaseReg& index, Signature signature = Signature{0}) noexcept
: BaseMem(Signature::fromOpType(OperandType::kMem) |
Signature::fromMemBaseType(base.type()) |
Signature::fromMemIndexType(index.type()) |
signature, base.id(), index.id(), 0) {}
inline constexpr Mem(const BaseReg& base, const BaseReg& index, const Shift& shift, Signature signature = Signature{0}) noexcept
: BaseMem(Signature::fromOpType(OperandType::kMem) |
Signature::fromMemBaseType(base.type()) |
Signature::fromMemIndexType(index.type()) |
Signature::fromValue<kSignatureMemPredicateMask>(uint32_t(shift.op())) |
Signature::fromValue<kSignatureMemShiftValueMask>(shift.value()) |
signature, base.id(), index.id(), 0) {}
inline constexpr Mem(uint64_t base, Signature signature = Signature{0}) noexcept
: BaseMem(Signature::fromOpType(OperandType::kMem) |
signature, uint32_t(base >> 32), 0, int32_t(uint32_t(base & 0xFFFFFFFFu))) {}
//! \}
//! \name Overloaded Operators
//! \{
inline Mem& operator=(const Mem& other) noexcept = default;
//! \}
//! \name Clone
//! \{
//! Clones the memory operand.
inline constexpr Mem clone() const noexcept { return Mem(*this); }
//! Gets new memory operand adjusted by `off`.
inline Mem cloneAdjusted(int64_t off) const noexcept {
Mem result(*this);
result.addOffset(off);
return result;
}
//! Clones the memory operand and makes it pre-index.
inline Mem pre() const noexcept {
Mem result(*this);
result.setPredicate(kOffsetPreIndex);
return result;
}
//! Clones the memory operand, applies a given offset `off` and makes it pre-index.
inline Mem pre(int64_t off) const noexcept {
Mem result(*this);
result.setPredicate(kOffsetPreIndex);
result.addOffset(off);
return result;
}
//! Clones the memory operand and makes it post-index.
inline Mem post() const noexcept {
Mem result(*this);
result.setPredicate(kOffsetPreIndex);
return result;
}
//! Clones the memory operand, applies a given offset `off` and makes it post-index.
inline Mem post(int64_t off) const noexcept {
Mem result(*this);
result.setPredicate(kOffsetPostIndex);
result.addOffset(off);
return result;
}
//! \}
//! \name Base & Index
//! \{
//! Converts memory `baseType` and `baseId` to `arm::Reg` instance.
//!
//! The memory must have a valid base register otherwise the result will be wrong.
inline Reg baseReg() const noexcept { return Reg::fromTypeAndId(baseType(), baseId()); }
//! Converts memory `indexType` and `indexId` to `arm::Reg` instance.
//!
//! The memory must have a valid index register otherwise the result will be wrong.
inline Reg indexReg() const noexcept { return Reg::fromTypeAndId(indexType(), indexId()); }
using BaseMem::setIndex;
inline void setIndex(const BaseReg& index, uint32_t shift) noexcept {
setIndex(index);
setShift(shift);
}
//! \}
//! \name ARM Specific Features
//! \{
//! Gets whether the memory operand has shift (aka scale) constant.
inline constexpr bool hasShift() const noexcept { return _signature.hasField<kSignatureMemShiftValueMask>(); }
//! Gets the memory operand's shift (aka scale) constant.
inline constexpr uint32_t shift() const noexcept { return _signature.getField<kSignatureMemShiftValueMask>(); }
//! Sets the memory operand's shift (aka scale) constant.
inline void setShift(uint32_t shift) noexcept { _signature.setField<kSignatureMemShiftValueMask>(shift); }
//! Resets the memory operand's shift (aka scale) constant to zero.
inline void resetShift() noexcept { _signature.setField<kSignatureMemShiftValueMask>(0); }
//! Gets memory predicate (shift mode or offset mode), see \ref ShiftOp and \ref OffsetMode.
inline constexpr uint32_t predicate() const noexcept { return _signature.getField<kSignatureMemPredicateMask>(); }
//! Sets memory predicate to `predicate`, see `Mem::ShiftOp`.
inline void setPredicate(uint32_t predicate) noexcept { _signature.setField<kSignatureMemPredicateMask>(predicate); }
//! Resets shift mode to LSL (default).
inline void resetPredicate() noexcept { _signature.setField<kSignatureMemPredicateMask>(0); }
inline constexpr bool isFixedOffset() const noexcept { return predicate() < kOffsetPreIndex; }
inline constexpr bool isPreOrPost() const noexcept { return predicate() >= kOffsetPreIndex; }
inline constexpr bool isPreIndex() const noexcept { return predicate() == kOffsetPreIndex; }
inline constexpr bool isPostIndex() const noexcept { return predicate() == kOffsetPostIndex; }
inline void resetToFixedOffset() noexcept { resetPredicate(); }
inline void makePreIndex() noexcept { setPredicate(kOffsetPreIndex); }
inline void makePostIndex() noexcept { setPredicate(kOffsetPostIndex); }
//! \}
};
//! Creates `[base.reg, offset]` memory operand (offset mode).
static inline constexpr Mem ptr(const Gp& base, int32_t offset = 0) noexcept {
return Mem(base, offset);
}
//! Creates `[base.reg, offset]!` memory operand (pre-index mode).
static inline constexpr Mem ptr_pre(const Gp& base, int32_t offset = 0) noexcept {
return Mem(base, offset, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPreIndex));
}
//! Creates `[base.reg], offset` memory operand (post-index mode).
static inline constexpr Mem ptr_post(const Gp& base, int32_t offset = 0) noexcept {
return Mem(base, offset, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPostIndex));
}
//! Creates `[base.reg, index]` memory operand.
static inline constexpr Mem ptr(const Gp& base, const Gp& index) noexcept {
return Mem(base, index);
}
//! Creates `[base.reg], index` memory operand (post-index mode).
static inline constexpr Mem ptr_post(const Gp& base, const Gp& index) noexcept {
return Mem(base, index, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPostIndex));
}
//! Creates `[base.reg, index, SHIFT_OP #shift]` memory operand.
static inline constexpr Mem ptr(const Gp& base, const Gp& index, const Shift& shift) noexcept {
return Mem(base, index, shift);
}
//! Creates `[base + offset]` memory operand.
static inline constexpr Mem ptr(const Label& base, int32_t offset = 0) noexcept {
return Mem(base, offset);
}
// TODO: [ARM] PC + offset address.
#if 0
//! Creates `[PC + offset]` (relative) memory operand.
static inline constexpr Mem ptr(const PC& pc, int32_t offset = 0) noexcept {
return Mem(pc, offset);
}
#endif
//! Creates `[base]` absolute memory operand.
//!
//! \note The concept of absolute memory operands doesn't exist on ARM, the ISA only provides PC relative addressing.
//! Absolute memory operands can only be used if it's known that the PC relative offset is encodable and that it
//! would be within the limits. Absolute address is also often output from disassemblers, so AsmJit support it so it
//! can assemble it back.
static inline constexpr Mem ptr(uint64_t base) noexcept { return Mem(base); }
//! \}
ASMJIT_END_SUB_NAMESPACE
//! \cond INTERNAL
ASMJIT_BEGIN_NAMESPACE
ASMJIT_DEFINE_TYPE_ID(arm::GpW, TypeId::kInt32);
ASMJIT_DEFINE_TYPE_ID(arm::GpX, TypeId::kInt64);
ASMJIT_DEFINE_TYPE_ID(arm::VecS, TypeId::kFloat32x1);
ASMJIT_DEFINE_TYPE_ID(arm::VecD, TypeId::kFloat64x1);
ASMJIT_DEFINE_TYPE_ID(arm::VecV, TypeId::kInt32x4);
ASMJIT_END_NAMESPACE
//! \endcond
#endif // ASMJIT_ARM_ARMOPERAND_H_INCLUDED
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifdef _WIN32
#pragma push_macro("min")
#pragma push_macro("max")
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
#endif
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifdef _WIN32
#pragma pop_macro("min")
#pragma pop_macro("max")
#endif
// This file is part of AsmJit project <https://asmjit.com>
//
// SPDX-License-Identifier: Zlib
// Official GitHub Repository: https://github.com/asmjit/asmjit
//
// Copyright (c) 2008-2021 The AsmJit Authors
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
#ifndef ASMJIT_ASMJIT_H_INCLUDED
#define ASMJIT_ASMJIT_H_INCLUDED
#include "./core.h"
#ifndef ASMJIT_NO_X86
#include "./x86.h"
#endif
#endif // ASMJIT_ASMJIT_H_INCLUDED
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_H_INCLUDED
#define ASMJIT_CORE_H_INCLUDED
//! Root namespace used by AsmJit.
namespace asmjit {
//! \mainpage API Reference
//!
//! AsmJit C++ API reference documentation generated by Doxygen.
//!
//! AsmJit library uses one global namespace called \ref asmjit, which provides the whole functionality. Core
//! functionality is within \ref asmjit namespace and architecture specific functionality is always in its own
//! namespace. For example \ref asmjit::x86 provides both 32-bit and 64-bit X86 code generation.
//!
//! \section main_groups Documentation Groups
//!
//! AsmJit documentation is structured into groups. Groups can be followed in order to learn AsmJit, but knowledge
//! from multiple groups is required to use AsmJit properly:
//!
//! $$DOCS_GROUP_OVERVIEW$$
//!
//! \note It's important to understand that in order to learn AsmJit all groups are important. Some groups can be
//! omitted if a particular tool is out of interest - for example \ref asmjit_assembler users don't need to know
//! about \ref asmjit_builder, but it's not the opposite. \ref asmjit_builder users should know about \ref
//! asmjit_assembler as it also uses operands, labels, and other concepts. Similarly \ref asmjit_compiler users
//! should know how both \ref asmjit_assembler and \ref asmjit_builder tools work.
//!
//! \section where_to_start Where To Start
//!
//! AsmJit \ref asmjit_core provides the following two classes that are essential from the code generation perspective:
//!
//! - \ref CodeHolder provides functionality to temporarily hold the generated code. It stores all the necessary
//! information about the code - code buffers, sections, labels, symbols, and information about relocations.
//!
//! - \ref BaseEmitter provides interface used by emitter implementations. The interface provides basic building
//! blocks that are then implemented by \ref BaseAssembler, \ref BaseBuilder, and \ref BaseCompiler.
//!
//! Code emitters:
//!
//! - \ref asmjit_assembler - provides direct machine code generation.
//!
//! - \ref asmjit_builder - provides intermediate code generation that can be processed before it's serialized to
//! \ref BaseAssembler.
//!
//! - \ref asmjit_compiler - provides high-level code generation with built-in register allocation.
//!
//! - \ref FuncNode - provides insight into how function looks from the Compiler perspective and how it's stored in
//! a node-list.
//!
//! \section main_recommendations Recommendations
//!
//! The following steps are recommended for all AsmJit users:
//!
//! - Make sure that you use \ref Logger, see \ref asmjit_logging.
//!
//! - Make sure that you use \ref ErrorHandler, see \ref asmjit_error_handling.
//!
//! - Instruction validation in your debug builds can reveal problems too. AsmJit provides validation at instruction
//! level that can be enabled via \ref BaseEmitter::addDiagnosticOptions(). See \ref DiagnosticOptions for more
//! details.
//!
//! - If you are a Compiler user, use diagnostic options and read carefully if anything suspicious pops out.
//! Diagnostic options can be enabled via \ref BaseEmitter::addDiagnosticOptions(). If unsure which ones to use,
//! enable annotations and all debug options: `DiagnosticOptions::kRAAnnotate | DiagnosticOptions::kRADebugAll`.
//!
//! - Make sure you put a breakpoint into \ref DebugUtils::errored() function if you have a problem with AsmJit
//! returning errors during instruction encoding or register allocation. Having an active breakpoint there can
//! help to reveal the origin of the error, to inspect variables and other conditions that caused it.
//!
//! The reason for using \ref Logger and \ref ErrorHandler is that they provide a very useful information about what's
//! happening inside emitters. In many cases the information provided by these two is crucial to quickly identify and
//! fix issues that happen during development (for example wrong instruction, address, or register used). In addition,
//! output from \ref Logger is always necessary when filling bug reports. In other words, using logging and proper error
//! handling can save a lot of time during the development and can also save users from submitting issues.
//!
//! \section main_other Other Pages
//!
//! - <a href="annotated.html">Class List</a> - List of classes sorted alphabetically
//! - <a href="namespaceasmjit.html">AsmJit Namespace</a> - List of symbols provided by `asmjit` namespace
//! \defgroup asmjit_build Build Instructions
//! \brief Build instructions, supported environments, and feature selection.
//!
//! ### Overview
//!
//! AsmJit is designed to be easy embeddable in any project. However, it depends on some compile-time definitions that
//! can be used to enable or disable features to decrease the resulting binary size. A typical way of building AsmJit
//! is to use [cmake](https://www.cmake.org), but it's also possible to just include AsmJit source code in your project
//! and to just build it. The easiest way to include AsmJit in your project is to just include **src** directory in
//! your project and to define \ref ASMJIT_STATIC. AsmJit can be just updated from time to time without any changes to
//! this integration process. Do not embed AsmJit's `test` files in such case as these are used exclusively for testing.
//!
//! ### Supported C++ Compilers
//!
//! - Requirements:
//!
//! - AsmJit won't build without C++11 enabled. If you use older GCC or Clang you would have to enable at least
//! C++11 standard through compiler flags.
//!
//! - Tested:
//!
//! - **Clang** - Tested by GitHub Actions - Clang 3.9+ (with C++11 enabled) is officially supported (older Clang
//! versions having C++11 support are probably fine, but are not regularly tested).
//!
//! - **GNU** - Tested by GitHub Actions - GCC 4.8+ (with C++11 enabled) is officially supported.
//!
//! - **MINGW** - Should work, but it's not tested in our CI environment.
//!
//! - **MSVC** - Tested by GitHub Actions - VS2017+ is officially supported, VS2015 is reported to work.
//!
//! - Untested:
//!
//! - **Intel** - No maintainers and no CI environment to regularly test this compiler.
//!
//! - **Other** C++ compilers would require basic support in
//! [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h).
//!
//! ### Supported Operating Systems and Platforms
//!
//! - Tested:
//!
//! - **Linux** - Tested by GitHub Actions (any distribution is generally supported).
//!
//! - **Mac OS** - Tested by GitHub Actions (any version is supported).
//!
//! - **Windows** - Tested by GitHub Actions - (Windows 7+ is officially supported).
//!
//! - **Emscripten** - Works if compiled with \ref ASMJIT_NO_JIT. AsmJit cannot generate WASM code, but can be
//! used to generate X86/X64 code within a browser, for example.
//!
//! - Untested:
//!
//! - **BSDs** - No maintainers, no CI environment to regularly test BSDs, but they should work out of box.
//!
//! - **Haiku** - Not regularly tested, but reported to work.
//!
//! - **Other** operating systems would require some testing and support in the following files:
//! - [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h)
//! - [core/osutils.cpp](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/osutils.cpp)
//! - [core/virtmem.cpp](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/virtmem.cpp)
//!
//! ### Supported Backends / Architectures
//!
//! - **X86** and **X86_64** - Both 32-bit and 64-bit backends tested on CI.
//! - **AArch64** - AArch64 backend is currently only partially tested (there is no native AArch64 runner to test
//! AsmJit Builder/Compiler)
//!
//! ### Static Builds and Embedding
//!
//! These definitions can be used to enable static library build. Embed is used when AsmJit's source code is embedded
//! directly in another project, implies static build as well.
//!
//! - \ref ASMJIT_EMBED - Asmjit is embedded, implies \ref ASMJIT_STATIC.
//! - \ref ASMJIT_STATIC - Enable static-library build.
//!
//! \note Projects that use AsmJit statically must define \ref ASMJIT_STATIC in all compilation units that use AsmJit,
//! otherwise AsmJit would use dynamic library imports in \ref ASMJIT_API decorator. The recommendation is to define
//! this macro across the whole project that uses AsmJit this way.
//!
//! ### Build Configuration
//!
//! These definitions control whether asserts are active or not. By default AsmJit would autodetect build configuration
//! from existing pre-processor definitions, but this behavior can be overridden, for example to enable debug asserts
//! in release configuration.
//!
//! - \ref ASMJIT_BUILD_DEBUG - Overrides build configuration to debug, asserts will be enabled in this case.
//! - \ref ASMJIT_BUILD_RELEASE - Overrides build configuration to release, asserts will be disabled in this case.
//!
//! \note There is usually no need to override the build configuration. AsmJit detects the build configuration by
//! checking whether `NDEBUG` is defined and automatically defines \ref ASMJIT_BUILD_RELEASE if configuration overrides
//! were not used. We only recommend using build configuration overrides in special situations, like using AsmJit in
//! release configuration with asserts enabled for whatever reason.
//!
//! ### AsmJit Backends
//!
//! AsmJit currently supports only X86/X64 backend, but the plan is to add more backends in the future. By default
//! AsmJit builds only the host backend, which is autodetected at compile-time, but this can be overridden.
//!
//! - \ref ASMJIT_NO_X86 - Disable X86/X64 backends.
//! - \ref ASMJIT_NO_FOREIGN - Disables the support for foreign architectures.
//!
//! ### Features Selection
//!
//! AsmJit builds by defaults all supported features, which includes all emitters, logging, instruction validation and
//! introspection, and JIT memory allocation. Features can be disabled at compile time by using `ASMJIT_NO_...`
//! definitions.
//!
//! - \ref ASMJIT_NO_DEPRECATED - Disables deprecated API at compile time so it won't be available and the
//! compilation will fail if there is attempt to use such API. This includes deprecated classes, namespaces,
//! enumerations, and functions.
//!
//! - \ref ASMJIT_NO_BUILDER - Disables \ref asmjit_builder functionality completely. This implies \ref
//! ASMJIT_NO_COMPILER as \ref asmjit_compiler cannot be used without \ref asmjit_builder.
//!
//! - \ref ASMJIT_NO_COMPILER - Disables \ref asmjit_compiler functionality completely.
//!
//! - \ref ASMJIT_NO_JIT - Disables JIT memory management and \ref JitRuntime.
//!
//! - \ref ASMJIT_NO_LOGGING - Disables \ref Logger and \ref Formatter.
//!
//! - \ref ASMJIT_NO_TEXT - Disables everything that contains string representation of AsmJit constants, should
//! be used together with \ref ASMJIT_NO_LOGGING as logging doesn't make sense without the ability to query
//! instruction names, register names, etc...
//!
//! - \ref ASMJIT_NO_VALIDATION - Disables validation API.
//!
//! - \ref ASMJIT_NO_INTROSPECTION - Disables instruction introspection API, must be used together with \ref
//! ASMJIT_NO_COMPILER as \ref asmjit_compiler requires introspection for its liveness analysis and register
//! allocation.
//!
//! \note It's not recommended to disable features if you plan to build AsmJit as a shared library that will be
//! used by multiple projects that you don't control how AsmJit was built (for example AsmJit in a Linux distribution).
//! The possibility to disable certain features exists mainly for customized AsmJit builds.
//! \defgroup asmjit_breaking_changes Breaking Changes
//! \brief Documentation of breaking changes
//!
//! ### Overview
//!
//! AsmJit is a live project that is being actively developed. Deprecating the existing API in favor of a new
//! one is preferred, but it's not always possible if the changes are significant. AsmJit authors prefer to do
//! accumulated breaking changes at once instead of breaking the API often. This page documents deprecated and
//! removed APIs and should serve as a how-to guide for people that want to port existing code to work with the
//! newest AsmJit.
//!
//! ### Tips
//!
//! Useful tips before you start:
//!
//! - Visit our [Public Gitter Channel](https://gitter.im/asmjit/asmjit) if you need a quick help.
//!
//! - Build AsmJit with `ASMJIT_NO_DEPRECATED` macro defined to make sure that you are not using deprecated
//! functionality at all. Deprecated functions are decorated with `ASMJIT_DEPRECATED()` macro, but sometimes
//! it's not possible to decorate everything like classes, which are used by deprecated functions as well,
//! because some compilers would warn about that. If your project compiles fine with `ASMJIT_NO_DEPRECATED`
//! it's not using anything, which was deprecated.
//!
//! ### Changes committed at 2021-12-13
//!
//! Core changes:
//!
//! - Removed old deprecated API.
//!
//! - Many enumerations were changed to enum class, and many public APIs were changed to use such enums instead
//! of uint32_t. This change makes some APIs backward incompatible - there are no deprecations this time.
//!
//! - Extracted operand signature manipulation to `OperandSignature`.
//! - Setting function arguments through `Compiler::setArg()` was deprecated, use FuncNode::setArg() instead.
//! - Moved `{arch}::Features::k` to `CpuFeatures::{arch}::k`.
//! - Moved `BaseEmitter::kEncodingOption` to `EncodingOptions::k`.
//! - Moved `BaseEmitter::kFlag` to `EmitterFlags::k`.
//! - Moved `BaseEmitter::kType` to `EmitterType::k`.
//! - Moved `BaseEmitter::kValidationOption` to `DiagnosticOptions::kValidate`.
//! - Moved `BaseFeatures` to `CpuFeatures`.
//! - Moved `BaseInst::kControl` to `InstControlFlow::k`.
//! - Moved `BaseInst::kOption` and `x86::Inst::kOption` to `InstOptions::k`.
//! - Moved `BaseNode::kNode` to `NodeType::k`.
//! - Moved `BaseReg::kGroup` and `x86::Reg::kGroup` to `RegGroup::k`.
//! - Moved `BaseReg::kType` and `x86::Reg::kType` to `RegType::k`.
//! - Moved `CallConv::kFlag` to `CallConvFlags::k`.
//! - Moved `CallConv::kId` to `CallConvId::k`.
//! - Moved `CallConv::kStrategy` to `CallConvStrategy::k`.
//! - Moved `CodeBuffer::kFlag` to `CodeBufferFlags`.
//! - Moved `ConstPool::kScope` to `ConstPoolScope::k`.
//! - Moved `Environment::kArch` to `Arch::k`.
//! - Moved `Environment::kSubArch` to `SubArch::k`.
//! - Moved `Environment::kFormat` to `OjectFormat::k`.
//! - Moved `Environment::kPlatform` to `Platform::k`.
//! - Moved `Environment::kAbi` to `PlatformABI::k`.
//! - Moved `Environment::kVendor` to `Vendor::k`.
//! - Moved `FormatOptions::kFlag` to `FormatFlags::k` and `DiagnosticOptions::k` (Compiler diagnostics flags).
//! - Moved `FormatOptions::kIndentation` to `FormatIndentationGroup::k`.
//! - Moved `FuncFrame::kAttr` to `FuncAttributes::k`.
//! - Moved `Globals::kReset` to `ResetPolicy::k`.
//! - Moved `InstDB::kAvx512Flag` to `InstDB::Avx512Flags::k`.
//! - Moved `InstDB::kFlag` to `InstDB::InstFlags::k`.
//! - Moved `InstDB::kMemFlag` to `InstDB::OpFlags::kMem`.
//! - Moved `InstDB::kMode` to `InstDB::Mode::k`.
//! - Moved `InstDB::kOpFlag` to `InstDB::OpFlags::k{OpType}...`.
//! - Moved `JitAllocator::kOption` to `JitAllocatorOptions::k`.
//! - Moved `Label::kType` to `LabelType::k`.
//! - Moved `Operand::kOpType` to `OperandType::k`.
//! - Moved `OpRWInfo::kFlag` to `OpRWFlags::k`.
//! - Moved `Type::kId` to `TypeId::k`.
//! - Moved `VirtMem::k` to `VirtMem::MemoryFlags::k`.
//!
//! ### Changes committed at 2020-05-30
//!
//! AsmJit has been cleaned up significantly, many todo items have been fixed and many functions and classes have
//! been redesigned, some in an incompatible way.
//!
//! Core changes:
//!
//! - `Imm` operand has now only `Imm::value()` and `Imm::valueAs()` functions that return its value content,
//! and `Imm::setValue()` function that sets the content. Functions like `setI8()`, `setU8()` were deprecated.
//!
//! Old functions were deprecated, but code using them should still compile.
//!
//! - `ArchInfo` has been replaced with `Environment`. Environment provides more details about the architecture,
//! but drops some properties that were used by arch info - `gpSize(`) and `gpCount()`. `gpSize()` can be replaced
//! with `registerSize()` getter, which returns a native register size of the architecture the environment uses.
//! However, `gpCount()` was removed - at the moment `ArchTraits` can be used to access such properties.
//!
//! Some other functions were renamed, like `ArchInfo::isX86Family()` is now `Environment::isFamilyX86()`, etc.
//! The reason for changing the order was support for more propertries and all the accessors now start with the
//! type of the property, like `Environment::isPlatformWindows()`.
//!
//! This function causes many other classes to provide `environment()` getter instead of `archInfo()` getter.
//! In addition, AsmJit now uses `arch()` to get an architecture instead of `archId()`. `ArchInfo::kIdXXX` was
//! renamed to `Environment::kArchXXX`.
//!
//! Some functions were deprecated, some removed...
//!
//! - `CodeInfo` has been removed in favor of `Environment`. If you used `CodeInfo` to set architecture and base
//! address, this is now possible with `Environment` and setting base address explicitly by `CodeHolder::init()`
//! - the first argument is `Environment`, and the second argument is base address, which defaults to
//! `Globals::kNoBaseAddress`.
//!
//! CodeInfo class was deprecated, but the code using it should still compile with warnings.
//!
//! - `CallConv` has been updated to offer a more unified way of representing calling conventions - many calling
//! conventions were abstracted to follow standard naming like `CallConvId::kCDecl` or `CallConvId::kStdCall`.
//!
//! This change means that other APIs like `FuncDetail::init()` now require both, calling convention and target
//! `Environment`.
//!
//! - `Logging` namespace has been renamed to `Formatter`, which now provides general functionality for formatting
//! in AsmJit.
//!
//! Logging namespace should still work, but its use is deprecated. Unfortunately this will be without deprecation
//! warnings, so make sure you don't use it.
//!
//! - `Data64`, `Data128`, and `Data256` structs were deprecated and should no longer be used. There is no replacement,
//! AsmJit users should simply create their own structures if they need them or use the new repeated embed API in
//! emitters, see `BaseEmitter::embedDataArray()`.
//!
//! Emitter changes:
//!
//! - `BaseEmitter::emit()` function signature has been changed to accept 3 operands by reference and the rest 3
//! operands as a continuous array. This change is purely cosmetic and shouldn't affect users as emit() has many
//! overloads that dispatch to the right function.
//!
//! - `x86::Emitter` (Assembler, Builder, Compiler) deprecates embed utilities like `dint8()`, `duint8()`, `duint16()`,
//! `dxmm()`, etc... in favor of a new and more powerful `BaseEmitter::embedDataArray()`. This function also allows
//! emitting repeated values and/or patterns, which is used by helpers `BaseEmitter::embedUInt8()`, and others...
//!
//! - Validation is now available through `BaseEmitter::DiagnosticOptions`, which can be enabled/disabled through
//! `BaseEmitter::addDiagnosticOptions()` and `BaseEmitter::clearDiagnosticOptions()`, respectively. Validation
//! options now separate between encoding and Builder/Compiler so it's possible to choose the granularity required.
//!
//! Builder changes:
//!
//! - Internal functions for creating nodes were redesigned. They now accept a pointer to the node created as
//! a first parameter. These changes should not affect AsmJit users as these functions were used internally.
//!
//! Compiler changes:
//!
//! - `FuncCallNode` has been renamed to `InvokeNode`. Additionally, function calls should now use
//! `x86::Compiler::invoke()` instead of `call()`. The reason behind this is to remove the confusion between a
//! `call` instruction and AsmJit's `call()` intrinsic, which is now `invoke()`.
//!
//! - Creating new nodes also changed. Now the preferred way of invoking a function is to call
//! `x86::Compiler::invoke()` where the first argument is `InvokeNode**`. The function now returns an error and
//! would call `ErrorHandler` in case of a failure. Error handling was unspecified in the past - the function was
//! marked noexcept, but called error handler, which could throw.
//!
//! The reason behind this change is to make the API consistent with other changes and to also make it possible
//! to inspect the possible error. In the previous API it returned a new node or `nullptr` in case of error,
//! which the user couldn't inspect unless there was an attached `ErrorHandler`.
//!
//! Samples:
//!
//! ```
//! #include <asmjit/x86.h>
//!
//! using namespace asmjit;
//!
//! // The basic setup of JitRuntime and CodeHolder changed, use environment()
//! // instead of codeInfo().
//! void basicSetup() {
//! JitRuntime rt;
//! CodeHolder code(rt.environment());
//! }
//!
//! // Calling a function (Compiler) changed - use invoke() instead of call().
//! void functionInvocation(x86::Compiler& cc) {
//! InvokeNode* invokeNode;
//! cc.invoke(&invokeNode, targetOperand, FuncSignatureT<...>(...));
//! }
//! ```
//! \defgroup asmjit_core Core
//! \brief Globals, code storage, and emitter interface.
//!
//! ### Overview
//!
//! AsmJit library uses \ref CodeHolder to hold code during code generation and emitters inheriting from \ref
//! BaseEmitter to emit code. CodeHolder uses containers to manage its data:
//!
//! - \ref Section - stores information about a code or data section.
//! - \ref CodeBuffer - stores actual code or data, part of \ref Section.
//! - \ref LabelEntry - stores information about a label - its name, offset, section where it belongs to, and
//! other bits.
//! - \ref LabelLink - stores information about yet unbound label, which was already used by the assembler.
//! - \ref RelocEntry - stores information about a relocation.
//! - \ref AddressTableEntry - stores information about an address, which was used in a jump or call. Such
//! address may need relocation.
//!
//! To generate code you would need to instantiate at least the following classes:
//!
//! - \ref CodeHolder - to hold code during code generation.
//! - \ref BaseEmitter - to emit code into \ref CodeHolder.
//! - \ref Target (optional) - most likely \ref JitRuntime to keep the generated code in executable memory. \ref
//! Target can be customized by inheriting from it.
//!
//! There are also other core classes that are important:
//!
//! - \ref Environment - describes where the code will run. Environment brings the concept of target triples or
//! tuples into AsmJit, which means that users can specify target architecture, platform, and ABI.
//! - \ref TypeId - encapsulates lightweight type functionality that can be used to describe primitive and vector
//! types. Types are used by higher level utilities, for example by \ref asmjit_function and \ref asmjit_compiler.
//! - \ref CpuInfo - encapsulates CPU information - stores both CPU information and CPU features described by \ref
//! CpuFeatures.
//!
//! AsmJit also provides global constants:
//!
//! - \ref Globals - namespace that provides global constants.
//! - \ref ByteOrder - byte-order constants and functionality.
//!
//! \note CodeHolder examples use \ref x86::Assembler as abstract interfaces cannot be used to generate code.
//!
//! ### CodeHolder & Emitters
//!
//! The example below shows how the mentioned classes interact to generate X86 code:
//!
//! ```
//! #include <asmjit/x86.h>
//! #include <stdio.h>
//!
//! using namespace asmjit;
//!
//! // Signature of the generated function.
//! typedef int (*Func)(void);
//!
//! int main() {
//! JitRuntime rt; // Runtime specialized for JIT code execution.
//!
//! CodeHolder code; // Holds code and relocation information.
//! code.init(rt.environment()); // Initialize code to match the JIT environment.
//!
//! x86::Assembler a(&code); // Create and attach x86::Assembler to code.
//! a.mov(x86::eax, 1); // Move one to eax register.
//! a.ret(); // Return from function.
//! // ===== x86::Assembler is no longer needed from here and can be destroyed =====
//!
//! Func fn; // Holds address to the generated function.
//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime.
//! if (err) return 1; // Handle a possible error returned by AsmJit.
//! // ===== CodeHolder is no longer needed from here and can be destroyed =====
//!
//! int result = fn(); // Execute the generated code.
//! printf("%d\n", result); // Print the resulting "1".
//!
//! // All classes use RAII, all resources will be released before `main()` returns,
//! // the generated function can be, however, released explicitly if you intend to
//! // reuse or keep the runtime alive, which you should in a production-ready code.
//! rt.release(fn);
//!
//! return 0;
//! }
//! ```
//!
//! The example above used \ref x86::Assembler as an emitter. AsmJit provides the following emitters that offer various
//! levels of abstraction:
//!
//! - \ref asmjit_assembler - Low-level emitter that emits directly to \ref CodeBuffer.
//! - \ref asmjit_builder - Low-level emitter that emits to a \ref BaseNode list.
//! - \ref asmjit_compiler - High-level emitter that provides register allocation.
//!
//! ### Targets and JitRuntime
//!
//! AsmJit's \ref Target is an interface that provides basic target abstraction. At the moment AsmJit provides only
//! one implementation called \ref JitRuntime, which as the name suggests provides JIT code target and execution
//! runtime. \ref JitRuntime provides all the necessary stuff to implement a simple JIT compiler with basic memory
//! management. It only provides \ref JitRuntime::add() and \ref JitRuntime::release() functions that are used to
//! either add code to the runtime or release it. \ref JitRuntime doesn't do any decisions on when the code should be
//! released, the decision is up to the developer.
//!
//! See more at \ref asmjit_virtual_memory group.
//!
//! ### More About Environment
//!
//! In the previous example the \ref Environment is retrieved from \ref JitRuntime. It's logical as \ref JitRuntime
//! always returns an \ref Environment that is compatible with the host. For example if your application runs on X86_64
//! CPU the \ref Environment returned will use \ref Arch::kX64 architecture in contrast to \ref Arch::kX86, which will
//! be used in 32-bit mode on an X86 target.
//!
//! AsmJit allows to setup the \ref Environment manually and to select a different architecture and ABI when necessary.
//! So let's do something else this time, let's always generate a 32-bit code and print its binary representation. To
//! do that, we can create our own \ref Environment and initialize it to \ref Arch::kX86.
//!
//! ```
//! #include <asmjit/x86.h>
//! #include <stdio.h>
//!
//! using namespace asmjit;
//!
//! int main(int argc, char* argv[]) {
//! using namespace asmjit::x86;
//!
//! // Create a custom environment initialized to 32-bit X86 architecture.
//! Environment env;
//! env.setArch(Arch::kX86);
//!
//! CodeHolder code; // Create a CodeHolder.
//! code.init(env); // Initialize CodeHolder with custom environment.
//!
//! // Generate a 32-bit function that sums 4 floats and looks like:
//! // void func(float* dst, const float* a, const float* b)
//! x86::Assembler a(&code); // Create and attach x86::Assembler to `code`.
//!
//! a.mov(eax, dword_ptr(esp, 4)); // Load the destination pointer.
//! a.mov(ecx, dword_ptr(esp, 8)); // Load the first source pointer.
//! a.mov(edx, dword_ptr(esp, 12)); // Load the second source pointer.
//!
//! a.movups(xmm0, ptr(ecx)); // Load 4 floats from [ecx] to XMM0.
//! a.movups(xmm1, ptr(edx)); // Load 4 floats from [edx] to XMM1.
//! a.addps(xmm0, xmm1); // Add 4 floats in XMM1 to XMM0.
//! a.movups(ptr(eax), xmm0); // Store the result to [eax].
//! a.ret(); // Return from function.
//!
//! // We have no Runtime this time, it's on us what we do with the code.
//! // CodeHolder stores code in Section, which provides some basic properties
//! // and CodeBuffer structure. We are interested in section's CodeBuffer.
//! //
//! // NOTE: The first section is always '.text', it can be retrieved by
//! // code.sectionById(0) or simply by code.textSection().
//! CodeBuffer& buffer = code.textSection()->buffer();
//!
//! // Print the machine-code generated or do something else with it...
//! // 8B4424048B4C24048B5424040F28010F58010F2900C3
//! for (size_t i = 0; i < buffer.length; i++)
//! printf("%02X", buffer.data[i]);
//!
//! return 0;
//! }
//! ```
//!
//! ### Explicit Code Relocation
//!
//! In addition to \ref Environment, \ref CodeHolder can be configured to specify a base-address (or a virtual base
//! address in a linker terminology), which could be static (useful when you know the location where the target's
//! machine code will be) or dynamic. AsmJit assumes dynamic base-address by default and relocates the code held by
//! \ref CodeHolder to a user provided address on-demand. To be able to relocate to a user provided address it needs
//! to store some information about relocations, which is represented by \ref RelocEntry. Relocation entries are only
//! required if you call external functions from the generated code that cannot be encoded by using a 32-bit
//! displacement (64-bit displacements are not provided by aby supported architecture).
//!
//! There is also a concept called \ref LabelLink - label link is a lightweight data structure that doesn't have any
//! identifier and is stored in \ref LabelEntry as a single-linked list. Label link represents either unbound yet used
//! label and cross-sections links (only relevant to code that uses multiple sections). Since crossing sections is
//! something that cannot be resolved immediately these links persist until offsets of these sections are assigned and
//! until \ref CodeHolder::resolveUnresolvedLinks() is called. It's an error if you end up with code that has
//! unresolved label links after flattening. You can verify it by calling \ref CodeHolder::hasUnresolvedLinks(), which
//! inspects the value returned by \ref CodeHolder::unresolvedLinkCount().
//!
//! AsmJit can flatten code that uses multiple sections by assigning each section an incrementing offset that respects
//! its alignment. Use \ref CodeHolder::flatten() to do that. After the sections are flattened their offsets and
//! virtual sizes are adjusted to respect each section's buffer size and alignment. The \ref
//! CodeHolder::resolveUnresolvedLinks() function must be called before relocating the code held by \ref CodeHolder.
//! You can also flatten your code manually by iterating over all sections and calculating their offsets (relative to
//! base) by your own algorithm. In that case \ref CodeHolder::flatten() should not be called, however,
//! \ref CodeHolder::resolveUnresolvedLinks() should be.
//!
//! The example below shows how to use a built-in virtual memory allocator \ref JitAllocator instead of using \ref
//! JitRuntime (just in case you want to use your own memory management) and how to relocate the generated code
//! into your own memory block - you can use your own virtual memory allocator if you prefer that, but that's OS
//! specific and not covered by the documentation.
//!
//! The following code is similar to the previous one, but implements a function working in both 32-bit and 64-bit
//! environments:
//!
//! ```
//! #include <asmjit/x86.h>
//! #include <stdio.h>
//!
//! using namespace asmjit;
//!
//! typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b);
//!
//! int main() {
//! // Create a custom environment that matches the current host environment.
//! Environment env = Environment::host();
//!
//! CodeHolder code; // Create a CodeHolder.
//! code.init(env); // Initialize CodeHolder with environment.
//!
//! x86::Assembler a(&code); // Create and attach x86::Assembler to `code`.
//!
//! // Signature: 'void func(int* dst, const int* a, const int* b)'.
//! x86::Gp dst;
//! x86::Gp src_a;
//! x86::Gp src_b;
//!
//! // Handle the difference between 32-bit and 64-bit calling conventions
//! // (arguments passed through stack vs. arguments passed by registers).
//! if (env.is32Bit()) {
//! dst = x86::eax;
//! src_a = x86::ecx;
//! src_b = x86::edx;
//! a.mov(dst , x86::dword_ptr(x86::esp, 4));
//! a.mov(src_a, x86::dword_ptr(x86::esp, 8));
//! a.mov(src_b, x86::dword_ptr(x86::esp, 12));
//! }
//! else {
//! if (env.isPlatformWindows()) {
//! dst = x86::rcx; // First argument (destination pointer).
//! src_a = x86::rdx; // Second argument (source 'a' pointer).
//! src_b = x86::r8; // Third argument (source 'b' pointer).
//! }
//! else {
//! dst = x86::rdi; // First argument (destination pointer).
//! src_a = x86::rsi; // Second argument (source 'a' pointer).
//! src_b = x86::rdx; // Third argument (source 'b' pointer).
//! }
//! }
//!
//! a.movdqu(x86::xmm0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0.
//! a.movdqu(x86::xmm1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1.
//! a.paddd(x86::xmm0, x86::xmm1); // Add 4 ints in XMM1 to XMM0.
//! a.movdqu(x86::ptr(dst), x86::xmm0); // Store the result to [dst].
//! a.ret(); // Return from function.
//!
//! // Even when we didn't use multiple sections AsmJit could insert one section
//! // called '.addrtab' (address table section), which would be filled by data
//! // required by relocations (absolute jumps and calls). You can omit this code
//! // if you are 100% sure your code doesn't contain multiple sections and
//! // such relocations. You can use `CodeHolder::hasAddressTable()` to verify
//! // whether the address table section does exist.
//! code.flatten();
//! code.resolveUnresolvedLinks();
//!
//! // After the code was generated it can be relocated manually to any memory
//! // location, however, we need to know it's size before we perform memory
//! // allocation. `CodeHolder::codeSize()` returns the worst estimated code
//! // size in case that relocations are not possible without trampolines (in
//! // that case some extra code at the end of the current code buffer is
//! // generated during relocation).
//! size_t estimatedSize = code.codeSize();
//!
//! // Instead of rolling up our own memory allocator we can use the one AsmJit
//! // provides. It's decoupled so you don't need to use `JitRuntime` for that.
//! JitAllocator allocator;
//!
//! // Allocate an executable virtual memory and handle a possible failure.
//! void* p = allocator.alloc(estimatedSize);
//! if (!p)
//! return 0;
//!
//! // Now relocate the code to the address provided by the memory allocator.
//! // Please note that this DOESN'T COPY anything to `p`. This function will
//! // store the address in CodeHolder and use relocation entries to patch the
//! // existing code in all sections to respect the base address provided.
//! code.relocateToBase((uint64_t)p);
//!
//! // This is purely optional. There are cases in which the relocation can omit
//! // unneeded data, which would shrink the size of address table. If that
//! // happened the codeSize returned after relocateToBase() would be smaller
//! // than the originally `estimatedSize`.
//! size_t codeSize = code.codeSize();
//!
//! // This will copy code from all sections to `p`. Iterating over all sections
//! // and calling `memcpy()` would work as well, however, this function supports
//! // additional options that can be used to also zero pad sections' virtual
//! // size, etc.
//! //
//! // With some additional features, copyFlattenData() does roughly this:
//! // for (Section* section : code.sections())
//! // memcpy((uint8_t*)p + section->offset(),
//! // section->data(),
//! // section->bufferSize());
//! code.copyFlattenedData(p, codeSize, CopySectionFlags::kPadSectionBuffer);
//!
//! // Execute the generated function.
//! int inA[4] = { 4, 3, 2, 1 };
//! int inB[4] = { 1, 5, 2, 8 };
//! int out[4];
//!
//! // This code uses AsmJit's ptr_as_func<> to cast between void* and SumIntsFunc.
//! ptr_as_func<SumIntsFunc>(p)(out, inA, inB);
//!
//! // Prints {5 8 4 9}
//! printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]);
//!
//! // Release 'p' is it's no longer needed. It will be destroyed with 'vm'
//! // instance anyway, but it's a good practice to release it explicitly
//! // when you know that the function will not be needed anymore.
//! allocator.release(p);
//!
//! return 0;
//! }
//! ```
//!
//! If you know the base-address in advance (before the code generation) it can be passed as a second argument to
//! \ref CodeHolder::init(). In that case the Assembler will know the absolute position of each instruction and
//! would be able to use it during instruction encoding to prevent relocations where possible. The following example
//! shows how to configure the base address:
//!
//! ```
//! #include <asmjit/x86.h>
//! #include <stdio.h>
//!
//! using namespace asmjit;
//!
//! void initializeCodeHolder(CodeHolder& code) {
//! Environment env = Environment::host();
//! uint64_t baseAddress = uint64_t(0x1234);
//!
//! // initialize CodeHolder with environment and custom base address.
//! code.init(env, baseAddress);
//! }
//! ```
//!
//! ### Label Offsets and Links
//!
//! When a label that is not yet bound is used by the Assembler, it creates a \ref LabelLink, which is then added to
//! a \ref LabelEntry. These links are also created if a label is used in a different section than in which it was
//! bound. Let's examine some functions that can be used to check whether there are any unresolved links.
//!
//! ```
//! #include <asmjit/core.h>
//! #include <stdio.h>
//!
//! using namespace asmjit;
//!
//! void labelLinksExample(CodeHolder& code, const Label& label) {
//! // Tests whether the `label` is bound.
//! bool isBound = code.isLabelBound(label);
//! printf("Label %u is %s\n", label.id(), isBound ? "bound" : "not bound");
//!
//! // Returns true if the code contains either referenced, but unbound
//! // labels, or cross-section label links that are not resolved yet.
//! bool hasUnresolved = code.hasUnresolvedLinks(); // Boolean answer.
//! size_t nUnresolved = code.unresolvedLinkCount(); // Count of unresolved links.
//!
//! printf("Number of unresolved links: %zu\n", nUnresolved);
//! }
//! ```
//!
//! There is no function that would return the number of unbound labels as this is completely unimportant from
//! CodeHolder's perspective. If a label is not used then it doesn't matter whether it's bound or not, only actually
//! used labels matter. After a Label is bound it's possible to query its offset offset relative to the start of the
//! section where it was bound:
//!
//! ```
//! #include <asmjit/core.h>
//! #include <stdio.h>
//!
//! using namespace asmjit;
//!
//! void labelOffsetExample(CodeHolder& code, const Label& label) {
//! // Label offset is known after it's bound. The offset provided is relative
//! // to the start of the section, see below for alternative. If the given
//! // label is not bound the offset returned will be zero. It's recommended
//! // to always check whether the label is bound before using its offset.
//! uint64_t sectionOffset = code.labelOffset(label);
//! printf("Label offset relative to section: %llu\n", (unsigned long long)sectionOffset);
//!
//! // If you use multiple sections and want the offset relative to the base.
//! // NOTE: This function expects that the section has already an offset and
//! // the label-link was resolved (if this is not true you will still get an
//! // offset relative to the start of the section).
//! uint64_t baseOffset = code.labelOffsetFromBase(label);
//! printf("Label offset relative to base: %llu\n", (unsigned long long)baseOffset);
//! }
//! ```
//!
//! ### Sections
//!
//! AsmJit allows to create multiple sections within the same \ref CodeHolder. A test-case
//! [asmjit_test_x86_sections.cpp](https://github.com/asmjit/asmjit/blob/master/test/asmjit_test_x86_sections.cpp)
//! can be used as a reference point although the following example should also provide a useful insight:
//!
//! ```
//! #include <asmjit/x86.h>
//! #include <stdio.h>
//!
//! using namespace asmjit;
//!
//! void sectionsExample(CodeHolder& code) {
//! // Text section is always provided as the first section.
//! Section* text = code.textSection(); // or code.sectionById(0);
//!
//! // To create another section use CodeHolder::newSection().
//! Section* data;
//! Error err = code.newSection(&data,
//! ".data", // Section name
//! SIZE_MAX, // Name length if the name is not null terminated (or SIZE_MAX).
//! SectionFlags::kNone, // Section flags, see SectionFlags.
//! 8, // Section alignment, must be power of 2.
//! 0); // Section order value (optional, default 0).
//!
//! // When you switch sections in Assembler, Builder, or Compiler the cursor
//! // will always move to the end of that section. When you create an Assembler
//! // the cursor would be placed at the end of the first (.text) section, which
//! // is initially empty.
//! x86::Assembler a(&code);
//! Label L_Data = a.newLabel();
//!
//! a.mov(x86::eax, x86::ebx); // Emits in .text section.
//!
//! a.section(data); // Switches to the end of .data section.
//! a.bind(L_Data); // Binds label in this .data section
//! a.db(0x01); // Emits byte in .data section.
//!
//! a.section(text); // Switches to the end of .text section.
//! a.add(x86::ebx, x86::eax); // Emits in .text section.
//!
//! // References a label in .text section, which was bound in .data section.
//! // This would create a LabelLink even when the L_Data is already bound,
//! // because the reference crosses sections. See below...
//! a.lea(x86::rsi, x86::ptr(L_Data));
//! }
//! ```
//!
//! The last line in the example above shows that a LabelLink would be created even for bound labels that cross
//! sections. In this case a referenced label was bound in another section, which means that the link couldn't be
//! resolved at that moment. If your code uses sections, but you wish AsmJit to flatten these sections (you don't
//! plan to flatten them manually) then there is an API for that.
//!
//! ```
//! #include <asmjit/x86.h>
//! #include <stdio.h>
//!
//! using namespace asmjit;
//!
//! // ... (continuing the previous example) ...
//! void sectionsExampleContinued(CodeHolder& code) {
//! // Suppose we have some code that contains multiple sections and
//! // we would like to flatten it by using AsmJit's built-in API:
//! Error err = code.flatten();
//! if (err) {
//! // There are many reasons it can fail, so always handle a possible error.
//! printf("Failed to flatten the code: %s\n", DebugUtils::errorAsString(err));
//! exit(1);
//! }
//!
//! // After flattening all sections would contain assigned offsets
//! // relative to base. Offsets are 64-bit unsigned integers so we
//! // cast them to `size_t` for simplicity. On 32-bit targets it's
//! // guaranteed that the offset cannot be greater than `2^32 - 1`.
//! printf("Data section offset %zu", size_t(data->offset()));
//!
//! // The flattening doesn't resolve unresolved label links, this
//! // has to be done manually as flattening can be done separately.
//! err = code.resolveUnresolvedLinks();
//! if (err) {
//! // This is the kind of error that should always be handled...
//! printf("Failed to resolve label links: %s\n", DebugUtils::errorAsString(err));
//! exit(1);
//! }
//!
//! if (code.hasUnresolvedLinks()) {
//! // This would mean either unbound label or some other issue.
//! printf("The code has %zu unbound labels\n", code.unresovedLinkCount());
//! exit(1);
//! }
//! }
//! ```
//! \defgroup asmjit_assembler Assembler
//! \brief Assembler interface and operands.
//!
//! ### Overview
//!
//! AsmJit's Assembler is used to emit machine code directly into a \ref CodeBuffer. In general, code generation
//! with assembler requires the knowledge of the following:
//!
//! - \ref BaseAssembler and architecture-specific assemblers:
//! - \ref x86::Assembler - Assembler specific to X86 architecture
//! - \ref Operand and its variations:
//! - \ref BaseReg - Base class for a register operand, inherited by:
//! - \ref x86::Reg - Register operand specific to X86 architecture.
//! - \ref BaseMem - Base class for a memory operand, inherited by:
//! - \ref x86::Mem - Memory operand specific to X86 architecture.
//! - \ref Imm - Immediate (value) operand.
//! - \ref Label - Label operand.
//!
//! \note Assembler examples use \ref x86::Assembler as abstract interfaces cannot be used to generate code.
//!
//! ### Operand Basics
//!
//! Let's start with operands. \ref Operand is a data structure that defines a data layout of any operand. It can be
//! inherited, but any class inheriting it cannot add any members to it, only the existing layout can be reused.
//! AsmJit allows to construct operands dynamically, to store them, and to query a complete information about them
//! at run-time. Operands are small (always 16 bytes per \ref Operand) and can be copied and passed by value. Please
//! never allocate individual operands dynamically by using a `new` keyword - it would work, but then you would have
//! to be responsible for deleting such operands. In AsmJit operands are always part of some other data structures
//! like \ref InstNode, which is part of \ref asmjit_builder tool.
//!
//! Operands contain only identifiers, but not pointers to any code-generation data. For example \ref Label operand
//! only provides label identifier, but not a pointer to \ref LabelEntry structure. In AsmJit such IDs are used to
//! link stuff together without having to deal with pointers.
//!
//! AsmJit's operands all inherit from a base class called \ref Operand. Operands have the following properties that
//! are commonly accessible by getters and setters:
//!
//! - \ref Operand - Base operand, which only provides accessors that are common to all operand types.
//! - \ref BaseReg - Describes either physical or virtual register. Physical registers have id that matches the
//! target's machine id directly whereas virtual registers must be allocated into physical registers by a register
//! allocator pass. Register operand provides:
//! - Register Type (\ref RegType) - Unique id that describes each possible register provided by the target
//! architecture - for example X86 backend provides general purpose registers (GPB-LO, GPB-HI, GPW, GPD, and GPQ)
//! and all types of other registers like K, MM, BND, XMM, YMM, ZMM, and TMM.
//! - Register Group (\ref RegGroup) - Groups multiple register types under a single group - for example all
//! general-purpose registers (of all sizes) on X86 are part of \ref RegGroup::kGp and all SIMD registers
//! (XMM, YMM, ZMM) are part of \ref RegGroup::kVec.
//! - Register Size - Contains the size of the register in bytes. If the size depends on the mode (32-bit vs
//! 64-bit) then generally the higher size is used (for example RIP register has size 8 by default).
//! - Register Id - Contains physical or virtual id of the register.
//! - \ref BaseMem - Used to reference a memory location. Memory operand provides:
//! - Base Register - A base register type and id (physical or virtual).
//! - Index Register - An index register type and id (physical or virtual).
//! - Offset - Displacement or absolute address to be referenced (32-bit if base register is used and 64-bit if
//! base register is not used).
//! - Flags that can describe various architecture dependent information (like scale and segment-override on X86).
//! - \ref Imm - Immediate values are usually part of instructions (encoded within the instruction itself) or data.
//! - \ref Label - used to reference a location in code or data. Labels must be created by the \ref BaseEmitter or
//! by \ref CodeHolder. Each label has its unique id per \ref CodeHolder instance.
//!
//! ### Operand Manipulation
//!
//! AsmJit allows to construct operands dynamically, to store them, and to query a complete information about them at
//! run-time. Operands are small (always 16 bytes per `Operand`) and should be always copied (by value) if you intend
//! to store them (don't create operands by using `new` keyword, it's not recommended). Operands are safe to be passed
//! to `memcpy()` and `memset()`, which becomes handy when working with arrays of operands. If you set all members of
//! an \ref Operand to zero the operand would become NONE operand, which is the same as a default constructed Operand.
//!
//! The example below illustrates how operands can be used and modified even without using any other code generation
//! classes. The example uses X86 architecture-specific operands.
//!
//! ```
//! #include <asmjit/x86.h>
//!
//! using namespace asmjit;
//!
//! // Registers can be copied, it's a common practice.
//! x86::Gp dstRegByValue() { return x86::ecx; }
//!
//! void usingOperandsExample(x86::Assembler& a) {
//! // Gets `ecx` register returned by a function.
//! x86::Gp dst = dstRegByValue();
//! // Gets `rax` register directly from the provided `x86` namespace.
//! x86::Gp src = x86::rax;
//! // Constructs `r10` dynamically.
//! x86::Gp idx = x86::gpq(10);
//! // Constructs [src + idx] memory address - referencing [rax + r10].
//! x86::Mem m = x86::ptr(src, idx);
//!
//! // Examine `m`: Returns `RegType::kX86_Gpq`.
//! m.indexType();
//! // Examine `m`: Returns 10 (`r10`).
//! m.indexId();
//!
//! // Reconstruct `idx` stored in mem:
//! x86::Gp idx_2 = x86::Gp::fromTypeAndId(m.indexType(), m.indexId());
//!
//! // True, `idx` and idx_2` are identical.
//! idx == idx_2;
//!
//! // Possible - op will still be the same as `m`.
//! Operand op = m;
//! // True (can be casted to BaseMem or architecture-specific Mem).
//! op.isMem();
//!
//! // True, `op` is just a copy of `m`.
//! m == op;
//!
//! // Static cast is fine and valid here.
//! static_cast<BaseMem&>(op).addOffset(1);
//! // However, using `as<T>()` to cast to a derived type is preferred.
//! op.as<BaseMem>().addOffset(1);
//! // False, `op` now points to [rax + r10 + 2], which is not [rax + r10].
//! m == op;
//!
//! // Emitting 'mov' - type safe way.
//! a.mov(dst, m);
//! // Not possible, `mov` doesn't provide mov(x86::Gp, Operand) overload.
//! a.mov(dst, op);
//!
//! // Type-unsafe, but possible.
//! a.emit(x86::Inst::kIdMov, dst, m);
//! // Also possible, `emit()` is typeless and can be used with raw Operand.
//! a.emit(x86::Inst::kIdMov, dst, op);
//! }
//! ```
//!
//! Some operands have to be created explicitly by emitters. For example labels must be created by \ref
//! BaseEmitter::newLabel(), which creates a label entry and returns a \ref Label operand with the id that refers
//! to it. Such label then can be used by emitters.
//!
//! ### Memory Operands
//!
//! Some architectures like X86 provide a complex memory addressing model that allows to encode addresses having a
//! BASE register, INDEX register with a possible scale (left shift), and displacement (called offset in AsmJit).
//! Memory address on X86 can also specify memory segment (segment-override in X86 terminology) and some instructions
//! (gather / scatter) require INDEX to be a \ref x86::Vec register instead of a general-purpose register.
//!
//! AsmJit allows to encode and work with all forms of addresses mentioned and implemented by X86. In addition, it
//! also allows to construct absolute 64-bit memory address operands, which is only allowed in one form of 'mov'
//! instruction.
//!
//! ```
//! #include <asmjit/x86.h>
//!
//! using namespace asmjit;
//!
//! void testX86Mem() {
//! // Makes it easier to access x86 stuff...
//! using namespace asmjit::x86;
//!
//! // BASE + OFFSET.
//! Mem a = ptr(rax); // a = [rax]
//! Mem b = ptr(rax, 15); // b = [rax + 15]
//!
//! // BASE + INDEX << SHIFT - Shift is in BITS as used by X86!
//! Mem c = ptr(rax, rbx); // c = [rax + rbx]
//! Mem d = ptr(rax, rbx, 2); // d = [rax + rbx << 2]
//! Mem e = ptr(rax, rbx, 2, 15); // e = [rax + rbx << 2 + 15]
//!
//! // BASE + VM (Vector Index) (encoded as MOD+VSIB).
//! Mem f = ptr(rax, xmm1); // f = [rax + xmm1]
//! Mem g = ptr(rax, xmm1, 2); // g = [rax + xmm1 << 2]
//! Mem h = ptr(rax, xmm1, 2, 15); // h = [rax + xmm1 << 2 + 15]
//!
//! // Absolute address:
//! uint64_t addr = (uint64_t)0x1234;
//! Mem i = ptr(addr); // i = [0x1234]
//! Mem j = ptr(addr, rbx); // j = [0x1234 + rbx]
//! Mem k = ptr(addr, rbx, 2); // k = [0x1234 + rbx << 2]
//!
//! // LABEL - Will be encoded as RIP (64-bit) or absolute address (32-bit).
//! Label L = ...;
//! Mem m = ptr(L); // m = [L]
//! Mem n = ptr(L, rbx); // n = [L + rbx]
//! Mem o = ptr(L, rbx, 2); // o = [L + rbx << 2]
//! Mem p = ptr(L, rbx, 2, 15); // p = [L + rbx << 2 + 15]
//!
//! // RIP - 64-bit only (RIP can't use INDEX).
//! Mem q = ptr(rip, 24); // q = [rip + 24]
//! }
//! ```
//!
//! Memory operands can optionally contain memory size. This is required by instructions where the memory size cannot
//! be deduced from other operands, like `inc` and `dec` on X86:
//!
//! ```
//! #include <asmjit/x86.h>
//!
//! using namespace asmjit;
//!
//! void testX86Mem() {
//! // The same as: dword ptr [rax + rbx].
//! x86::Mem a = x86::dword_ptr(rax, rbx);
//!
//! // The same as: qword ptr [rdx + rsi << 0 + 1].
//! x86::Mem b = x86::qword_ptr(rdx, rsi, 0, 1);
//! }
//! ```
//!
//! Memory operands provide API that can be used to access its properties:
//!
//! ```
//! #include <asmjit/x86.h>
//!
//! using namespace asmjit;
//!
//! void testX86Mem() {
//! // The same as: dword ptr [rax + 12].
//! x86::Mem mem = x86::dword_ptr(rax, 12);
//!
//! mem.hasBase(); // true.
//! mem.hasIndex(); // false.
//! mem.size(); // 4.
//! mem.offset(); // 12.
//!
//! mem.setSize(0); // Sets the size to 0 (makes it sizeless).
//! mem.addOffset(-1); // Adds -1 to the offset and makes it 11.
//! mem.setOffset(0); // Sets the offset to 0.
//! mem.setBase(rcx); // Changes BASE to RCX.
//! mem.setIndex(rax); // Changes INDEX to RAX.
//! mem.hasIndex(); // true.
//! }
//! // ...
//! ```
//!
//! Making changes to memory operand is very comfortable when emitting loads
//! and stores:
//!
//! ```
//! #include <asmjit/x86.h>
//!
//! using namespace asmjit;
//!
//! void testX86Mem(CodeHolder& code) {
//! x86::Assembler a(code); // Your initialized x86::Assembler.
//! x86::Mem mSrc = x86::ptr(eax); // Construct [eax] memory operand.
//!
//! // One way of emitting bunch of loads is to use `mem.adjusted()`, which
//! // returns a new memory operand and keeps the source operand unchanged.
//! a.movaps(x86::xmm0, mSrc); // No adjustment needed to load [eax].
//! a.movaps(x86::xmm1, mSrc.adjusted(16)); // Loads from [eax + 16].
//! a.movaps(x86::xmm2, mSrc.adjusted(32)); // Loads from [eax + 32].
//! a.movaps(x86::xmm3, mSrc.adjusted(48)); // Loads from [eax + 48].
//!
//! // ... do something with xmm0-3 ...
//!
//! // Another way of adjusting memory is to change the operand in-place.
//! // If you want to keep the original operand you can simply clone it.
//! x86::Mem mDst = mSrc.clone(); // Clone mSrc.
//!
//! a.movaps(mDst, x86::xmm0); // Stores xmm0 to [eax].
//! mDst.addOffset(16); // Adds 16 to `mDst`.
//!
//! a.movaps(mDst, x86::xmm1); // Stores to [eax + 16] .
//! mDst.addOffset(16); // Adds 16 to `mDst`.
//!
//! a.movaps(mDst, x86::xmm2); // Stores to [eax + 32].
//! mDst.addOffset(16); // Adds 16 to `mDst`.
//!
//! a.movaps(mDst, x86::xmm3); // Stores to [eax + 48].
//! }
//! ```
//!
//! ### Assembler Examples
//!
//! - \ref x86::Assembler provides many X86/X64 examples.
//! \defgroup asmjit_builder Builder
//! \brief Builder interface, nodes, and passes.
//!
//! ### Overview
//!
//! Both \ref BaseBuilder and \ref BaseCompiler interfaces describe emitters that emit into a representation that
//! allows further processing. The code stored in such representation is completely safe to be patched, simplified,
//! reordered, obfuscated, removed, injected, analyzed, or processed some other way. Each instruction, label,
//! directive, or other building block is stored as \ref BaseNode (or derived class like \ref InstNode or \ref
//! LabelNode) and contains all the information necessary to pass that node later to the assembler.
//!
//! \ref BaseBuilder is an emitter that inherits from \ref BaseEmitter interface. It was designed to provide a maximum
//! compatibility with the existing \ref BaseAssembler emitter so users can move from assembler to builder when needed,
//! for example to implement post-processing, which is not possible with Assembler.
//!
//! ### Builder Nodes
//!
//! \ref BaseBuilder doesn't generate machine code directly, it uses an intermediate representation based on nodes,
//! however, it allows to serialize to \ref BaseAssembler when the code is ready to be encoded.
//!
//! There are multiple node types used by both \ref BaseBuilder and \ref BaseCompiler :
//!
//! - Basic nodes:
//! - \ref BaseNode - Base class for all nodes.
//! - \ref InstNode - Represents an instruction node.
//! - \ref AlignNode - Represents an alignment directive (.align).
//! - \ref LabelNode - Represents a location where to bound a \ref Label.
//!
//! - Data nodes:
//! - \ref EmbedDataNode - Represents data.
//! - \ref EmbedLabelNode - Represents \ref Label address embedded as data.
//! - \ref EmbedLabelDeltaNode - Represents a difference of two labels embedded in data.
//! - \ref ConstPoolNode - Represents a constant pool data embedded as data.
//!
//! - Informative nodes:
//! - \ref CommentNode - Represents a comment string, doesn't affect code generation.
//! - \ref SentinelNode - A marker that can be used to remember certain position in code or data, doesn't affect
//! code generation. Used by \ref FuncNode to mark the end of a function.
//!
//! - Other nodes are provided by \ref asmjit_compiler infrastructure.
//!
//! ### Builder Examples
//!
//! - \ref x86::Builder provides many X86/X64 examples.
//! \defgroup asmjit_compiler Compiler
//! \brief Compiler interface.
//!
//! ### Overview
//!
//! \ref BaseCompiler is a high-level interface, which provides register allocation and support for defining and
//! invoking functions, built on top of \ref BaseBuilder interface At the moment it's the easiest way of generating
//! code in AsmJit as most architecture and OS specifics is properly abstracted and handled by AsmJit automatically.
//! However, abstractions also mean restrictions, which means that \ref BaseCompiler has more limitations than \ref
//! BaseAssembler or \ref BaseBuilder.
//!
//! Since \ref BaseCompiler provides register allocation it also establishes the concept of functions - a function
//! in Compiler sense is a unit in which virtual registers are allocated into physical registers by the register
//! allocator. In addition, it enables to use such virtual registers in function invocations.
//!
//! \ref BaseCompiler automatically handles function calling conventions. It's still architecture dependent, but
//! makes the code generation much easies. Functions are essential; the first-step to generate some code is to define
//! a signature of the function to be generated (before generating the function body itself). Function arguments and
//! return value(s) are handled by assigning virtual registers to them. Similarly, function calls are handled the same
//! way.
//!
//! ### Compiler Nodes
//!
//! \ref BaseCompiler adds some nodes that are required for function generation and invocation:
//!
//! - \ref FuncNode - Represents a function definition.
//! - \ref FuncRetNode - Represents a function return.
//! - \ref InvokeNode - Represents a function invocation.
//!
//! \ref BaseCompiler also makes the use of passes (\ref Pass) and automatically adds an architecture-dependent
//! register allocator pass to the list of passes when attached to \ref CodeHolder.
//!
//! ### Compiler Examples
//!
//! - \ref x86::Compiler provides many X86/X64 examples.
//!
//! ### Compiler Tips
//!
//! Users of AsmJit have done mistakes in the past, this section should provide some useful tips for beginners:
//!
//! - Virtual registers in compiler are bound to a single function. At the moment the implementation doesn't
//! care whether a single virtual register is used in multiple functions, but it sees it as two independent
//! virtual registers in that case. This means that virtual registers cannot be used to implement global
//! variables. Global variables are basically memory addresses which functions can read from and write to,
//! and they have to be implemented in the same way.
//!
//! - Compiler provides a useful debugging functionality, which can be turned on through \ref FormatFlags. Use
//! \ref Logger::addFlags() to turn on additional logging features when using Compiler.
//! \defgroup asmjit_function Function
//! \brief Function definitions.
//!
//! ### Overview
//!
//! AsmJit provides functionality that can be used to define function signatures and to calculate automatically
//! optimal function frame that can be used directly by a prolog and epilog insertion. This feature was exclusive
//! to AsmJit's Compiler for a very long time, but was abstracted out and is now available for all users regardless
//! of the emitter they use. The following use cases are possible:
//!
//! - Calculate function frame before the function is generated - this is the only way available to \ref
//! BaseAssembler users and it will be described in this section.
//!
//! - Calculate function frame after the function is generated - this way is generally used by \ref BaseBuilder
//! and \ref BaseCompiler emitters and this way is generally described in \ref asmjit_compiler section.
//!
//! The following concepts are used to describe and create functions in AsmJit:
//!
//! - \ref TypeId - Type-id is an 8-bit value that describes a platform independent type as we know from C/C++.
//! It provides abstractions for most common types like `int8_t`, `uint32_t`, `uintptr_t`, `float`, `double`,
//! and all possible vector types to match ISAs up to AVX512. \ref TypeId was introduced originally for \ref
//! asmjit_compiler, but it's now used by \ref FuncSignature as well.
//!
//! - \ref CallConv - Describes a calling convention - this class contains instructions to assign registers and
//! stack addresses to function arguments and return value(s), but doesn't specify any function signature itself.
//! Calling conventions are architecture and OS dependent.
//!
//! - \ref FuncSignature - Describes a function signature, for example `int func(int, int)`. FuncSignature contains
//! a function calling convention id, return value type, and function arguments. The signature itself is platform
//! independent and uses \ref TypeId to describe types of function arguments and function return value(s).
//!
//! - \ref FuncDetail - Architecture and ABI dependent information that describes \ref CallConv and expanded \ref
//! FuncSignature. Each function argument and return value is represented as \ref FuncValue that contains the
//! original \ref TypeId enriched with additional information that specifies whether the value is passed or
//! returned by register (and which register) or by stack. Each value also contains some other metadata that
//! provide additional information required to handle it properly (for example whether a vector is passed
//! indirectly by a pointer as required by WIN64 calling convention).
//!
//! - \ref FuncFrame - Contains information about the function frame that can be used by prolog/epilog inserter
//! (PEI). Holds call stack size size and alignment, local stack size and alignment, and various attributes that
//! describe how prolog and epilog should be constructed. `FuncFrame` doesn't know anything about function's
//! arguments or return values, it hold only information necessary to create a valid and ABI conforming function
//! prologs and epilogs.
//!
//! - \ref FuncArgsAssignment - A helper class that can be used to reassign function arguments into user specified
//! registers. It's architecture and ABI dependent mapping from function arguments described by \ref CallConv
//! and \ref FuncDetail into registers specified by the user.
//!
//! It's a lot of concepts where each represents one step in a function frame calculation. It can be used to create
//! function prologs, epilogs, and also to calculate information necessary to perform function calls.
//! \defgroup asmjit_logging Logging
//! \brief Logging and formatting.
//!
//! ### Overview
//!
//! The initial phase of a project that generates machine code is not always smooth. Failure cases are common not just
//! at the beginning phase, but also during the development or refactoring. AsmJit provides logging functionality to
//! address this issue. AsmJit does already a good job with function overloading to prevent from emitting unencodable
//! instructions, but it can't prevent from emitting machine code that is correct at instruction level, but doesn't
//! work when it's executed asa whole. Logging has always been an important part of AsmJit's infrastructure and looking
//! at logs can sometimes reveal code generation issues quickly.
//!
//! AsmJit provides API for logging and formatting:
//!
//! - \ref Logger - A logger that you can pass to \ref CodeHolder and all emitters that inherit from \ref BaseEmitter.
//!
//! - \ref FormatOptions - Formatting options that can change how instructions and operands are formatted.
//!
//! - \ref Formatter - A namespace that provides functions that can format input data like \ref Operand, \ref BaseReg,
//! \ref Label, and \ref BaseNode into \ref String.
//!
//! AsmJit's \ref Logger serves the following purposes:
//!
//! - Provides a basic foundation for logging.
//!
//! - Abstract class leaving the implementation on users. The following built-in implementations are provided for
//! simplicity:
//!
//! - \ref FileLogger implements logging into a standard `FILE` stream.
//! - \ref StringLogger serializes all logs into a \ref String instance.
//!
//! AsmJit's \ref FormatOptions provides the following to customize the formatting of instructions and operands through:
//!
//! - \ref FormatFlags
//! - \ref FormatIndentationGroup
//!
//! ### Logging
//!
//! A \ref Logger is typically attached to a \ref CodeHolder, which propagates it to all attached emitters
//! automatically. The example below illustrates how to use \ref FileLogger that outputs to standard output:
//!
//! ```
//! #include <asmjit/core.h>
//! #include <stdio.h>
//!
//! using namespace asmjit;
//!
//! int main() {
//! JitRuntime rt; // Runtime specialized for JIT code execution.
//! FileLogger logger(stdout); // Logger should always survive CodeHolder.
//!
//! CodeHolder code; // Holds code and relocation information.
//! code.init(rt.environment()); // Initialize to the same arch as JIT runtime.
//! code.setLogger(&logger); // Attach the `logger` to `code` holder.
//!
//! // ... code as usual, everything emitted will be logged to `stdout` ...
//! return 0;
//! }
//! ```
//!
//! If output to FILE stream is not desired it's possible to use \ref StringLogger, which concatenates everything
//! into a multi-line string:
//!
//! ```
//! #include <asmjit/core.h>
//! #include <stdio.h>
//! #include <utility>
//!
//! using namespace asmjit;
//!
//! int main() {
//! JitRuntime rt; // Runtime specialized for JIT code execution.
//! StringLogger logger; // Logger should always survive CodeHolder.
//!
//! CodeHolder code; // Holds code and relocation information.
//! code.init(rt.environment()); // Initialize to the same arch as JIT runtime.
//! code.setLogger(&logger); // Attach the `logger` to `code` holder.
//!
//! // ... code as usual, logging will be concatenated to logger string ...
//!
//! // You can either use the string from StringLogger directly or you can
//! // move it. Logger::data() returns its content as null terminated char[].
//! printf("Logger content: %s\n", logger.data());
//!
//! // It can be moved into your own string like this:
//! String content = std::move(logger.content());
//! printf("The same content: %s\n", content.data());
//!
//! return 0;
//! }
//! ```
//!
//! ### Formatting
//!
//! AsmJit uses \ref Formatter to format inputs that are then passed to \ref Logger. Formatting is public and can be
//! used by AsmJit users as well. The most important thing to know regarding formatting is that \ref Formatter always
//! appends to the output string, so it can be used to build complex strings without having to concatenate
//! intermediate strings.
//!
//! The first example illustrates how to format operands:
//!
//! ```
//! #include <asmjit/core.h>
//! #include <stdio.h>
//!
//! using namespace asmjit;
//!
//! void logOperand(Arch arch, const Operand_& op) {
//! // The emitter is optional (named labels and virtual registers need it).
//! BaseEmitter* emitter = nullptr;
//!
//! // No flags by default.
//! FormatFlags formatFlags = FormatFlags::kNone;
//!
//! StringTmp<128> sb;
//! Formatter::formatOperand(sb, formatFlags, emitter, arch, op);
//! printf("%s\n", sb.data());
//! }
//!
//! void formattingExample() {
//! using namespace x86;
//!
//! // Architecture is not part of operand, it must be passed explicitly.
//! // Format flags. We pass it explicitly also to 'logOperand' to make
//! // compatible with what AsmJit normally does.
//! Arch arch = Arch::kX64;
//!
//! log(arch, rax); // Prints 'rax'.
//! log(arch, ptr(rax, rbx, 2)); // Prints '[rax + rbx * 4]`.
//! log(arch, dword_ptr(rax, rbx, 2)); // Prints 'dword [rax + rbx * 4]`.
//! log(arch, imm(42)); // Prints '42'.
//! }
//! ```
//!
//! Next example illustrates how to format whole instructions:
//!
//! ```
//! #include <asmjit/core.h>
//! #include <stdio.h>
//! #include <utility>
//!
//! using namespace asmjit;
//!
//! template<typename... Args>
//! void logInstruction(Arch arch, const BaseInst& inst, Args&&... args) {
//! // The emitter is optional (named labels and virtual registers need it).
//! BaseEmitter* emitter = nullptr;
//!
//! // No flags by default.
//! FormatFlags formatFlags = FormatFlags::kNone;
//!
//! // The formatter expects operands in an array.
//! Operand_ operands { std::forward<Args>(args)... };
//!
//! StringTmp<128> sb;
//! Formatter::formatInstruction(
//! sb, formatFlags, emitter, arch, inst, operands, sizeof...(args));
//! printf("%s\n", sb.data());
//! }
//!
//! void formattingExample() {
//! using namespace x86;
//!
//! // Architecture is not part of operand, it must be passed explicitly.
//! // Format flags. We pass it explicitly also to 'logOperand' to make
//! // compatible with what AsmJit normally does.
//! Arch arch = Arch::kX64;
//!
//! // Prints 'mov rax, rcx'.
//! logInstruction(arch, BaseInst(Inst::kIdMov), rax, rcx);
//!
//! // Prints 'vaddpd zmm0, zmm1, [rax] {1to8}'.
//! logInstruction(arch,
//! BaseInst(Inst::kIdVaddpd),
//! zmm0, zmm1, ptr(rax)._1toN());
//!
//! // BaseInst abstracts instruction id, instruction options, and extraReg.
//! // Prints 'lock add [rax], rcx'.
//! logInstruction(arch,
//! BaseInst(Inst::kIdAdd, InstOptions::kX86_Lock),
//! x86::ptr(rax), rcx);
//!
//! // Similarly an extra register (like AVX-512 selector) can be used.
//! // Prints 'vaddpd zmm0 {k2} {z}, zmm1, [rax]'.
//! logInstruction(arch,
//! BaseInst(Inst::kIdAdd, InstOptions::kX86_ZMask, k2),
//! zmm0, zmm1, ptr(rax));
//! }
//! ```
//!
//! And finally, the example below illustrates how to use a built-in function to format the content of
//! \ref BaseBuilder, which consists of nodes:
//!
//! ```
//! #include <asmjit/core.h>
//! #include <stdio.h>
//!
//! using namespace asmjit;
//!
//! void formattingExample(BaseBuilder* builder) {
//! FormatFlags formatFlags = FormatFlags::kNone;
//!
//! // This also shows how temporary strings can be used.
//! StringTmp<512> sb;
//!
//! // FormatNodeList requires the String for output, formatting flags, which
//! // were zero (no extra flags), and the builder instance, which we have
//! // provided. An overloaded version also exists, which accepts begin and
//! // and end nodes, which can be used to only format a range of nodes.
//! Formatter::formatNodeList(sb, formatFlags, builder);
//!
//! // You can do whatever else with the string, it's always null terminated,
//! // so it can be passed to C functions like printf().
//! printf("%s\n", sb.data());
//! }
//! ```
//! \defgroup asmjit_error_handling Error Handling
//! \brief Error handling.
//!
//! ### Overview
//!
//! AsmJit uses error codes to represent and return errors. Every function that can fail returns an \ref Error code.
//! Exceptions are never thrown by AsmJit itself even in extreme conditions like out-of-memory, but it's possible to
//! override \ref ErrorHandler::handleError() to throw, in that case no error will be returned and exception will be
//! thrown instead. All functions where this can happen are not marked `noexcept`.
//!
//! Errors should never be ignored, however, checking errors after each AsmJit API call would simply overcomplicate
//! the whole code generation experience. \ref ErrorHandler exists to make the use of AsmJit API simpler as it allows
//! to customize how errors can be handled:
//!
//! - Record the error and continue (the way how the error is user-implemented).
//! - Throw an exception. AsmJit doesn't use exceptions and is completely exception-safe, but it's perfectly legal
//! to throw an exception from the error handler.
//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler, Builder and Compiler to a
//! consistent state before calling \ref ErrorHandler::handleError(), so `longjmp()` can be used without issues
//! to cancel the code-generation if an error occurred. This method can be used if exception handling in your
//! project is turned off and you still want some comfort. In most cases it should be safe as AsmJit uses \ref
//! Zone memory and the ownership of memory it allocates always ends with the instance that allocated it. If
//! using this approach please never jump outside the life-time of \ref CodeHolder and \ref BaseEmitter.
//!
//! ### Using ErrorHandler
//!
//! An example of attaching \ref ErrorHandler to \ref CodeHolder.
//!
//! ```
//! #include <asmjit/x86.h>
//! #include <stdio.h>
//!
//! using namespace asmjit;
//!
//! // A simple error handler implementation, extend according to your needs.
//! class MyErrorHandler : public ErrorHandler {
//! public:
//! void handleError(Error err, const char* message, BaseEmitter* origin) override {
//! printf("AsmJit error: %s\n", message);
//! }
//! };
//!
//! int main() {
//! JitRuntime rt;
//!
//! MyErrorHandler myErrorHandler;
//! CodeHolder code;
//!
//! code.init(rt.environment());
//! code.setErrorHandler(&myErrorHandler);
//!
//! x86::Assembler a(&code);
//! // ... code generation ...
//!
//! return 0;
//! }
//! ```
//!
//! Useful classes in error handling group:
//!
//! - See \ref DebugUtils that provides utilities useful for debugging.
//! - See \ref Error that lists error codes that AsmJit uses.
//! - See \ref ErrorHandler for more details about error handling.
//! \defgroup asmjit_instruction_db Instruction DB
//! \brief Instruction database (introspection, read/write, validation, ...).
//!
//! ### Overview
//!
//! AsmJit provides a public instruction database that can be used to query information about a complete instruction.
//! The instruction database requires the knowledge of the following:
//!
//! - \ref BaseInst - Base instruction that contains instruction id, options, and a possible extra-register that
//! represents either REP prefix counter or AVX-512 selector (mask).
//!
//! - \ref Operand - Represents operands of an instruction.
//!
//! Each instruction can be then queried for the following information:
//!
//! - \ref InstRWInfo - Read/write information of instruction and its oprands (includes \ref OpRWInfo).
//!
//! - \ref CpuFeatures - CPU features required to execute the instruction.
//!
//! In addition to query functionality AsmJit is also able to validate whether an instruction and its operands are
//! valid. This is useful for making sure that what user tries to emit is correct and it can be also used by other
//! projects that parse user input, like AsmTK project.
//!
//! ### Query API
//!
//! The instruction query API is provided by \ref InstAPI namespace. The following queries are possible:
//!
//! - \ref InstAPI::queryRWInfo() - queries read/write information of the given instruction and its operands.
//! Includes also CPU flags read/written.
//!
//! - \ref InstAPI::queryFeatures() - queries CPU features that are required to execute the given instruction. A full
//! instruction with operands must be given as some architectures like X86 may require different features for the
//! same instruction based on its operands.
//!
//! - <a href="https://github.com/asmjit/asmjit/blob/master/test/asmjit_test_instinfo.cpp">asmjit_test_instinfo.cpp</a>
//! can be also used as a reference about accessing instruction information.
//!
//! ### Validation API
//!
//! The instruction validation API is provided by \ref InstAPI namespace in the similar fashion like the Query API,
//! however, validation can also be turned on at \ref BaseEmitter level. The following is possible:
//!
//! - \ref InstAPI::validate() - low-level instruction validation function that is used internally by emitters
//! if strict validation is enabled.
//!
//! - \ref BaseEmitter::addDiagnosticOptions() - can be used to enable validation at emitter level, see \ref
//! DiagnosticOptions.
//! \defgroup asmjit_virtual_memory Virtual Memory
//! \brief Virtual memory management.
//!
//! ### Overview
//!
//! AsmJit's virtual memory management is divided into two main categories:
//!
//! - Low level API that provides cross-platform abstractions for virtual memory allocation. Implemented in
//! \ref VirtMem namespace.
//!
//! - High level API that makes it very easy to store generated code for execution. See \ref JitRuntime, which is
//! used by many examples for its simplicity and easy integration with \ref CodeHolder. There is also \ref
//! JitAllocator, which lays somewhere between RAW memory allocation and \ref JitRuntime.
//! \defgroup asmjit_zone Zone Memory
//! \brief Zone memory allocator and containers.
//!
//! ### Overview
//!
//! AsmJit uses zone memory allocation (also known as Arena allocation) to allocate most of the data it uses. It's a
//! fast allocator that allows AsmJit to allocate a lot of small data structures fast and without `malloc()` overhead.
//! Since code generators and all related classes are usually short-lived this approach decreases memory usage and
//! fragmentation as arena-based allocators always allocate larger blocks of memory, which are then split into smaller
//! chunks.
//!
//! Another advantage of zone memory allocation is that since the whole library uses this strategy it's very easy to
//! deallocate everything that a particular instance is holding by simply releasing the memory the allocator holds.
//! This improves destruction time of such objects as there is no destruction at all. Long-lived objects just reset
//! its data in destructor or in their reset() member function for a future reuse. For this purpose all containers in
//! AsmJit are also zone allocated.
//!
//! ### Zone Allocation
//!
//! - \ref Zone - Incremental zone memory allocator with minimum features. It can only allocate memory without the
//! possibility to return it back to the allocator.
//!
//! - \ref ZoneTmp - A temporary \ref Zone with some initial static storage. If the allocation requests fit the
//! static storage allocated then there will be no dynamic memory allocation during the lifetime of \ref ZoneTmp,
//! otherwise it would act as \ref Zone with one preallocated block on the stack.
//!
//! - \ref ZoneAllocator - A wrapper of \ref Zone that provides the capability of returning memory to the allocator.
//! Such memory is stored in a pool for later reuse.
//!
//! ### Zone Allocated Containers
//!
//! - \ref ZoneString - Zone allocated string.
//! - \ref ZoneHash - Zone allocated hash table.
//! - \ref ZoneTree - Zone allocated red-black tree.
//! - \ref ZoneList - Zone allocated double-linked list.
//! - \ref ZoneStack - Zone allocated stack.
//! - \ref ZoneVector - Zone allocated vector.
//! - \ref ZoneBitVector - Zone allocated vector of bits.
//!
//! ### Using Zone Allocated Containers
//!
//! The most common data structure exposed by AsmJit is \ref ZoneVector. It's very similar to `std::vector`, but the
//! implementation doesn't use exceptions and uses the mentioned \ref ZoneAllocator for performance reasons. You don't
//! have to worry about allocations as you should not need to add items to AsmJit's data structures directly as there
//! should be API for all required operations.
//!
//! The following APIs in \ref CodeHolder returns \ref ZoneVector reference:
//!
//! ```
//! using namespace asmjit;
//!
//! void example(CodeHolder& code) {
//! // Contains all emitters attached to CodeHolder.
//! const ZoneVector<BaseEmitter*>& emitters = code.emitters();
//!
//! // Contains all section entries managed by CodeHolder.
//! const ZoneVector<Section*>& sections = code.sections();
//!
//! // Contains all label entries managed by CodeHolder.
//! const ZoneVector<LabelEntry*>& labelEntries = code.labelEntries();
//!
//! // Contains all relocation entries managed by CodeHolder.
//! const ZoneVector<RelocEntry*>& relocEntries = code.relocEntries();
//! }
//! ```
//!
//! \ref ZoneVector has overloaded array access operator to make it possible to access its elements through operator[].
//! Some standard functions like \ref ZoneVector::empty(), \ref ZoneVector::size(), and \ref ZoneVector::data() are
//! provided as well. Vectors are also iterable through a range-based for loop:
//!
//! ```
//! using namespace asmjit;
//!
//! void example(CodeHolder& code) {
//! for (LabelEntry* le : code.labelEntries()) {
//! printf("Label #%u {Bound=%s Offset=%llu}",
//! le->id(),
//! le->isBound() ? "true" : "false",
//! (unsigned long long)le->offset());
//! }
//! }
//! ```
//!
//! ### Design Considerations
//!
//! Zone-allocated containers do not store the allocator within the container. This decision was made to reduce the
//! footprint of such containers as AsmJit tooling, especially Compiler's register allocation, may use many instances
//! of such containers to perform code analysis and register allocation.
//!
//! For example to append an item into a \ref ZoneVector it's required to pass the allocator as the first argument,
//! so it can be used in case that the vector needs a reallocation. Such function also returns an error, which must
//! be propagated to the caller.
//!
//! ```
//! using namespace asmjit
//!
//! Error example(ZoneAllocator* allocator) {
//! ZoneVector<int> vector;
//!
//! // Unfortunately, allocator must be provided to all functions that mutate
//! // the vector. However, AsmJit users should never need to do this as all
//! // manipulation should be done through public API, which takes care of
//! // that.
//! for (int i = 0; i < 100; i++) {
//! ASMJIT_PROPAGATE(vector.append(allocator, i));
//! }
//!
//! // By default vector's destructor doesn't release anything as it knows
//! // that its content is zone allocated. However, \ref ZoneVector::release
//! // can be used to explicitly release the vector data to the allocator if
//! // necessary
//! vector.release(allocator);
//! }
//! ```
//!
//! Containers like \ref ZoneVector also provide a functionality to reserve a certain number of items before any items
//! are added to it. This approach is used internally in most places as it allows to prepare space for data that will
//! be added to some container before the data itself was created.
//!
//! ```
//! using namespace asmjit
//!
//! Error example(ZoneAllocator* allocator) {
//! ZoneVector<int> vector;
//!
//! ASMJIT_PROPAGATE(vector.willGrow(100));
//! for (int i = 0; i < 100; i++) {
//! // Cannot fail.
//! vector.appendUnsafe(allocator, i);
//! }
//!
//! vector.release(allocator);
//! }
//! ```
//! \defgroup asmjit_utilities Utilities
//! \brief Utility classes and functions.
//!
//! ### Overview
//!
//! AsmJit uses and provides utility classes and functions, that can be used with AsmJit. The functionality can be
//! divided into the following topics:
//!
//! ### String Functionality
//!
//! - \ref String - AsmJit's string container, which is used internally and which doesn't use exceptions and has
//! a stable layout, which is not dependent on C++ standard library.
//!
//! - \ref StringTmp - String that can have base storage allocated on stack. The amount of storage on stack can
//! be specified as a template parameter.
//!
//! - \ref FixedString - Fixed string container limited up to N characters.
//!
//! ### Code Generation Utilities
//!
//! - \ref ConstPool - Constant pool used by \ref BaseCompiler, but also available to users that may find use of it.
//!
//! ### Support Functionality Used by AsmJit
//!
//! - \ref Support namespace provides many other utility functions and classes that are used by AsmJit, and made
//! public.
//! \defgroup asmjit_x86 X86 Backend
//! \brief X86/X64 backend.
//! \defgroup asmjit_arm ARM Commons
//! \brief ARM commons shared between AArch32 and AArch64.
//! \defgroup asmjit_a64 AArch64 Backend
//! \brief AArch64 backend.
//! \cond INTERNAL
//! \defgroup asmjit_ra RA
//! \brief Register allocator internals.
//! \endcond
} // {asmjit}
#include "asmjit-scope-begin.h"
#include "core/archtraits.h"
#include "core/assembler.h"
#include "core/builder.h"
#include "core/codeholder.h"
#include "core/compiler.h"
#include "core/constpool.h"
#include "core/cpuinfo.h"
#include "core/emitter.h"
#include "core/environment.h"
#include "core/errorhandler.h"
#include "core/formatter.h"
#include "core/func.h"
#include "core/globals.h"
#include "core/inst.h"
#include "core/jitallocator.h"
#include "core/jitruntime.h"
#include "core/logger.h"
#include "core/operand.h"
#include "core/osutils.h"
#include "core/string.h"
#include "core/support.h"
#include "core/target.h"
#include "core/type.h"
#include "core/virtmem.h"
#include "core/zone.h"
#include "core/zonehash.h"
#include "core/zonelist.h"
#include "core/zonetree.h"
#include "core/zonestack.h"
#include "core/zonestring.h"
#include "core/zonevector.h"
#include "asmjit-scope-end.h"
#endif // ASMJIT_CORE_H_INCLUDED
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_API_BUILD_P_H_INCLUDED
#define ASMJIT_CORE_API_BUILD_P_H_INCLUDED
#define ASMJIT_EXPORTS
// Only turn-off these warnings when building asmjit itself.
#ifdef _MSC_VER
#ifndef _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE
#endif
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#endif
// Dependencies only required for asmjit build, but never exposed through public headers.
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#endif
#include "./api-config.h"
#if !defined(ASMJIT_BUILD_DEBUG) && defined(__GNUC__) && !defined(__clang__)
#define ASMJIT_FAVOR_SIZE __attribute__((__optimize__("Os")))
#define ASMJIT_FAVOR_SPEED __attribute__((__optimize__("O3")))
#elif ASMJIT_CXX_HAS_ATTRIBUTE(__minsize__, 0)
#define ASMJIT_FAVOR_SIZE __attribute__((__minsize__))
#define ASMJIT_FAVOR_SPEED
#else
#define ASMJIT_FAVOR_SIZE
#define ASMJIT_FAVOR_SPEED
#endif
// Make sure '#ifdef'ed unit tests are properly highlighted in IDE.
#if !defined(ASMJIT_TEST) && defined(__INTELLISENSE__)
#define ASMJIT_TEST
#endif
// Include a unit testing package if this is a `asmjit_test_unit` build.
#if defined(ASMJIT_TEST)
#include "../../../test/broken.h"
#endif
#endif // ASMJIT_CORE_API_BUILD_P_H_INCLUDED
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment