Singularity/Library/PackageCache/com.unity.burst@1.8.4/Editor/BurstDisassembler.Core.ARM6...
2024-05-06 11:45:45 -07:00

1434 lines
36 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
#if UNITY_EDITOR || BURST_INTERNAL
namespace Unity.Burst.Editor
{
internal partial class BurstDisassembler
{
internal class ARM64AsmTokenKindProvider : AsmTokenKindProvider
{
private static readonly string[] Registers = new[]
{
"nzcv",
"wsp",
"sp",
"lr",
"r0",
"r1",
"r2",
"r3",
"r4",
"r5",
"r6",
"r7",
"r8",
"r9",
"r10",
"r11",
"r12",
"r13",
"r14",
"r15",
"b0",
"b1",
"b2",
"b3",
"b4",
"b5",
"b6",
"b7",
"b8",
"b9",
"b10",
"b11",
"b12",
"b13",
"b14",
"b15",
"b16",
"b17",
"b18",
"b19",
"b20",
"b21",
"b22",
"b23",
"b24",
"b25",
"b26",
"b27",
"b28",
"b29",
"b30",
"b31",
"d0",
"d1",
"d2",
"d3",
"d4",
"d5",
"d6",
"d7",
"d8",
"d9",
"d10",
"d11",
"d12",
"d13",
"d14",
"d15",
"d16",
"d17",
"d18",
"d19",
"d20",
"d21",
"d22",
"d23",
"d24",
"d25",
"d26",
"d27",
"d28",
"d29",
"d30",
"d31",
"h0",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"h7",
"h8",
"h9",
"h10",
"h11",
"h12",
"h13",
"h14",
"h15",
"h16",
"h17",
"h18",
"h19",
"h20",
"h21",
"h22",
"h23",
"h24",
"h25",
"h26",
"h27",
"h28",
"h29",
"h30",
"h31",
"q0",
"q1",
"q2",
"q3",
"q4",
"q5",
"q6",
"q7",
"q8",
"q9",
"q10",
"q11",
"q12",
"q13",
"q14",
"q15",
"q16",
"q17",
"q18",
"q19",
"q20",
"q21",
"q22",
"q23",
"q24",
"q25",
"q26",
"q27",
"q28",
"q29",
"q30",
"q31",
"s0",
"s1",
"s2",
"s3",
"s4",
"s5",
"s6",
"s7",
"s8",
"s9",
"s10",
"s11",
"s12",
"s13",
"s14",
"s15",
"s16",
"s17",
"s18",
"s19",
"s20",
"s21",
"s22",
"s23",
"s24",
"s25",
"s26",
"s27",
"s28",
"s29",
"s30",
"s31",
"w0",
"w1",
"w2",
"w3",
"w4",
"w5",
"w6",
"w7",
"w8",
"w9",
"w10",
"w11",
"w12",
"w13",
"w14",
"w15",
"w16",
"w17",
"w18",
"w19",
"w20",
"w21",
"w22",
"w23",
"w24",
"w25",
"w26",
"w27",
"w28",
"w29",
"w30",
"wzr",
"x0",
"x1",
"x2",
"x3",
"x4",
"x5",
"x6",
"x7",
"x8",
"x9",
"x10",
"x11",
"x12",
"x13",
"x14",
"x15",
"x16",
"x17",
"x18",
"x19",
"x20",
"x21",
"x22",
"x23",
"x24",
"x25",
"x26",
"x27",
"x28",
"x29",
"x30",
"v0",
"v1",
"v2",
"v3",
"v4",
"v5",
"v6",
"v7",
"v8",
"v9",
"v10",
"v11",
"v12",
"v13",
"v14",
"v15",
"v16",
"v17",
"v18",
"v19",
"v20",
"v21",
"v22",
"v23",
"v24",
"v25",
"v26",
"v27",
"v28",
"v29",
"v30",
};
private static readonly string[] Instructions = new[]
{
"bkpt",
"usat",
"stm",
"stmia",
"stmib",
"stmda",
"stmdb",
"ldm",
"ldmia",
"ldmib",
"ldmda",
"ldmdb",
"it",
"itt",
"ittt",
"itttt",
"ite",
"itte",
"ittte",
"uxtab",
"abs",
"adc",
"add",
"addhi",
"adds",
"addhn",
"addhn2",
"addp",
"addv",
"addw",
"adr",
"adrp",
"aesd",
"aese",
"aesimc",
"aesmc",
"and",
"asr",
"asrs",
"at",
"bfi",
"bfm",
"bfxil",
"bic",
"bif",
"bit",
"brk",
"bsl",
"ccmn",
"ccmp",
"clrex",
"cls",
"clz",
"cmeq",
"cmge",
"cmgt",
"cmhi",
"cmhs",
"cmle",
"cmlt",
"cmn",
"cmp",
"cmtst",
"cnt",
"crc32b",
"crc32cb",
"crc32ch",
"crc32cw",
"crc32cx",
"crc32h",
"crc32w",
"crc32x",
"csel",
"csinc",
"csinv",
"csneg",
"dc",
"dcps1",
"dcps2",
"dcps3",
"dmb",
"drps",
"dsb",
"dup",
"eon",
"eor",
"eors",
"eret",
"ext",
"extr",
"fabd",
"fabs",
"facge",
"facgt",
"fadd",
"faddp",
"fccmp",
"fccmpe",
"fcmeq",
"fcmge",
"fcmgt",
"fcmle",
"fcmlt",
"fcmp",
"fcmpe",
"fcsel",
"fcvt",
"fcvtas",
"fcvtau",
"fcvtl",
"fcvtl2",
"fcvtms",
"fcvtmu",
"fcvtn",
"fcvtn2",
"fcvtns",
"fcvtnu",
"fcvtps",
"fcvtpu",
"fcvtxn",
"fcvtxn2",
"fcvtzs",
"fcvtzu",
"fdiv",
"fmadd",
"fmax",
"fmaxnm",
"fmaxnmp",
"fmaxnmv",
"fmaxp",
"fmaxv",
"fmin",
"fminnm",
"fminnmp",
"fminnmv",
"fminp",
"fminv",
"fmla",
"fmls",
"fmov",
"fmsub",
"fmul",
"fmulx",
"fneg",
"fnmadd",
"fnmsub",
"fnmul",
"frecpe",
"frecps",
"frecpx",
"frinta",
"frinti",
"frintm",
"frintn",
"frintp",
"frintx",
"frintz",
"frsqrte",
"frsqrts",
"fsqrt",
"fsub",
"hint",
"hlt",
"hvc",
"ic",
"ins",
"isb",
"ld1",
"ld1r",
"ld2",
"ld2r",
"ld3",
"ld3r",
"ld4",
"ld4r",
"ldar",
"ldarb",
"ldarh",
"ldaxp",
"ldaxr",
"ldaxrb",
"ldaxrh",
"ldnp",
"ldp",
"ldpsw",
"ldr",
"ldrb",
"ldrd",
"ldrh",
"ldrsb",
"ldrsh",
"ldrsw",
"ldtr",
"ldtrb",
"ldtrh",
"ldtrsb",
"ldtrsh",
"ldtrsw",
"ldur",
"ldurb",
"ldurh",
"ldursb",
"ldursh",
"ldursw",
"ldxp",
"ldxr",
"ldxrb",
"ldxrh",
"lsl",
"lsls",
"lsr",
"lsrs",
"madd",
"mla",
"mls",
"mneg",
"mov",
"movi",
"movk",
"movn",
"movt",
"movz",
"movw",
"mrs",
"msr",
"msub",
"mul",
"muls",
"mvn",
"mvns",
"mvni",
"neg",
"ngc",
"nop",
"not",
"orn",
"orr",
"orrs",
"pmul",
"pmull",
"pmull2",
"prfm",
"prfum",
"raddhn",
"raddhn2",
"rbit",
"rev",
"rev16",
"rev32",
"rev64",
"ror",
"rshrn",
"rshrn2",
"rsubhn",
"rsubhn2",
"saba",
"sabal",
"sabal2",
"sabd",
"sabdl",
"sabdl2",
"sadalp",
"saddl",
"saddl2",
"saddlp",
"saddlv",
"saddw",
"saddw2",
"sbc",
"sbfiz",
"sbfm",
"sbfx",
"scvtf",
"sdiv",
"sev",
"sevl",
"sha1c",
"sha1h",
"sha1m",
"sha1p",
"sha1su0",
"sha1su1",
"sha256h",
"sha256h2",
"sha256su0",
"sha256su1",
"shadd",
"shl",
"shll",
"shll2",
"shrn",
"shrn2",
"shsub",
"sli",
"smaddl",
"smax",
"smaxp",
"smaxv",
"smc",
"smin",
"sminp",
"sminv",
"smlal",
"smlal2",
"smlsl",
"smlsl2",
"smnegl",
"smov",
"smsubl",
"smulh",
"smull",
"smull2",
"sqabs",
"sqadd",
"sqdmlal",
"sqdmlal2",
"sqdmlsl",
"sqdmlsl2",
"sqdmulh",
"sqdmull",
"sqdmull2",
"sqneg",
"sqrdmulh",
"sqrshl",
"sqrshrn",
"sqrshrn2",
"sqrshrun",
"sqrshrun2",
"sqshl",
"sqshlu",
"sqshrn",
"sqshrn2",
"sqshrun",
"sqshrun2",
"sqsub",
"sqxtn",
"sqxtn2",
"sqxtun",
"sqxtun2",
"srhadd",
"sri",
"srshl",
"srshr",
"srsra",
"sshl",
"sshll",
"sshll2",
"sshr",
"ssra",
"ssubl",
"ssubl2",
"ssubw",
"ssubw2",
"st1",
"st2",
"st3",
"st4",
"stlr",
"stlrb",
"stlrh",
"stlxp",
"stlxr",
"stlxrb",
"stlxrh",
"stnp",
"stp",
"str",
"strd",
"strb",
"strh",
"sttr",
"sttrb",
"sttrh",
"stur",
"sturb",
"sturh",
"stxp",
"stxr",
"stxrb",
"stxrh",
"sub",
"subw",
"subs",
"rsb",
"rsbs",
"subhn",
"subhn2",
"suqadd",
"svc",
"sxtb",
"sxth",
"sxtw",
"sys",
"sysl",
"tbl",
"tbx",
"tbb",
"tbh",
"tlbi",
"trn1",
"trn2",
"tst",
"uaba",
"uabal",
"uabal2",
"uabd",
"uabdl",
"uabdl2",
"uadalp",
"uaddl",
"uaddl2",
"uaddlp",
"uaddlv",
"uaddw",
"uaddw2",
"ubfiz",
"ubfm",
"ubfx",
"ucvtf",
"udiv",
"uhadd",
"uhsub",
"umaddl",
"umax",
"umaxp",
"umaxv",
"umin",
"uminp",
"uminv",
"umlal",
"umlal2",
"umlsl",
"umlsl2",
"umnegl",
"umov",
"umsubl",
"umulh",
"umull",
"umull2",
"uqadd",
"uqrshl",
"uqrshrn",
"uqrshrn2",
"uqshl",
"uqshrn",
"uqshrn2",
"uqsub",
"uqxtn",
"uqxtn2",
"urecpe",
"urhadd",
"urshl",
"urshr",
"ursqrte",
"ursra",
"ushl",
"ushll",
"ushll2",
"ushr",
"usqadd",
"usra",
"usubl",
"usubl2",
"usubw",
"usubw2",
"uxtb",
"uxth",
"uzp1",
"uzp2",
"wfe",
"wfi",
"xtn",
"xtn2",
"yield",
"zip1",
"zip2",
"adcs",
"addg",
"adrl",
"ands",
"asrv",
"autda",
"autdza",
"autdb",
"autdzb",
"autia",
"autiza",
"autia1716",
"autiasp",
"autiaz",
"autib",
"autizb",
"autib1716",
"autibsp",
"autibz",
"axflag",
"b.cond",
"bfc",
"bics",
"cinc",
"cinv",
"cmpp",
"cneg",
"csdb",
"cset",
"csetm",
"eretaa",
"eretab",
"esb",
"irg",
"ldg",
"ldgv",
"lslv",
"lsrv",
"movl",
"negs",
"ngcs",
"pacda",
"pacdza",
"pacdb",
"pacdzb",
"pacga",
"pacia",
"paciza",
"pacia1716",
"paciasp",
"paciaz",
"pacib",
"pacizb",
"pacib1716",
"pacibsp",
"pacibz",
"psb",
"rorv",
"sbcs",
"st2g",
"stg",
"stgp",
"stgv",
"stz2g",
"stzg",
"subg",
"subp",
"subps",
"xaflag",
"xpacd",
"xpaci",
"xpaclri",
"casa",
"casal",
"cas",
"casl",
"casab",
"casalb",
"casb",
"caslb",
"casah",
"casalh",
"cash",
"caslh",
"caspa",
"caspal",
"casp",
"caspl",
"ldadda",
"ldaddal",
"ldadd",
"ldaddl",
"ldaddab",
"ldaddalb",
"ldaddb",
"ldaddlb",
"ldaddah",
"ldaddalh",
"ldaddh",
"ldaddlh",
"ldapr",
"ldaprb",
"ldaprh",
"ldclra",
"ldclral",
"ldclr",
"ldclrl",
"ldclrab",
"ldclralb",
"ldclrb",
"ldclrlb",
"ldclrah",
"ldclralh",
"ldclrh",
"ldclrlh",
"ldeora",
"ldeoral",
"ldeor",
"ldeorl",
"ldeorab",
"ldeoralb",
"ldeorb",
"ldeorlb",
"ldeorah",
"ldeoralh",
"ldeorh",
"ldeorlh",
"ldlar",
"ldlarb",
"ldlarh",
"ldraa",
"ldrab",
"ldseta",
"ldsetal",
"ldset",
"ldsetl",
"ldsetab",
"ldsetalb",
"ldsetb",
"ldsetlb",
"ldsetah",
"ldsetalh",
"ldseth",
"ldsetlh",
"ldsmaxa",
"ldsmaxal",
"ldsmax",
"ldsmaxl",
"ldsmaxab",
"ldsmaxalb",
"ldsmaxb",
"ldsmaxlb",
"ldsmaxah",
"ldsmaxalh",
"ldsmaxh",
"ldsmaxlh",
"ldsmina",
"ldsminal",
"ldsmin",
"ldsminl",
"ldsminab",
"ldsminalb",
"ldsminb",
"ldsminlb",
"ldsminah",
"ldsminalh",
"ldsminh",
"ldsminlh",
"ldumaxa",
"ldumaxal",
"ldumax",
"ldumaxl",
"ldumaxab",
"ldumaxalb",
"ldumaxb",
"ldumaxlb",
"ldumaxah",
"ldumaxalh",
"ldumaxh",
"ldumaxlh",
"ldumina",
"lduminal",
"ldumin",
"lduminl",
"lduminab",
"lduminalb",
"lduminb",
"lduminlb",
"lduminah",
"lduminalh",
"lduminh",
"lduminlh",
"stadd",
"staddl",
"staddb",
"staddlb",
"staddh",
"staddlh",
"stclr",
"stclrl",
"stclrb",
"stclrlb",
"stclrh",
"stclrlh",
"steor",
"steorl",
"steorb",
"steorlb",
"steorh",
"steorlh",
"stllr",
"stllrb",
"stllrh",
"stset",
"stsetl",
"stsetb",
"stsetlb",
"stseth",
"stsetlh",
"stsmax",
"stsmaxl",
"stsmaxb",
"stsmaxlb",
"stsmaxh",
"stsmaxlh",
"stsmin",
"stsminl",
"stsminb",
"stsminlb",
"stsminh",
"stsminlh",
"stumax",
"stumaxl",
"stumaxb",
"stumaxlb",
"stumaxh",
"stumaxlh",
"stumin",
"stuminl",
"stuminb",
"stuminlb",
"stuminh",
"stuminlh",
"swpa",
"swpal",
"swp",
"swpl",
"swpab",
"swpalb",
"swpb",
"swplb",
"swpah",
"swpalh",
"swph",
"swplh",
"fjcvtzs",
"fcmla",
"fmlal",
"fmlsl",
"sqrdmlah",
"sqrdmlsh",
"fcadd",
"sdot",
"sxtl",
"sxtl2",
"udot",
"uxtl",
"uxtl2",
"bcax",
"eor3",
"rax1",
"sha512h2",
"sha512h",
"sha512su0",
"sha512su1",
"sm3partw1",
"sm3partw2",
"sm3ss1",
"sm3tt1a",
"sm3tt1b",
"sm3tt2a",
"sm3tt2b",
"sm4e",
"sm4ekey",
"xar",
};
private static readonly string[] BranchInstructions = new string[]
{
"beq",
"bne",
"bcs",
"bhs",
"bcc",
"blo",
"bmi",
"bpl",
"bvs",
"bvc",
"bhi",
"bls",
"bge",
"blt",
"bgt",
"ble",
"bal",
"bnv",
"cbnz",
"cbz",
"tbnz",
"tbz",
"blraa",
"blraaz",
"blrab",
"blrabz",
"braa",
"braaz",
"brab",
"brabz",
};
private static readonly string[] JumpInstructions = new string[]
{
"b",
"br",
"blr",
"bx",
"bl",
"blx",
"bxj",
};
private static readonly string[] ReturnInstructions = new string[]
{
"ret",
"retaa",
"retab",
};
private static readonly string[] SimdInstructions = new string[]
{
// TODO: add missing instructions
"vld1",
"vld2",
"vld3",
"vld4",
"vabs",
"vadd",
"vaddl",
"vaddw",
"vmov",
"movs",
"vmul",
"vsub",
"vaba",
"vabl",
"vabd",
"vabdl",
"vacge",
"vacgt",
"vacle",
"vaclt",
"vaddhn",
"vand",
"vbic",
"vbif",
"vbit",
"vbsl",
"vceq",
"vcge",
"vcgt",
"vcle",
"vcls",
"vcnt",
"vclt",
"vclz",
"vcvt",
"vdup",
"veor",
"vext",
"vfma",
"vfms",
"vhadd",
"vhsub",
"vld",
"vmax",
"vmin",
"vmla",
"vmls",
"vmovl",
"vmovn",
"vmvn",
"vneg",
"vorn",
"vorr",
"vpadal",
"vpadd",
"vpmax",
"vpmin",
"vqabs",
"vqadd",
"vqdmlal",
"vqdmlsl",
"vqdmull",
"vqdmulh",
"vqmovn",
"vqneg",
"vqrdmulh",
"vqrshl",
"vqrshrn",
"vqshl",
"vqshrn",
"vqsub",
"vraddhn",
"vrecpe",
"vrecps",
"vrev",
"vrhadd",
"vrshr",
"vrshrn",
"vrsqrte",
"vrsqrts",
"vrsra",
"vrsubhn",
"vshl",
"vshr",
"vshrn",
"vsli",
"vsra",
"vsri",
"vst",
"vst1",
"vst2",
"vst3",
"vst4",
"vsubhn",
"vswp",
"vtbl",
"vtbx",
"vtrn",
"vtst",
"vuzp",
"vzip",
"vldm",
"vldr",
"vmrs",
"vmsr",
"vpop",
"vpush",
"vstm",
"vstr",
"vcmp",
"vcmpe",
"vcvtb",
"vcvtt",
"vdiv",
"vfnma",
"vfnms",
"vnmla",
"vnmls",
"vnmul",
"vsqrt",
"push",
"pop",
};
private ARM64AsmTokenKindProvider() : base(Registers.Length +
Instructions.Length +
BranchInstructions.Length +
JumpInstructions.Length +
ReturnInstructions.Length +
SimdInstructions.Length)
{
foreach (var register in Registers)
{
AddTokenKind(register, AsmTokenKind.Register);
}
foreach (var instruction in Instructions)
{
AddTokenKind(instruction, AsmTokenKind.Instruction);
}
foreach (var instruction in BranchInstructions)
{
AddTokenKind(instruction, AsmTokenKind.BranchInstruction);
}
foreach (var instruction in JumpInstructions)
{
AddTokenKind(instruction, AsmTokenKind.JumpInstruction);
}
foreach (var instruction in ReturnInstructions)
{
AddTokenKind(instruction, AsmTokenKind.ReturnInstruction);
}
foreach (var instruction in SimdInstructions)
{
AddTokenKind(instruction, AsmTokenKind.InstructionSIMD);
}
}
public override AsmTokenKind FindTokenKind(StringSlice instr)
{
instr = TryRemoveT(instr); // error here now that I added b.le etc.
var kind = base.FindTokenKind(instr);
if (kind != AsmTokenKind.Identifier)
{
return kind;
}
// Did not find instruction in listed instructions.
// Try matching whether it ended on a condition flag.
instr = TryRemoveCond(instr);
kind = base.FindTokenKind(instr);
return kind;
}
private static bool IsConditional(string text)
{
switch (text)
{
case "eq":
case "ne":
case "cs":
case "hs":
case "cc":
case "lo":
case "mi":
case "pl":
case "vs":
case "vc":
case "hi":
case "ls":
case "ge":
case "lt":
case "gt":
case "le":
case "al":
return true;
default:
return false;
}
}
internal static StringSlice TryRemoveT(StringSlice instr)
{
var idx = instr.IndexOf('.');
if (idx < 0)
{
return instr;
}
var instrS = instr.ToString();
if (IsConditional(instrS.Substring(idx+1)))
{
// remove '.' from string e.g. b.le => ble
return new StringSlice(instrS.Remove(idx, 1));
}
return new StringSlice(instrS, 0, idx);
}
internal static StringSlice TryRemoveCond(StringSlice instr)
{
if (instr.Length < 2)
{
return instr;
}
var instrS = instr.ToString();
var idx = instr.Length - 2;
return IsConditional(instrS.Substring(idx, 2))
? new StringSlice(instrS, 0, idx)
: instr;
}
private static bool IsFloatingRegister(string reg)
{
if (reg == "sp")
{
return false;
}
var c = reg[0];
return c == 'b' || c == 'h' || c == 's' || c == 'd' || c == 'q' || c == 'v';
}
private static int StripSizeIdentifier(string reg, int idx)
{
// "sp" only register that defies the heuristic.
if (reg != "sp")
{
switch (reg[idx])
{
case 'w':
case 'x':
case 's':
case 'q':
case 'h':
case 'b':
case 'd':
case 'v':
idx++;
break;
}
}
return idx;
}
public override bool RegisterEqual(string regA, string regB)
{
var isAFloat = IsFloatingRegister(regA);
var isBFloat = IsFloatingRegister(regB);
if ((isAFloat && isBFloat) || (isAFloat == isBFloat))
{
var idxA = StripSizeIdentifier(regA, 0);
var idxB = StripSizeIdentifier(regB, 0);
var lenA = regA.Length;
var lenB = regB.Length;
while (idxA < lenA && idxB < lenB)
{
if (regA[idxA] != regB[idxB])
{
break;
}
if ((idxA == lenA - 1 || regA[idxA+1] == '.')
&& (idxB == lenB - 1 || regB[idxB+1] == '.'))
{
return true;
}
idxA++;
idxB++;
}
}
return false;
}
/// <summary>
/// Assumes <see cref="instruction"/> is an arm SIMD instruction.
/// Returns whether it's a packed or scalar SIMD instruction.
/// </summary>
public override SIMDkind SimdKind(StringSlice instruction) =>
instruction.Contains('.')
? SIMDkind.Packed
: SIMDkind.Scalar;
public static readonly ARM64AsmTokenKindProvider Instance = new ARM64AsmTokenKindProvider();
}
}
}
#endif