From 0f56fdd506322253c21f3c0f4abc2a14a5d6db55 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Tue, 2 Jun 2026 18:40:24 -0400 Subject: [PATCH 1/2] [ARMv7] Expand ARM, Thumb, and NEON lifting coverage Add LLIL support for a broad set of previously unimplemented or partially implemented ARMv7, Thumb2, VFP, and NEON instructions. Cover system, control, synchronization, hint, and coprocessor operations, including MRS, MSR, VMSR, VMRS, SMC, HVC, CPS/CPSID/CPSIE, CLREX, DMB, DSB, ISB, PLD, SETEND, SRS/RFE, STC/LDC variants, and related intrinsics. Add integer, DSP, saturation, CRC, multiply, and packed arithmetic lifting, including CRC32 variants, QADD/QSUB forms, SSAT/USAT forms, SMMUL/SMMLA, SMLA/SMLAL variants, SXT/UXT variants, REV/RBIT/SEL, packed add/sub variants, UQASX/UQSAX, and Thumb writeback/control-transfer cases. Expand VFP/NEON support for vector moves, arithmetic, comparisons, conversions, shifts, narrowing/widening operations, structured loads/stores, table lookup, reductions, duplicate/reverse/ext operations, and fused multiply forms, wiring new intrinsics and metadata where needed. Extend ARM/Thumb decoder support where required, including CRC32 Thumb variants, and add focused ARM and Thumb lift tests for the new coverage. --- arch/armv7/arch_armv7.cpp | 987 +++++ arch/armv7/armv7_disasm/armv7.c | 35 + arch/armv7/armv7_disasm/armv7.h | 6 + arch/armv7/il.cpp | 4084 +++++++++++++-------- arch/armv7/il.h | 116 + arch/armv7/test_lift.py | 637 +++- arch/armv7/thumb2_disasm/arch_thumb2.cpp | 843 +++++ arch/armv7/thumb2_disasm/disassembler.cpp | 105 +- arch/armv7/thumb2_disasm/il_thumb2.cpp | 3470 ++++++++++++++++- 9 files changed, 8623 insertions(+), 1660 deletions(-) diff --git a/arch/armv7/arch_armv7.cpp b/arch/armv7/arch_armv7.cpp index 9f7831a24c..eb325e66b1 100644 --- a/arch/armv7/arch_armv7.cpp +++ b/arch/armv7/arch_armv7.cpp @@ -30,6 +30,90 @@ using namespace std; #define HANDLE_CASE(orig, opposite) case orig: case opposite: return (candidate == orig) || (candidate == opposite) +static Ref GetMrsOpEnum() +{ + EnumerationBuilder builder; + builder.AddMemberWithValue("apsr", REGS_APSR); + builder.AddMemberWithValue("cpsr", REGS_CPSR); + builder.AddMemberWithValue("spsr", REGS_SPSR); + Ref _enum = builder.Finalize(); + return _enum; +} + +static Ref GetMsrOpEnum() +{ + EnumerationBuilder builder; + builder.AddMemberWithValue("apsr", REGS_APSR); + builder.AddMemberWithValue("apsr_g", REGS_APSR_G); + builder.AddMemberWithValue("apsr_nzcvq", REGS_APSR_NZCVQ); + builder.AddMemberWithValue("apsr_nzcvqg", REGS_APSR_NZCVQG); + builder.AddMemberWithValue("cpsr", REGS_CPSR); + builder.AddMemberWithValue("cpsr_c", REGS_CPSR_C); + builder.AddMemberWithValue("cpsr_x", REGS_CPSR_X); + builder.AddMemberWithValue("cpsr_xc", REGS_CPSR_XC); + builder.AddMemberWithValue("cpsr_s", REGS_CPSR_S); + builder.AddMemberWithValue("cpsr_sc", REGS_CPSR_SC); + builder.AddMemberWithValue("cpsr_sx", REGS_CPSR_SX); + builder.AddMemberWithValue("cpsr_sxc", REGS_CPSR_SXC); + builder.AddMemberWithValue("cpsr_f", REGS_CPSR_F); + builder.AddMemberWithValue("cpsr_fc", REGS_CPSR_FC); + builder.AddMemberWithValue("cpsr_fx", REGS_CPSR_FX); + builder.AddMemberWithValue("cpsr_fxc", REGS_CPSR_FXC); + builder.AddMemberWithValue("cpsr_fs", REGS_CPSR_FS); + builder.AddMemberWithValue("cpsr_fsc", REGS_CPSR_FSC); + builder.AddMemberWithValue("cpsr_fsx", REGS_CPSR_FSX); + builder.AddMemberWithValue("cpsr_fsxc", REGS_CPSR_FSXC); + builder.AddMemberWithValue("spsr", REGS_SPSR); + builder.AddMemberWithValue("spsr_c", REGS_SPSR_C); + builder.AddMemberWithValue("spsr_x", REGS_SPSR_X); + builder.AddMemberWithValue("spsr_xc", REGS_SPSR_XC); + builder.AddMemberWithValue("spsr_s", REGS_SPSR_S); + builder.AddMemberWithValue("spsr_sc", REGS_SPSR_SC); + builder.AddMemberWithValue("spsr_sx", REGS_SPSR_SX); + builder.AddMemberWithValue("spsr_sxc", REGS_SPSR_SXC); + builder.AddMemberWithValue("spsr_f", REGS_SPSR_F); + builder.AddMemberWithValue("spsr_fc", REGS_SPSR_FC); + builder.AddMemberWithValue("spsr_fx", REGS_SPSR_FX); + builder.AddMemberWithValue("spsr_fxc", REGS_SPSR_FXC); + builder.AddMemberWithValue("spsr_fs", REGS_SPSR_FS); + builder.AddMemberWithValue("spsr_fsc", REGS_SPSR_FSC); + builder.AddMemberWithValue("spsr_fsx", REGS_SPSR_FSX); + builder.AddMemberWithValue("spsr_fsxc", REGS_SPSR_FSXC); + builder.AddMemberWithValue("apsr_nzcv", REGS_APSR_NZCV); + Ref _enum = builder.Finalize(); + return _enum; +} + +static Ref GetVfpStatusRegisterEnum() +{ + EnumerationBuilder builder; + builder.AddMemberWithValue("fpsid", REGS_FPSID); + builder.AddMemberWithValue("fpscr", REGS_FPSCR); + builder.AddMemberWithValue("mvfr2", REGS_MVFR2); + builder.AddMemberWithValue("mvfr1", REGS_MVFR1); + builder.AddMemberWithValue("mvfr0", REGS_MVFR0); + builder.AddMemberWithValue("fpexc", REGS_FPEXC); + builder.AddMemberWithValue("fpinst", REGS_FPINST); + builder.AddMemberWithValue("fpinst2", REGS_FPINST2); + Ref _enum = builder.Finalize(); + return _enum; +} + +static Ref GetCpsIflagsEnum() +{ + EnumerationBuilder builder; + builder.AddMemberWithValue("none", IFL_NONE); + builder.AddMemberWithValue("a", IFL_A); + builder.AddMemberWithValue("i", IFL_I); + builder.AddMemberWithValue("ia", IFL_IA); + builder.AddMemberWithValue("f", IFL_F); + builder.AddMemberWithValue("fa", IFL_FA); + builder.AddMemberWithValue("fi", IFL_FI); + builder.AddMemberWithValue("fia", IFL_FIA); + Ref _enum = builder.Finalize(); + return _enum; +} + static bool IsRelatedCondition(Condition orig, Condition candidate) { switch (orig) @@ -1407,10 +1491,288 @@ class Armv7Architecture: public ArmCommonArchitecture return "Coproc_SendOneWord"; case ARMV7_INTRIN_COPROC_SENDTWOWORDS: return "Coproc_SendTwoWords"; + case ARMV7_INTRIN_COPROC_STORE: + return "Coproc_Store"; + case ARMV7_INTRIN_COPROC_LOAD: + return "Coproc_Load"; + case ARMV7_INTRIN_COPROC_DATAPROCESSING: + return "Coproc_DataProcessing"; case ARMV7_INTRIN_EXCLUSIVE_MONITORS_PASS: return "ExclusiveMonitorsPass"; case ARMV7_INTRIN_SET_EXCLUSIVE_MONITORS: return "SetExclusiveMonitors"; + case ARMV7_INTRIN_DBG: + return "__dbg"; + case ARMV7_INTRIN_DMB_SY: + return "__dmb_SY"; + case ARMV7_INTRIN_DMB_ST: + return "__dmb_ST"; + case ARMV7_INTRIN_DMB_ISH: + return "__dmb_ISH"; + case ARMV7_INTRIN_DMB_ISHST: + return "__dmb_ISHST"; + case ARMV7_INTRIN_DMB_NSH: + return "__dmb_NSH"; + case ARMV7_INTRIN_DMB_NSHST: + return "__dmb_NSHST"; + case ARMV7_INTRIN_DMB_OSH: + return "__dmb_OSH"; + case ARMV7_INTRIN_DMB_OSHST: + return "__dmb_OSHST"; + case ARMV7_INTRIN_DSB_SY: + return "__dsb_SY"; + case ARMV7_INTRIN_DSB_ST: + return "__dsb_ST"; + case ARMV7_INTRIN_DSB_ISH: + return "__dsb_ISH"; + case ARMV7_INTRIN_DSB_ISHST: + return "__dsb_ISHST"; + case ARMV7_INTRIN_DSB_NSH: + return "__dsb_NSH"; + case ARMV7_INTRIN_DSB_NSHST: + return "__dsb_NSHST"; + case ARMV7_INTRIN_DSB_OSH: + return "__dsb_OSH"; + case ARMV7_INTRIN_DSB_OSHST: + return "__dsb_OSHST"; + case ARMV7_INTRIN_ISB: + return "__isb"; + case ARMV7_INTRIN_CPS: + return "__cps"; + case ARMV7_INTRIN_CPSID: + return "__cpsid"; + case ARMV7_INTRIN_CPSIE: + return "__cpsie"; + case ARMV7_INTRIN_SETEND: + return "__setend"; + case ARMV7_INTRIN_CLREX: + return "__clrex"; + case ARMV7_INTRIN_PLD: + return "__pld"; + case ARMV7_INTRIN_CRC32B: + return "__crc32b"; + case ARMV7_INTRIN_CRC32CB: + return "__crc32cb"; + case ARMV7_INTRIN_CRC32CH: + return "__crc32ch"; + case ARMV7_INTRIN_CRC32CW: + return "__crc32cw"; + case ARMV7_INTRIN_CRC32H: + return "__crc32h"; + case ARMV7_INTRIN_CRC32W: + return "__crc32w"; + case ARMV7_INTRIN_SEL: + return "__sel"; + case ARMV7_INTRIN_YIELD: + return "__yield"; + case ARMV7_INTRIN_SEV: + return "__sev"; + case ARMV7_INTRIN_WFE: + return "__wfe"; + case ARMV7_INTRIN_WFI: + return "__wfi"; + case ARMV7_INTRIN_HINT: + return "__hint"; + case ARMV7_INTRIN_UNPREDICTABLE: + return "__unpredictable"; + case ARMV7_INTRIN_HVC: + return "__hvc"; + case ARMV7_INTRIN_SMC: + return "__smc"; + case ARMV7_INTRIN_MRS: + return "__mrs"; + case ARMV7_INTRIN_MSR: + return "__msr"; + case ARMV7_INTRIN_VMRS: + return "__vmrs"; + case ARMV7_INTRIN_VMSR: + return "__vmsr"; + case ARMV7_INTRIN_VRINTA: + return "__vrinta"; + case ARMV7_INTRIN_VMAXNM: + return "__vmaxnm"; + case ARMV7_INTRIN_VMINNM: + return "__vminnm"; + case ARMV7_INTRIN_VMAX: + return "__vmax"; + case ARMV7_INTRIN_VMIN: + return "__vmin"; + case ARMV7_INTRIN_VPMAX: + return "__vpmax"; + case ARMV7_INTRIN_VPMIN: + return "__vpmin"; + case ARMV7_INTRIN_VREV16: + return "__vrev16"; + case ARMV7_INTRIN_VREV32: + return "__vrev32"; + case ARMV7_INTRIN_VREV64: + return "__vrev64"; + case ARMV7_INTRIN_VEXT: + return "__vext"; + case ARMV7_INTRIN_VCGT: + return "__vcgt"; + case ARMV7_INTRIN_VCEQ: + return "__vceq"; + case ARMV7_INTRIN_VTBL: + return "__vtbl"; + case ARMV7_INTRIN_VTBX: + return "__vtbx"; + case ARMV7_INTRIN_VDUP: + return "__vdup"; + case ARMV7_INTRIN_VABD: + return "__vabd"; + case ARMV7_INTRIN_VABDL: + return "__vabdl"; + case ARMV7_INTRIN_VABA: + return "__vaba"; + case ARMV7_INTRIN_VABAL: + return "__vabal"; + case ARMV7_INTRIN_VADDL: + return "__vaddl"; + case ARMV7_INTRIN_VADDW: + return "__vaddw"; + case ARMV7_INTRIN_VRADDHN: + return "__vraddhn"; + case ARMV7_INTRIN_VRSHR: + return "__vrshr"; + case ARMV7_INTRIN_VRSHL: + return "__vrshl"; + case ARMV7_INTRIN_VSRA: + return "__vsra"; + case ARMV7_INTRIN_VRSRA: + return "__vrsra"; + case ARMV7_INTRIN_VSRI: + return "__vsri"; + case ARMV7_INTRIN_VSLI: + return "__vsli"; + case ARMV7_INTRIN_VLD2: + return "__vld2"; + case ARMV7_INTRIN_VLD4: + return "__vld4"; + case ARMV7_INTRIN_VST2: + return "__vst2"; + case ARMV7_INTRIN_VST4: + return "__vst4"; + case ARMV7_INTRIN_VSHL: + return "__vshl"; + case ARMV7_INTRIN_VSHR: + return "__vshr"; + case ARMV7_INTRIN_VSHLL: + return "__vshll"; + case ARMV7_INTRIN_VBIF: + return "__vbif"; + case ARMV7_INTRIN_VBIT: + return "__vbit"; + case ARMV7_INTRIN_VBSL: + return "__vbsl"; + case ARMV7_INTRIN_VQADD: + return "__vqadd"; + case ARMV7_INTRIN_VHADD: + return "__vhadd"; + case ARMV7_INTRIN_VQSHL: + return "__vqshl"; + case ARMV7_INTRIN_VQRSHL: + return "__vqrshl"; + case ARMV7_INTRIN_VQSHRN: + return "__vqshrn"; + case ARMV7_INTRIN_VQSHRUN: + return "__vqshrun"; + case ARMV7_INTRIN_VQRSHRN: + return "__vqrshrn"; + case ARMV7_INTRIN_VQRSHRUN: + return "__vqrshrun"; + case ARMV7_INTRIN_VQMOVN: + return "__vqmovn"; + case ARMV7_INTRIN_VQMOVUN: + return "__vqmovun"; + case ARMV7_INTRIN_VMLA: + return "__vmla"; + case ARMV7_INTRIN_VMLS: + return "__vmls"; + case ARMV7_INTRIN_VMLAL: + return "__vmlal"; + case ARMV7_INTRIN_VMLSL: + return "__vmlsl"; + case ARMV7_INTRIN_VMUL: + return "__vmul"; + case ARMV7_INTRIN_VQDMULL: + return "__vqdmull"; + case ARMV7_INTRIN_SSAT: + return "__ssat"; + case ARMV7_INTRIN_SSAT16: + return "__ssat16"; + case ARMV7_INTRIN_USAT: + return "__usat"; + case ARMV7_INTRIN_USAT16: + return "__usat16"; + case ARMV7_INTRIN_SRS: + return "__srs"; + case ARMV7_INTRIN_RFE: + return "__rfe"; + case ARMV7_INTRIN_QADD: + return "__qadd"; + case ARMV7_INTRIN_QSUB: + return "__qsub"; + case ARMV7_INTRIN_QDADD: + return "__qdadd"; + case ARMV7_INTRIN_QDSUB: + return "__qdsub"; + case ARMV7_INTRIN_QADD16: + return "__qadd16"; + case ARMV7_INTRIN_QADD8: + return "__qadd8"; + case ARMV7_INTRIN_QSUB16: + return "__qsub16"; + case ARMV7_INTRIN_QSUB8: + return "__qsub8"; + case ARMV7_INTRIN_UQADD16: + return "__uqadd16"; + case ARMV7_INTRIN_UQADD8: + return "__uqadd8"; + case ARMV7_INTRIN_UQSUB16: + return "__uqsub16"; + case ARMV7_INTRIN_UQSUB8: + return "__uqsub8"; + case ARMV7_INTRIN_SXTAB16: + return "__sxtab16"; + case ARMV7_INTRIN_SXTB16: + return "__sxtb16"; + case ARMV7_INTRIN_UXTAB16: + return "__uxtab16"; + case ARMV7_INTRIN_UXTB16: + return "__uxtb16"; + case ARMV7_INTRIN_SADD16: + return "__sadd16"; + case ARMV7_INTRIN_SADD8: + return "__sadd8"; + case ARMV7_INTRIN_SHADD16: + return "__shadd16"; + case ARMV7_INTRIN_SHADD8: + return "__shadd8"; + case ARMV7_INTRIN_SSUB8: + return "__ssub8"; + case ARMV7_INTRIN_SHSUB8: + return "__shsub8"; + case ARMV7_INTRIN_SHSUB16: + return "__shsub16"; + case ARMV7_INTRIN_UHSUB8: + return "__uhsub8"; + case ARMV7_INTRIN_UHSUB16: + return "__uhsub16"; + case ARMV7_INTRIN_USUB8: + return "__usub8"; + case ARMV7_INTRIN_USUB16: + return "__usub16"; + case ARMV7_INTRIN_USAD8: + return "__usad8"; + case ARMV7_INTRIN_USADA8: + return "__usada8"; + case ARMV7_INTRIN_QSAX: + return "__qsax"; + case ARMV7_INTRIN_UQASX: + return "__uqasx"; + case ARMV7_INTRIN_UQSAX: + return "__uqsax"; default: return ""; } @@ -1423,8 +1785,147 @@ class Armv7Architecture: public ArmCommonArchitecture ARMV7_INTRIN_COPROC_GETTWOWORDS, ARMV7_INTRIN_COPROC_SENDONEWORD, ARMV7_INTRIN_COPROC_SENDTWOWORDS, + ARMV7_INTRIN_COPROC_STORE, + ARMV7_INTRIN_COPROC_LOAD, + ARMV7_INTRIN_COPROC_DATAPROCESSING, ARMV7_INTRIN_EXCLUSIVE_MONITORS_PASS, ARMV7_INTRIN_SET_EXCLUSIVE_MONITORS, + ARMV7_INTRIN_DBG, + ARMV7_INTRIN_DMB_SY, + ARMV7_INTRIN_DMB_ST, + ARMV7_INTRIN_DMB_ISH, + ARMV7_INTRIN_DMB_ISHST, + ARMV7_INTRIN_DMB_NSH, + ARMV7_INTRIN_DMB_NSHST, + ARMV7_INTRIN_DMB_OSH, + ARMV7_INTRIN_DMB_OSHST, + ARMV7_INTRIN_DSB_SY, + ARMV7_INTRIN_DSB_ST, + ARMV7_INTRIN_DSB_ISH, + ARMV7_INTRIN_DSB_ISHST, + ARMV7_INTRIN_DSB_NSH, + ARMV7_INTRIN_DSB_NSHST, + ARMV7_INTRIN_DSB_OSH, + ARMV7_INTRIN_DSB_OSHST, + ARMV7_INTRIN_ISB, + ARMV7_INTRIN_CPS, + ARMV7_INTRIN_CPSID, + ARMV7_INTRIN_CPSIE, + ARMV7_INTRIN_SETEND, + ARMV7_INTRIN_CLREX, + ARMV7_INTRIN_PLD, + ARMV7_INTRIN_CRC32B, + ARMV7_INTRIN_CRC32CB, + ARMV7_INTRIN_CRC32CH, + ARMV7_INTRIN_CRC32CW, + ARMV7_INTRIN_CRC32H, + ARMV7_INTRIN_CRC32W, + ARMV7_INTRIN_SEL, + ARMV7_INTRIN_YIELD, + ARMV7_INTRIN_SEV, + ARMV7_INTRIN_WFE, + ARMV7_INTRIN_WFI, + ARMV7_INTRIN_HINT, + ARMV7_INTRIN_UNPREDICTABLE, + ARMV7_INTRIN_HVC, + ARMV7_INTRIN_SMC, + ARMV7_INTRIN_MRS, + ARMV7_INTRIN_MSR, + ARMV7_INTRIN_VMRS, + ARMV7_INTRIN_VMSR, + ARMV7_INTRIN_VRINTA, + ARMV7_INTRIN_VMAXNM, + ARMV7_INTRIN_VMINNM, + ARMV7_INTRIN_VMAX, + ARMV7_INTRIN_VMIN, + ARMV7_INTRIN_VPMAX, + ARMV7_INTRIN_VPMIN, + ARMV7_INTRIN_VREV16, + ARMV7_INTRIN_VREV32, + ARMV7_INTRIN_VREV64, + ARMV7_INTRIN_VEXT, + ARMV7_INTRIN_VCGT, + ARMV7_INTRIN_VCEQ, + ARMV7_INTRIN_VTBL, + ARMV7_INTRIN_VTBX, + ARMV7_INTRIN_VDUP, + ARMV7_INTRIN_VABD, + ARMV7_INTRIN_VABDL, + ARMV7_INTRIN_VABA, + ARMV7_INTRIN_VABAL, + ARMV7_INTRIN_VADDL, + ARMV7_INTRIN_VADDW, + ARMV7_INTRIN_VRADDHN, + ARMV7_INTRIN_VRSHR, + ARMV7_INTRIN_VRSHL, + ARMV7_INTRIN_VSRA, + ARMV7_INTRIN_VRSRA, + ARMV7_INTRIN_VSRI, + ARMV7_INTRIN_VSLI, + ARMV7_INTRIN_VLD2, + ARMV7_INTRIN_VLD4, + ARMV7_INTRIN_VST2, + ARMV7_INTRIN_VST4, + ARMV7_INTRIN_VSHL, + ARMV7_INTRIN_VSHR, + ARMV7_INTRIN_VSHLL, + ARMV7_INTRIN_VBIF, + ARMV7_INTRIN_VBIT, + ARMV7_INTRIN_VBSL, + ARMV7_INTRIN_VQADD, + ARMV7_INTRIN_VHADD, + ARMV7_INTRIN_VQSHL, + ARMV7_INTRIN_VQRSHL, + ARMV7_INTRIN_VQSHRN, + ARMV7_INTRIN_VQSHRUN, + ARMV7_INTRIN_VQRSHRN, + ARMV7_INTRIN_VQRSHRUN, + ARMV7_INTRIN_VQMOVN, + ARMV7_INTRIN_VQMOVUN, + ARMV7_INTRIN_VMLA, + ARMV7_INTRIN_VMLS, + ARMV7_INTRIN_VMLAL, + ARMV7_INTRIN_VMLSL, + ARMV7_INTRIN_VMUL, + ARMV7_INTRIN_VQDMULL, + ARMV7_INTRIN_SSAT, + ARMV7_INTRIN_SSAT16, + ARMV7_INTRIN_USAT, + ARMV7_INTRIN_USAT16, + ARMV7_INTRIN_SRS, + ARMV7_INTRIN_RFE, + ARMV7_INTRIN_QADD, + ARMV7_INTRIN_QSUB, + ARMV7_INTRIN_QDADD, + ARMV7_INTRIN_QDSUB, + ARMV7_INTRIN_QADD16, + ARMV7_INTRIN_QADD8, + ARMV7_INTRIN_QSUB16, + ARMV7_INTRIN_QSUB8, + ARMV7_INTRIN_UQADD16, + ARMV7_INTRIN_UQADD8, + ARMV7_INTRIN_UQSUB16, + ARMV7_INTRIN_UQSUB8, + ARMV7_INTRIN_SXTAB16, + ARMV7_INTRIN_SXTB16, + ARMV7_INTRIN_UXTAB16, + ARMV7_INTRIN_UXTB16, + ARMV7_INTRIN_SADD16, + ARMV7_INTRIN_SADD8, + ARMV7_INTRIN_SHADD16, + ARMV7_INTRIN_SHADD8, + ARMV7_INTRIN_SSUB8, + ARMV7_INTRIN_SHSUB8, + ARMV7_INTRIN_SHSUB16, + ARMV7_INTRIN_UHSUB8, + ARMV7_INTRIN_UHSUB16, + ARMV7_INTRIN_USUB8, + ARMV7_INTRIN_USUB16, + ARMV7_INTRIN_USAD8, + ARMV7_INTRIN_USADA8, + ARMV7_INTRIN_QSAX, + ARMV7_INTRIN_UQASX, + ARMV7_INTRIN_UQSAX, }; } @@ -1463,12 +1964,395 @@ class Armv7Architecture: public ArmCommonArchitecture NameAndType(Type::IntegerType(1, false)), NameAndType("m", Type::IntegerType(1, false)), }; + case ARMV7_INTRIN_COPROC_STORE: + case ARMV7_INTRIN_COPROC_LOAD: + return { + NameAndType("address", Type::PointerType(4, Confidence(Type::VoidType(), 0), Confidence(false), Confidence(false), PointerReferenceType)), + NameAndType("cp", Type::IntegerType(1, false)), + NameAndType("d", Type::IntegerType(1, false)), + NameAndType("long_transfer", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_COPROC_DATAPROCESSING: + return { + NameAndType("cp", Type::IntegerType(1, false)), + NameAndType("opc1", Type::IntegerType(1, false)), + NameAndType("d", Type::IntegerType(1, false)), + NameAndType("n", Type::IntegerType(1, false)), + NameAndType("m", Type::IntegerType(1, false)), + NameAndType("opc2", Type::IntegerType(1, false)), + }; case ARMV7_INTRIN_EXCLUSIVE_MONITORS_PASS: case ARMV7_INTRIN_SET_EXCLUSIVE_MONITORS: return { NameAndType("address", Type::PointerType(4, Confidence(Type::VoidType(), 0), Confidence(false), Confidence(false), PointerReferenceType)), NameAndType("size", Type::IntegerType(1, false)), }; + case ARMV7_INTRIN_SMC: + return { + NameAndType("imm", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_HVC: + return { + NameAndType("imm", Type::IntegerType(2, false)), + }; + case ARMV7_INTRIN_DBG: + return { + NameAndType("option", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_HINT: + return { + NameAndType("imm", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_PLD: + return { + NameAndType("address", Type::PointerType(4, Confidence(Type::VoidType(), 0), Confidence(false), Confidence(false), PointerReferenceType)), + }; + case ARMV7_INTRIN_CRC32B: + case ARMV7_INTRIN_CRC32CB: + return { + NameAndType("accumulator", Type::IntegerType(4, false)), + NameAndType("value", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_CRC32H: + case ARMV7_INTRIN_CRC32CH: + return { + NameAndType("accumulator", Type::IntegerType(4, false)), + NameAndType("value", Type::IntegerType(2, false)), + }; + case ARMV7_INTRIN_CRC32W: + case ARMV7_INTRIN_CRC32CW: + return { + NameAndType("accumulator", Type::IntegerType(4, false)), + NameAndType("value", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_SEL: + return { + NameAndType("rn", Type::IntegerType(4, false)), + NameAndType("rm", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_QADD: + case ARMV7_INTRIN_QSUB: + case ARMV7_INTRIN_QDADD: + case ARMV7_INTRIN_QDSUB: + case ARMV7_INTRIN_QADD16: + case ARMV7_INTRIN_QADD8: + case ARMV7_INTRIN_QSUB16: + case ARMV7_INTRIN_QSUB8: + case ARMV7_INTRIN_UQADD16: + case ARMV7_INTRIN_UQADD8: + case ARMV7_INTRIN_UQSUB16: + case ARMV7_INTRIN_UQSUB8: + case ARMV7_INTRIN_QSAX: + case ARMV7_INTRIN_UQASX: + case ARMV7_INTRIN_UQSAX: + case ARMV7_INTRIN_SXTAB16: + case ARMV7_INTRIN_UXTAB16: + case ARMV7_INTRIN_SADD16: + case ARMV7_INTRIN_SADD8: + case ARMV7_INTRIN_SHADD16: + case ARMV7_INTRIN_SHADD8: + case ARMV7_INTRIN_SSUB8: + case ARMV7_INTRIN_SHSUB8: + case ARMV7_INTRIN_SHSUB16: + case ARMV7_INTRIN_UHSUB8: + case ARMV7_INTRIN_UHSUB16: + case ARMV7_INTRIN_USUB8: + case ARMV7_INTRIN_USUB16: + case ARMV7_INTRIN_USAD8: + return { + NameAndType("source1", Type::IntegerType(4, false)), + NameAndType("source2", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_SXTB16: + case ARMV7_INTRIN_UXTB16: + return { + NameAndType("source", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_USADA8: + return { + NameAndType("source1", Type::IntegerType(4, false)), + NameAndType("source2", Type::IntegerType(4, false)), + NameAndType("accumulator", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_CPS: + return { + NameAndType("mode", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_SETEND: + return { + NameAndType("endian", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_CPSID: + case ARMV7_INTRIN_CPSIE: + return { + NameAndType("iflags", Confidence>(Type::EnumerationType(this, GetCpsIflagsEnum(), 1, false), BN_FULL_CONFIDENCE)), + NameAndType("mode", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_MRS: + return { + NameAndType("status_register", Confidence>(Type::EnumerationType(this, GetMrsOpEnum(), 4, false), BN_FULL_CONFIDENCE)), + }; + case ARMV7_INTRIN_MSR: + return { + NameAndType("status_register", Confidence>(Type::EnumerationType(this, GetMsrOpEnum(), 4, false), BN_FULL_CONFIDENCE)), + NameAndType("source_register", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_VMRS: + return { + NameAndType("status_register", Confidence>(Type::EnumerationType(this, GetVfpStatusRegisterEnum(), 4, false), BN_FULL_CONFIDENCE)), + }; + case ARMV7_INTRIN_VMSR: + return { + NameAndType("status_register", Confidence>(Type::EnumerationType(this, GetVfpStatusRegisterEnum(), 4, false), BN_FULL_CONFIDENCE)), + NameAndType("source_register", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_VRINTA: + return { + NameAndType("source_register", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_VMAXNM: + case ARMV7_INTRIN_VMINNM: + return { + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VMAX: + case ARMV7_INTRIN_VMIN: + case ARMV7_INTRIN_VPMAX: + case ARMV7_INTRIN_VPMIN: + case ARMV7_INTRIN_VCGT: + case ARMV7_INTRIN_VHADD: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VCEQ: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_float", Type::BoolType()), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VREV16: + case ARMV7_INTRIN_VREV32: + case ARMV7_INTRIN_VREV64: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("source", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VEXT: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + NameAndType("index", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_SSAT: + case ARMV7_INTRIN_SSAT16: + case ARMV7_INTRIN_USAT: + case ARMV7_INTRIN_USAT16: + return { + NameAndType("saturate_to", Type::IntegerType(4, false)), + NameAndType("source", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_VTBL: + return { + NameAndType("length", Type::IntegerType(1, false)), + NameAndType("table0", Type::IntegerType(8, false)), + NameAndType("table1", Type::IntegerType(8, false)), + NameAndType("table2", Type::IntegerType(8, false)), + NameAndType("table3", Type::IntegerType(8, false)), + NameAndType("indices", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VTBX: + return { + NameAndType("length", Type::IntegerType(1, false)), + NameAndType("table0", Type::IntegerType(8, false)), + NameAndType("table1", Type::IntegerType(8, false)), + NameAndType("table2", Type::IntegerType(8, false)), + NameAndType("table3", Type::IntegerType(8, false)), + NameAndType("indices", Type::IntegerType(8, false)), + NameAndType("destination", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VDUP: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("source", Type::IntegerType(8, false)), + NameAndType("index", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_VABD: + case ARMV7_INTRIN_VABDL: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VABA: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("accumulator", Type::IntegerType(16, false)), + NameAndType("source1", Type::IntegerType(16, false)), + NameAndType("source2", Type::IntegerType(16, false)), + }; + case ARMV7_INTRIN_VABAL: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("accumulator", Type::IntegerType(16, false)), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VADDL: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VADDW: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("source1", Type::IntegerType(16, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VRADDHN: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("source1", Type::IntegerType(16, false)), + NameAndType("source2", Type::IntegerType(16, false)), + }; + case ARMV7_INTRIN_VRSHR: + case ARMV7_INTRIN_VRSHL: + case ARMV7_INTRIN_VSHL: + case ARMV7_INTRIN_VSHR: + case ARMV7_INTRIN_VSHLL: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("source", Type::IntegerType(8, false)), + NameAndType("shift", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VBIF: + case ARMV7_INTRIN_VBIT: + case ARMV7_INTRIN_VBSL: + return { + NameAndType("destination", Type::IntegerType(8, false)), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VSRA: + case ARMV7_INTRIN_VRSRA: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("accumulator", Type::IntegerType(8, false)), + NameAndType("source", Type::IntegerType(8, false)), + NameAndType("shift", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VSRI: + case ARMV7_INTRIN_VSLI: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("destination", Type::IntegerType(8, false)), + NameAndType("source", Type::IntegerType(8, false)), + NameAndType("shift", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VLD2: + case ARMV7_INTRIN_VLD4: + return { + NameAndType("address", Type::PointerType(4, Confidence(Type::VoidType(), 0), Confidence(false), Confidence(false), PointerReferenceType)), + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("alignment", Type::IntegerType(1, false)), + NameAndType("index", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_VST2: + case ARMV7_INTRIN_VST4: + return { + NameAndType("address", Type::PointerType(4, Confidence(Type::VoidType(), 0), Confidence(false), Confidence(false), PointerReferenceType)), + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("alignment", Type::IntegerType(1, false)), + NameAndType("index", Type::IntegerType(1, false)), + NameAndType("source0", Type::IntegerType(8, false)), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + NameAndType("source3", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VQADD: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VQSHL: + case ARMV7_INTRIN_VQRSHL: + case ARMV7_INTRIN_VQSHRN: + case ARMV7_INTRIN_VQSHRUN: + case ARMV7_INTRIN_VQRSHRN: + case ARMV7_INTRIN_VQRSHRUN: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("source_unsigned", Type::BoolType()), + NameAndType("destination_unsigned", Type::BoolType()), + NameAndType("source", Type::IntegerType( + (intrinsic == ARMV7_INTRIN_VQSHL || intrinsic == ARMV7_INTRIN_VQRSHL) ? 8 : 16, false)), + NameAndType("shift", Type::IntegerType( + (intrinsic == ARMV7_INTRIN_VQSHL || intrinsic == ARMV7_INTRIN_VQRSHL) ? 8 : 16, false)), + }; + case ARMV7_INTRIN_VQMOVN: + case ARMV7_INTRIN_VQMOVUN: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("source_unsigned", Type::BoolType()), + NameAndType("destination_unsigned", Type::BoolType()), + NameAndType("source", Type::IntegerType(16, false)), + }; + case ARMV7_INTRIN_VMLA: + case ARMV7_INTRIN_VMLS: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("accumulator", Type::IntegerType(8, false)), + NameAndType("source", Type::IntegerType(8, false)), + NameAndType("scalar", Type::IntegerType(8, false)), + NameAndType("index", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_VMLAL: + case ARMV7_INTRIN_VMLSL: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("accumulator", Type::IntegerType(16, false)), + NameAndType("source", Type::IntegerType(8, false)), + NameAndType("scalar", Type::IntegerType(8, false)), + NameAndType("index", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_VMUL: + case ARMV7_INTRIN_VQDMULL: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_SRS: + return { + NameAndType("mode", Type::IntegerType(1, false)), + NameAndType("increment", Type::BoolType()), + NameAndType("wordhigher", Type::BoolType()), + NameAndType("writeback", Type::BoolType()), + }; + case ARMV7_INTRIN_RFE: + return { + NameAndType("base_register", Type::IntegerType(4, false)), + NameAndType("increment", Type::BoolType()), + NameAndType("wordhigher", Type::BoolType()), + NameAndType("writeback", Type::BoolType()), + }; default: return vector(); } @@ -1484,6 +2368,109 @@ class Armv7Architecture: public ArmCommonArchitecture return { Type::IntegerType(4, false), Type::IntegerType(4, false) }; case ARMV7_INTRIN_EXCLUSIVE_MONITORS_PASS: return { Type::BoolType() }; + case ARMV7_INTRIN_MRS: + case ARMV7_INTRIN_VMRS: + case ARMV7_INTRIN_SEL: + case ARMV7_INTRIN_QADD: + case ARMV7_INTRIN_QSUB: + case ARMV7_INTRIN_QDADD: + case ARMV7_INTRIN_QDSUB: + case ARMV7_INTRIN_QADD16: + case ARMV7_INTRIN_QADD8: + case ARMV7_INTRIN_QSUB16: + case ARMV7_INTRIN_QSUB8: + case ARMV7_INTRIN_UQADD16: + case ARMV7_INTRIN_UQADD8: + case ARMV7_INTRIN_UQSUB16: + case ARMV7_INTRIN_UQSUB8: + case ARMV7_INTRIN_QSAX: + case ARMV7_INTRIN_UQASX: + case ARMV7_INTRIN_SXTAB16: + case ARMV7_INTRIN_SXTB16: + case ARMV7_INTRIN_UXTAB16: + case ARMV7_INTRIN_UXTB16: + case ARMV7_INTRIN_SADD16: + case ARMV7_INTRIN_SADD8: + case ARMV7_INTRIN_SHADD16: + case ARMV7_INTRIN_SHADD8: + case ARMV7_INTRIN_SSUB8: + case ARMV7_INTRIN_SHSUB8: + case ARMV7_INTRIN_SHSUB16: + case ARMV7_INTRIN_UHSUB8: + case ARMV7_INTRIN_UHSUB16: + case ARMV7_INTRIN_USUB8: + case ARMV7_INTRIN_USUB16: + case ARMV7_INTRIN_USAD8: + case ARMV7_INTRIN_USADA8: + case ARMV7_INTRIN_UQSAX: + case ARMV7_INTRIN_VRINTA: + case ARMV7_INTRIN_VMAXNM: + case ARMV7_INTRIN_VMINNM: + case ARMV7_INTRIN_SSAT: + case ARMV7_INTRIN_SSAT16: + case ARMV7_INTRIN_USAT: + case ARMV7_INTRIN_USAT16: + case ARMV7_INTRIN_CRC32B: + case ARMV7_INTRIN_CRC32CB: + case ARMV7_INTRIN_CRC32CH: + case ARMV7_INTRIN_CRC32CW: + case ARMV7_INTRIN_CRC32H: + case ARMV7_INTRIN_CRC32W: + return { Type::IntegerType(4, false) }; + case ARMV7_INTRIN_VLD2: + return { Type::IntegerType(8, false), Type::IntegerType(8, false) }; + case ARMV7_INTRIN_VLD4: + return { Type::IntegerType(8, false), Type::IntegerType(8, false), Type::IntegerType(8, false), Type::IntegerType(8, false) }; + case ARMV7_INTRIN_VTBL: + case ARMV7_INTRIN_VTBX: + case ARMV7_INTRIN_VDUP: + case ARMV7_INTRIN_VABD: + case ARMV7_INTRIN_VABA: + case ARMV7_INTRIN_VRSHR: + case ARMV7_INTRIN_VRSHL: + case ARMV7_INTRIN_VSRA: + case ARMV7_INTRIN_VRSRA: + case ARMV7_INTRIN_VSRI: + case ARMV7_INTRIN_VSLI: + case ARMV7_INTRIN_VRADDHN: + case ARMV7_INTRIN_VSHL: + case ARMV7_INTRIN_VSHR: + case ARMV7_INTRIN_VMAX: + case ARMV7_INTRIN_VMIN: + case ARMV7_INTRIN_VPMAX: + case ARMV7_INTRIN_VPMIN: + case ARMV7_INTRIN_VREV16: + case ARMV7_INTRIN_VREV32: + case ARMV7_INTRIN_VREV64: + case ARMV7_INTRIN_VEXT: + case ARMV7_INTRIN_VCGT: + case ARMV7_INTRIN_VCEQ: + case ARMV7_INTRIN_VQADD: + case ARMV7_INTRIN_VHADD: + case ARMV7_INTRIN_VQSHL: + case ARMV7_INTRIN_VQRSHL: + case ARMV7_INTRIN_VQSHRN: + case ARMV7_INTRIN_VQSHRUN: + case ARMV7_INTRIN_VQRSHRN: + case ARMV7_INTRIN_VQRSHRUN: + case ARMV7_INTRIN_VQMOVN: + case ARMV7_INTRIN_VQMOVUN: + case ARMV7_INTRIN_VMLA: + case ARMV7_INTRIN_VMLS: + case ARMV7_INTRIN_VMUL: + case ARMV7_INTRIN_VBIF: + case ARMV7_INTRIN_VBIT: + case ARMV7_INTRIN_VBSL: + return { Type::IntegerType(8, false) }; + case ARMV7_INTRIN_VABAL: + case ARMV7_INTRIN_VABDL: + case ARMV7_INTRIN_VADDL: + case ARMV7_INTRIN_VADDW: + case ARMV7_INTRIN_VSHLL: + case ARMV7_INTRIN_VMLAL: + case ARMV7_INTRIN_VMLSL: + case ARMV7_INTRIN_VQDMULL: + return { Type::IntegerType(16, false) }; default: return vector>>(); } diff --git a/arch/armv7/armv7_disasm/armv7.c b/arch/armv7/armv7_disasm/armv7.c index 2a5e5c6f40..f235ec30b4 100644 --- a/arch/armv7/armv7_disasm/armv7.c +++ b/arch/armv7/armv7_disasm/armv7.c @@ -48,6 +48,32 @@ static Register regMap[2] = {REG_D0, REG_Q0}; #define SET_REGISTER(x) (1<<((x))) #define DECODE_DT(s,u) (enum DataType)(1+((((u&1))<<2) | ((s)&3))) +static uint32_t armv7_crc32(uint32_t instructionValue, Instruction* restrict instruction) +{ + if ((instructionValue & 0x0f900df0) != 0x01000040) + return 1; + + uint32_t size = (instructionValue >> 21) & 3; + uint32_t castagnoli = (instructionValue >> 9) & 1; + if (size == 3) + return 1; + + static Operation crc32Operation[2][3] = { + { ARMV7_CRC32B, ARMV7_CRC32H, ARMV7_CRC32W }, + { ARMV7_CRC32CB, ARMV7_CRC32CH, ARMV7_CRC32CW }, + }; + + instruction->operation = crc32Operation[castagnoli][size]; + instruction->cond = (enum Condition)(instructionValue >> 28); + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (enum Register)((instructionValue >> 12) & 0xf); + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (enum Register)((instructionValue >> 16) & 0xf); + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (enum Register)(instructionValue & 0xf); + return 0; +} + static const char* operationString[] = { "UNDEFINED", "UNPREDICTABLE", @@ -77,6 +103,12 @@ static const char* operationString[] = { "cdp2", "clrex", "clz", + "crc32b", + "crc32cb", + "crc32ch", + "crc32cw", + "crc32h", + "crc32w", "cmn", "cmp", "cps", @@ -1081,6 +1113,9 @@ uint32_t armv7_data_processing_and_misc(uint32_t instructionValue, Instruction* } decode; decode.value = instructionValue; + if (armv7_crc32(instructionValue, instruction) == 0) + return 0; + if (decode.op == 0) { if ((decode.op1 & 0x19) == 0x10) //10xx0 diff --git a/arch/armv7/armv7_disasm/armv7.h b/arch/armv7/armv7_disasm/armv7.h index 14ff191a3c..923b1d7e4e 100644 --- a/arch/armv7/armv7_disasm/armv7.h +++ b/arch/armv7/armv7_disasm/armv7.h @@ -55,6 +55,12 @@ enum Operation { ARMV7_CDP2, ARMV7_CLREX, ARMV7_CLZ, + ARMV7_CRC32B, + ARMV7_CRC32CB, + ARMV7_CRC32CH, + ARMV7_CRC32CW, + ARMV7_CRC32H, + ARMV7_CRC32W, ARMV7_CMN, ARMV7_CMP, ARMV7_CPS, diff --git a/arch/armv7/il.cpp b/arch/armv7/il.cpp index a999cb6079..69cc3a0295 100644 --- a/arch/armv7/il.cpp +++ b/arch/armv7/il.cpp @@ -124,6 +124,885 @@ static void ConditionExecute(LowLevelILFunction& il, Condition cond, ExprId true il.MarkLabel(falseCode); } +static uint32_t GetDmbIntrinsic(DsbOption option) +{ + switch (option) + { + case DSB_SY: + return ARMV7_INTRIN_DMB_SY; + case DSB_ST: + return ARMV7_INTRIN_DMB_ST; + case DSB_ISH: + return ARMV7_INTRIN_DMB_ISH; + case DSB_ISHST: + return ARMV7_INTRIN_DMB_ISHST; + case DSB_NSH: + return ARMV7_INTRIN_DMB_NSH; + case DSB_NSHST: + return ARMV7_INTRIN_DMB_NSHST; + case DSB_OSH: + return ARMV7_INTRIN_DMB_OSH; + case DSB_OSHST: + return ARMV7_INTRIN_DMB_OSHST; + default: + return 0; + } +} + +static uint32_t GetDsbIntrinsic(DsbOption option) +{ + switch (option) + { + case DSB_SY: + return ARMV7_INTRIN_DSB_SY; + case DSB_ST: + return ARMV7_INTRIN_DSB_ST; + case DSB_ISH: + return ARMV7_INTRIN_DSB_ISH; + case DSB_ISHST: + return ARMV7_INTRIN_DSB_ISHST; + case DSB_NSH: + return ARMV7_INTRIN_DSB_NSH; + case DSB_NSHST: + return ARMV7_INTRIN_DSB_NSHST; + case DSB_OSH: + return ARMV7_INTRIN_DSB_OSH; + case DSB_OSHST: + return ARMV7_INTRIN_DSB_OSHST; + default: + return 0; + } +} + +static uint32_t GetCrc32Intrinsic(Operation operation) +{ + switch (operation) + { + case ARMV7_CRC32B: + return ARMV7_INTRIN_CRC32B; + case ARMV7_CRC32CB: + return ARMV7_INTRIN_CRC32CB; + case ARMV7_CRC32CH: + return ARMV7_INTRIN_CRC32CH; + case ARMV7_CRC32CW: + return ARMV7_INTRIN_CRC32CW; + case ARMV7_CRC32H: + return ARMV7_INTRIN_CRC32H; + case ARMV7_CRC32W: + return ARMV7_INTRIN_CRC32W; + default: + return 0; + } +} + +static size_t GetCrc32ValueSize(Operation operation) +{ + switch (operation) + { + case ARMV7_CRC32B: + case ARMV7_CRC32CB: + return 1; + case ARMV7_CRC32H: + case ARMV7_CRC32CH: + return 2; + case ARMV7_CRC32W: + case ARMV7_CRC32CW: + return 4; + default: + return 0; + } +} + +static size_t GetDataTypeSize(DataType dataType) +{ + switch (dataType) + { + case DT_8: + case DT_S8: + case DT_U8: + case DT_I8: + case DT_P8: + return 1; + case DT_16: + case DT_S16: + case DT_U16: + case DT_I16: + case DT_F16: + case DT_P16: + return 2; + case DT_32: + case DT_S32: + case DT_U32: + case DT_I32: + case DT_F32: + case DT_P32: + return 4; + case DT_64: + case DT_S64: + case DT_U64: + case DT_I64: + case DT_F64: + case DT_P64: + return 8; + default: + return 0; + } +} + +static bool IsSignedDataType(DataType dataType) +{ + switch (dataType) + { + case DT_S8: + case DT_S16: + case DT_S32: + case DT_S64: + case DT_I8: + case DT_I16: + case DT_I32: + case DT_I64: + return true; + default: + return false; + } +} + +static bool IsUnsignedDataType(DataType dataType) +{ + switch (dataType) + { + case DT_U8: + case DT_U16: + case DT_U32: + case DT_U64: + return true; + default: + return false; + } +} + +static ExprId ReadVectorElement(LowLevelILFunction& il, InstructionOperand& op, size_t elementSize, size_t outputSize, bool isSigned) +{ + size_t regSize = get_register_size(op.reg); + size_t shift = op.imm * elementSize * 8; + ExprId value = il.Register(regSize, op.reg); + if (shift != 0) + value = il.LogicalShiftRight(regSize, value, il.Const(1, shift)); + value = il.LowPart(elementSize, value); + if (outputSize > elementSize) + return isSigned ? il.SignExtend(outputSize, value) : il.ZeroExtend(outputSize, value); + return value; +} + +static ExprId ReadVectorElement(LowLevelILFunction& il, Register reg, size_t elementSize, size_t index) +{ + size_t regSize = get_register_size(reg); + size_t shift = index * elementSize * 8; + ExprId value = il.Register(regSize, reg); + if (shift != 0) + value = il.LogicalShiftRight(regSize, value, il.Const(1, shift)); + return il.LowPart(elementSize, value); +} + +static ExprId InsertVectorElement(LowLevelILFunction& il, InstructionOperand& dst, ExprId src, size_t elementSize) +{ + size_t regSize = get_register_size(dst.reg); + size_t shift = dst.imm * elementSize * 8; + size_t elementBits = elementSize * 8; + uint64_t elementMask = (elementBits == 64) ? UINT64_MAX : ((1ULL << elementBits) - 1); + uint64_t shiftedMask = elementMask << shift; + + ExprId value = il.LowPart(elementSize, src); + if (regSize > elementSize) + value = il.ZeroExtend(regSize, value); + if (shift != 0) + value = il.ShiftLeft(regSize, value, il.Const(1, shift)); + + return il.Or(regSize, + il.And(regSize, il.Register(regSize, dst.reg), il.Const(regSize, ~shiftedMask)), + value); +} + +static ExprId InsertVectorElement(LowLevelILFunction& il, Register reg, ExprId src, size_t elementSize, size_t index) +{ + size_t regSize = get_register_size(reg); + size_t shift = index * elementSize * 8; + size_t elementBits = elementSize * 8; + uint64_t elementMask = (elementBits == 64) ? UINT64_MAX : ((1ULL << elementBits) - 1); + uint64_t shiftedMask = elementMask << shift; + + ExprId value = src; + if (regSize > elementSize) + value = il.ZeroExtend(regSize, value); + if (shift != 0) + value = il.ShiftLeft(regSize, value, il.Const(1, shift)); + + return il.Or(regSize, + il.And(regSize, il.Register(regSize, reg), il.Const(regSize, ~shiftedMask)), + value); +} + +static ExprId ReadFloatOperand(LowLevelILFunction& il, InstructionOperand& op, size_t size) +{ + switch (op.cls) + { + case REG: + return il.Register(size, op.reg); + case FIMM32: + return il.FloatConstRaw(size, op.imm); + case FIMM64: + return il.FloatConstRaw(size, op.imm64); + default: + return il.Unimplemented(); + } +} + +static void FloatCompare(LowLevelILFunction& il, Instruction& instr) +{ + InstructionOperand& lhsOp = instr.operands[0]; + InstructionOperand& rhsOp = instr.operands[1]; + size_t size = get_register_size(lhsOp.reg); + ExprId lhs = ReadFloatOperand(il, lhsOp, size); + ExprId rhs = (rhsOp.cls == NONE) ? il.FloatConstRaw(size, 0) : ReadFloatOperand(il, rhsOp, size); + + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.FloatCompareLessThan(size, lhs, rhs))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.FloatCompareEqual(size, lhs, rhs))); + il.AddInstruction(il.SetFlag(IL_FLAG_C, il.Not(1, il.FloatCompareLessThan(size, lhs, rhs)))); + il.AddInstruction(il.SetFlag(IL_FLAG_V, il.FloatCompareUnordered(size, lhs, rhs))); +} + +static ExprId RoundFloatOperand(LowLevelILFunction& il, Instruction& instr, ExprId src, size_t size) +{ + switch (instr.operation) + { + case ARMV7_VRINTN: + case ARMV7_VRINTR: + case ARMV7_VRINTX: + return il.RoundToInt(size, src); + case ARMV7_VRINTP: + return il.Ceil(size, src); + case ARMV7_VRINTM: + return il.Floor(size, src); + case ARMV7_VRINTZ: + return il.FloatTrunc(size, src); + default: + return il.Unimplemented(); + } +} + +static ExprId FixedPointScale(LowLevelILFunction& il, size_t size, uint64_t fractionalBits) +{ + double scale = static_cast(UINT64_C(1) << fractionalBits); + if (size == 8) + return il.FloatConstDouble(scale); + return il.FloatConstSingle(static_cast(scale)); +} + +static bool GetDoubleRegisterList(Register regList, std::vector& regs) +{ + for (uint32_t i = 0; i < 32; i++) + { + if (((static_cast(regList) >> i) & 1) != 0) + regs.push_back(static_cast(REG_D0 + i)); + } + return !regs.empty() && regs.size() <= 4; +} + +static ExprId VectorTableLookup(LowLevelILFunction& il, Instruction& instr) +{ + InstructionOperand& destOp = instr.operands[0]; + InstructionOperand& tableOp = instr.operands[1]; + InstructionOperand& indicesOp = instr.operands[2]; + if (destOp.cls != REG || tableOp.cls != REG_LIST_DOUBLE || indicesOp.cls != REG) + return il.Unimplemented(); + + std::vector tableRegs; + if (!GetDoubleRegisterList(tableOp.reg, tableRegs)) + return il.Unimplemented(); + + std::vector inputs; + inputs.push_back(il.Const(1, tableRegs.size())); + for (size_t i = 0; i < 4; i++) + { + if (i < tableRegs.size()) + inputs.push_back(il.Register(8, tableRegs[i])); + else + inputs.push_back(il.Const(8, 0)); + } + inputs.push_back(il.Register(8, indicesOp.reg)); + + bool isVtbl = instr.operation == ARMV7_VTBL; + if (!isVtbl) + inputs.push_back(il.Register(8, destOp.reg)); + + return il.Intrinsic( + { RegisterOrFlag::Register(destOp.reg) }, + isVtbl ? ARMV7_INTRIN_VTBL : ARMV7_INTRIN_VTBX, + inputs); +} + +static void HalvingVectorAdd(LowLevelILFunction& il, Instruction& instr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + size_t regSize = get_register_size(dst.reg); + size_t elementSize = GetDataTypeSize(instr.dataType); + + if (dst.cls != REG || src1.cls != REG || src2.cls != REG || regSize == 0 || elementSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + ARMV7_INTRIN_VHADD, + { + il.Const(1, elementSize * 8), + il.Const(1, IsSignedDataType(instr.dataType) ? 0 : 1), + il.Register(get_register_size(src1.reg), src1.reg), + il.Register(get_register_size(src2.reg), src2.reg), + })); +} + +static ExprId SaturatingVectorShiftRightNarrow(LowLevelILFunction& il, Instruction& instr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src = instr.operands[1]; + InstructionOperand& shift = instr.operands[2]; + + if (dst.cls != REG || src.cls != REG || shift.cls != IMM) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t sourceSize = get_register_size(src.reg); + if (elementSize == 0 || sourceSize == 0) + return il.Unimplemented(); + + bool sourceUnsigned = (instr.operation == ARMV7_VQSHRUN) ? false : !IsSignedDataType(instr.dataType); + if (instr.operation == ARMV7_VQRSHRUN) + sourceUnsigned = false; + bool destinationUnsigned = (instr.operation == ARMV7_VQSHRUN || instr.operation == ARMV7_VQRSHRUN) + ? true + : sourceUnsigned; + uint32_t intrinsic = (instr.operation == ARMV7_VQSHRUN) ? ARMV7_INTRIN_VQSHRUN : ARMV7_INTRIN_VQSHRN; + if (instr.operation == ARMV7_VQRSHRUN) + intrinsic = ARMV7_INTRIN_VQRSHRUN; + else if (instr.operation == ARMV7_VQRSHRN) + intrinsic = ARMV7_INTRIN_VQRSHRN; + + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + intrinsic, + { + il.Const(1, elementSize * 8), + il.Const(1, sourceUnsigned ? 1 : 0), + il.Const(1, destinationUnsigned ? 1 : 0), + il.Register(sourceSize, src.reg), + il.Const(sourceSize, shift.imm), + }); +} + +static ExprId SaturatingVectorMoveNarrow(LowLevelILFunction& il, Instruction& instr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src = instr.operands[1]; + + if (dst.cls != REG || src.cls != REG) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t sourceSize = get_register_size(src.reg); + if (elementSize == 0 || sourceSize == 0) + return il.Unimplemented(); + + bool sourceUnsigned = !IsSignedDataType(instr.dataType); + bool destinationUnsigned = sourceUnsigned || (instr.operation == ARMV7_VQMOVUN); + + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + (instr.operation == ARMV7_VQMOVUN) ? ARMV7_INTRIN_VQMOVUN : ARMV7_INTRIN_VQMOVN, + { + il.Const(1, elementSize * 8), + il.Const(1, sourceUnsigned ? 1 : 0), + il.Const(1, destinationUnsigned ? 1 : 0), + il.Register(sourceSize, src.reg), + }); +} + +static ExprId RoundedVectorShift(LowLevelILFunction& il, Instruction& instr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src = instr.operands[1]; + InstructionOperand& shift = instr.operands[2]; + + if (dst.cls != REG || src.cls != REG || (shift.cls != IMM && shift.cls != REG)) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t regSize = get_register_size(dst.reg); + if (elementSize == 0 || regSize == 0) + return il.Unimplemented(); + + ExprId shiftValue = shift.cls == IMM + ? il.Const(regSize, shift.imm) + : il.Register(regSize, shift.reg); + + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + (instr.operation == ARMV7_VRSHL) ? ARMV7_INTRIN_VRSHL : ARMV7_INTRIN_VRSHR, + { + il.Const(1, elementSize * 8), + il.Const(1, IsSignedDataType(instr.dataType) ? 0 : 1), + il.Register(regSize, src.reg), + shiftValue, + }); +} + +static ExprId ShiftRightAccumulateOrInsert(LowLevelILFunction& il, Instruction& instr, uint32_t intrinsic) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src = instr.operands[1]; + InstructionOperand& shift = instr.operands[2]; + + if (dst.cls != REG || src.cls != REG || shift.cls != IMM) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t regSize = get_register_size(dst.reg); + if (elementSize == 0 || regSize == 0) + return il.Unimplemented(); + + if (intrinsic == ARMV7_INTRIN_VSRA || intrinsic == ARMV7_INTRIN_VRSRA) + { + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + intrinsic, + { + il.Const(1, elementSize * 8), + il.Const(1, IsSignedDataType(instr.dataType) ? 0 : 1), + il.Register(regSize, dst.reg), + il.Register(regSize, src.reg), + il.Const(regSize, shift.imm), + }); + } + + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + intrinsic, + { + il.Const(1, elementSize * 8), + il.Register(regSize, dst.reg), + il.Register(regSize, src.reg), + il.Const(regSize, shift.imm), + }); +} + +static ExprId VectorDuplicate(LowLevelILFunction& il, Instruction& instr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src = instr.operands[1]; + + if (dst.cls != REG || src.cls != REG) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t destSize = get_register_size(dst.reg); + size_t sourceSize = get_register_size(src.reg); + if (elementSize == 0 || destSize == 0 || sourceSize == 0) + return il.Unimplemented(); + + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + ARMV7_INTRIN_VDUP, + { + il.Const(1, elementSize * 8), + il.Register(sourceSize, src.reg), + il.Const(1, src.flags.hasElements ? src.imm : 0), + }); +} + +static ExprId SaturatingVectorAdd(LowLevelILFunction& il, Instruction& instr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + + if (dst.cls != REG || src1.cls != REG || src2.cls != REG) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t regSize = get_register_size(dst.reg); + if (elementSize == 0 || regSize == 0) + return il.Unimplemented(); + + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + ARMV7_INTRIN_VQADD, + { + il.Const(1, elementSize * 8), + il.Const(1, IsSignedDataType(instr.dataType) ? 0 : 1), + il.Register(regSize, src1.reg), + il.Register(regSize, src2.reg), + }); +} + +static ExprId SaturatingVectorShiftLeft(LowLevelILFunction& il, Instruction& instr, uint32_t intrinsic) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src = instr.operands[1]; + InstructionOperand& shift = instr.operands[2]; + + if (dst.cls != REG || src.cls != REG || shift.cls != REG) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t regSize = get_register_size(dst.reg); + if (elementSize == 0 || regSize == 0) + return il.Unimplemented(); + + bool isUnsigned = !IsSignedDataType(instr.dataType); + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + intrinsic, + { + il.Const(1, elementSize * 8), + il.Const(1, isUnsigned ? 1 : 0), + il.Const(1, isUnsigned ? 1 : 0), + il.Register(regSize, src.reg), + il.Register(regSize, shift.reg), + }); +} + +static ExprId VectorMaximumMinimum(LowLevelILFunction& il, Instruction& instr, uint32_t intrinsic) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + + if (dst.cls != REG || src1.cls != REG || src2.cls != REG) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t regSize = get_register_size(dst.reg); + if (elementSize == 0 || regSize == 0) + return il.Unimplemented(); + + bool isUnsigned = !IsSignedDataType(instr.dataType) && instr.dataType != DT_F32 && instr.dataType != DT_F64; + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + intrinsic, + { + il.Const(1, elementSize * 8), + il.Const(1, isUnsigned ? 1 : 0), + il.Register(get_register_size(src1.reg), src1.reg), + il.Register(get_register_size(src2.reg), src2.reg), + }); +} + +static ExprId VectorReverse(LowLevelILFunction& il, Instruction& instr, uint32_t intrinsic) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src = instr.operands[1]; + + if (dst.cls != REG || src.cls != REG) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t destSize = get_register_size(dst.reg); + size_t sourceSize = get_register_size(src.reg); + if (elementSize == 0 || destSize == 0 || sourceSize == 0) + return il.Unimplemented(); + + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + intrinsic, + { + il.Const(1, elementSize * 8), + il.Register(sourceSize, src.reg), + }); +} + +static ExprId VectorExtract(LowLevelILFunction& il, Instruction& instr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + InstructionOperand& index = instr.operands[3]; + + if (dst.cls != REG || src1.cls != REG || src2.cls != REG || index.cls != IMM) + return il.Unimplemented(); + + size_t destSize = get_register_size(dst.reg); + size_t source1Size = get_register_size(src1.reg); + size_t source2Size = get_register_size(src2.reg); + if (destSize == 0 || source1Size == 0 || source2Size == 0) + return il.Unimplemented(); + + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + ARMV7_INTRIN_VEXT, + { + il.Const(1, 8), + il.Register(source1Size, src1.reg), + il.Register(source2Size, src2.reg), + il.Const(1, index.imm / 8), + }); +} + +static ExprId VectorAbsoluteDifferenceAccumulate(LowLevelILFunction& il, Instruction& instr, uint32_t intrinsic) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + + if (dst.cls != REG || src1.cls != REG || src2.cls != REG) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t destSize = get_register_size(dst.reg); + size_t sourceSize = get_register_size(src1.reg); + if (elementSize == 0 || destSize == 0 || sourceSize == 0) + return il.Unimplemented(); + + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + intrinsic, + { + il.Const(1, elementSize * 8), + il.Const(1, IsSignedDataType(instr.dataType) ? 0 : 1), + il.Register(destSize, dst.reg), + il.Register(sourceSize, src1.reg), + il.Register(get_register_size(src2.reg), src2.reg), + }); +} + +static ExprId VectorAbsoluteDifference(LowLevelILFunction& il, Instruction& instr, uint32_t intrinsic) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + + if (dst.cls != REG || src1.cls != REG || src2.cls != REG) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t destSize = get_register_size(dst.reg); + size_t source1Size = get_register_size(src1.reg); + size_t source2Size = get_register_size(src2.reg); + if (elementSize == 0 || destSize == 0 || source1Size == 0 || source2Size == 0) + return il.Unimplemented(); + + bool isUnsigned = !IsSignedDataType(instr.dataType) && instr.dataType != DT_F32 && instr.dataType != DT_F64; + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + intrinsic, + { + il.Const(1, elementSize * 8), + il.Const(1, isUnsigned ? 1 : 0), + il.Register(source1Size, src1.reg), + il.Register(source2Size, src2.reg), + }); +} + +static ExprId VectorWideningAdd(LowLevelILFunction& il, Instruction& instr, uint32_t intrinsic) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + + if (dst.cls != REG || src1.cls != REG || src2.cls != REG) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t destSize = get_register_size(dst.reg); + size_t source1Size = get_register_size(src1.reg); + size_t source2Size = get_register_size(src2.reg); + if (elementSize == 0 || destSize == 0 || source1Size == 0 || source2Size == 0) + return il.Unimplemented(); + + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + intrinsic, + { + il.Const(1, elementSize * 8), + il.Const(1, IsSignedDataType(instr.dataType) ? 0 : 1), + il.Register(source1Size, src1.reg), + il.Register(source2Size, src2.reg), + }); +} + +static ExprId VectorRoundingAddNarrow(LowLevelILFunction& il, Instruction& instr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + + if (dst.cls != REG || src1.cls != REG || src2.cls != REG) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t destSize = get_register_size(dst.reg); + size_t source1Size = get_register_size(src1.reg); + size_t source2Size = get_register_size(src2.reg); + if (elementSize == 0 || destSize == 0 || source1Size == 0 || source2Size == 0) + return il.Unimplemented(); + + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + ARMV7_INTRIN_VRADDHN, + { + il.Const(1, elementSize * 8), + il.Register(source1Size, src1.reg), + il.Register(source2Size, src2.reg), + }); +} + +static ExprId VectorMultiply(LowLevelILFunction& il, Instruction& instr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + + if (dst.cls != REG || src1.cls != REG || src2.cls != REG) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t destSize = get_register_size(dst.reg); + size_t source1Size = get_register_size(src1.reg); + size_t source2Size = get_register_size(src2.reg); + if (elementSize == 0 || destSize == 0 || source1Size == 0 || source2Size == 0) + return il.Unimplemented(); + + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + ARMV7_INTRIN_VMUL, + { + il.Const(1, elementSize * 8), + il.Const(1, IsUnsignedDataType(instr.dataType) ? 1 : 0), + il.Register(source1Size, src1.reg), + il.Register(source2Size, src2.reg), + }); +} + +static ExprId VectorMultiplyAccumulateIntrinsic(LowLevelILFunction& il, Instruction& instr, uint32_t intrinsic) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + + if (dst.cls != REG || src1.cls != REG || src2.cls != REG) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t destSize = get_register_size(dst.reg); + size_t source1Size = get_register_size(src1.reg); + size_t source2Size = get_register_size(src2.reg); + if (elementSize == 0 || destSize == 0 || source1Size == 0 || source2Size == 0) + return il.Unimplemented(); + + std::vector inputs; + inputs.push_back(il.Const(1, elementSize * 8)); + if ((intrinsic == ARMV7_INTRIN_VMLAL) || (intrinsic == ARMV7_INTRIN_VMLSL)) + inputs.push_back(il.Const(1, IsUnsignedDataType(instr.dataType) ? 1 : 0)); + inputs.push_back(il.Register(destSize, dst.reg)); + inputs.push_back(il.Register(source1Size, src1.reg)); + inputs.push_back(il.Register(source2Size, src2.reg)); + inputs.push_back(il.Const(1, src2.flags.hasElements ? src2.imm : 0xff)); + + return il.Intrinsic({ RegisterOrFlag::Register(dst.reg) }, intrinsic, inputs); +} + +static ExprId VectorSaturatingDoublingMultiplyLongIntrinsic(LowLevelILFunction& il, Instruction& instr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + + if (dst.cls != REG || src1.cls != REG || src2.cls != REG) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t source1Size = get_register_size(src1.reg); + size_t source2Size = get_register_size(src2.reg); + if (elementSize == 0 || source1Size == 0 || source2Size == 0) + return il.Unimplemented(); + + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + ARMV7_INTRIN_VQDMULL, + { + il.Const(1, elementSize * 8), + il.Const(1, IsUnsignedDataType(instr.dataType) ? 1 : 0), + il.Register(source1Size, src1.reg), + il.Register(source2Size, src2.reg), + }); +} + +static void VectorCompareEqual(LowLevelILFunction& il, Instruction& instr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + size_t regSize = get_register_size(dst.reg); + size_t elementSize = GetDataTypeSize(instr.dataType); + + if (dst.cls != REG || src1.cls != REG || (src2.cls != REG && src2.cls != IMM) + || regSize == 0 || elementSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + if (src2.cls == IMM && src2.imm != 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + bool isFloat = instr.dataType == DT_F32; + ExprId rhs = (src2.cls == IMM) ? il.Const(regSize, 0) : il.Register(get_register_size(src2.reg), src2.reg); + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + ARMV7_INTRIN_VCEQ, + { + il.Const(1, elementSize * 8), + il.Const(1, isFloat ? 1 : 0), + il.Register(get_register_size(src1.reg), src1.reg), + rhs, + })); +} + +static ExprId VectorCompareGreaterThan(LowLevelILFunction& il, Instruction& instr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + + if (dst.cls != REG || src1.cls != REG || (src2.cls != REG && src2.cls != IMM)) + return il.Unimplemented(); + + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t regSize = get_register_size(dst.reg); + if (elementSize == 0 || regSize == 0) + return il.Unimplemented(); + + if (src2.cls == IMM && src2.imm != 0) + return il.Unimplemented(); + + ExprId rhs = (src2.cls == IMM) ? il.Const(regSize, 0) : il.Register(get_register_size(src2.reg), src2.reg); + bool isUnsigned = !IsSignedDataType(instr.dataType) && instr.dataType != DT_F32 && instr.dataType != DT_F64; + return il.Intrinsic( + { RegisterOrFlag::Register(dst.reg) }, + ARMV7_INTRIN_VCGT, + { + il.Const(1, elementSize * 8), + il.Const(1, isUnsigned ? 1 : 0), + il.Register(get_register_size(src1.reg), src1.reg), + rhs, + }); +} static ExprId GetShifted(LowLevelILFunction& il, Register reg, uint32_t ShiftAmount, Shift shift) { @@ -233,6 +1112,33 @@ static ExprId GetShiftedRegister(LowLevelILFunction& il, InstructionOperand& op) return GetShifted(il, op.reg, op.imm, op.shift); } +static bool GetShiftCarryOut(LowLevelILFunction& il, InstructionOperand& op, ExprId& carry) +{ + if (op.flags.offsetRegUsed || op.imm == 0) + return false; + + size_t regSize = get_register_size(op.reg); + ExprId value = il.Register(regSize, op.reg); + switch (op.shift) + { + case SHIFT_LSL: + carry = il.TestBit(regSize, value, il.Const(1, 32 - op.imm)); + return true; + case SHIFT_LSR: + case SHIFT_ASR: + carry = il.TestBit(regSize, value, il.Const(1, op.imm - 1)); + return true; + case SHIFT_ROR: + carry = il.TestBit(regSize, value, il.Const(1, (op.imm - 1) & 31)); + return true; + case SHIFT_RRX: + carry = il.TestBit(regSize, value, il.Const(1, 0)); + return true; + default: + return false; + } +} + static ExprId ReadAddress(LowLevelILFunction& il, InstructionOperand& op, size_t addr) { @@ -332,6 +1238,147 @@ static ExprId ReadILOperand(LowLevelILFunction& il, InstructionOperand& op, size return 0; } +static void LogicalOperand(LowLevelILFunction& il, Instruction& instr, bool writeFlags, bool exclusiveOr, size_t addr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + size_t size = get_register_size(dst.reg); + ExprId value = exclusiveOr + ? il.Xor(size, ReadRegisterOrPointer(il, src1, addr), ReadILOperand(il, src2, addr)) + : il.And(size, ReadRegisterOrPointer(il, src1, addr), ReadILOperand(il, src2, addr)); + + if (!writeFlags) + { + il.AddInstruction(SetRegisterOrBranch(il, dst.reg, value)); + return; + } + + il.AddInstruction(il.SetRegister(size, LLIL_TEMP(0), value)); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(size, il.Register(size, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(size, il.Register(size, LLIL_TEMP(0)), il.Const(size, 0)))); + + ExprId carry; + if (GetShiftCarryOut(il, src2, carry)) + il.AddInstruction(il.SetFlag(IL_FLAG_C, carry)); + + il.AddInstruction(SetRegisterOrBranch(il, dst.reg, il.Register(size, LLIL_TEMP(0)))); +} + +static void TestOperand(LowLevelILFunction& il, Instruction& instr, size_t addr) +{ + InstructionOperand& src1 = instr.operands[0]; + InstructionOperand& src2 = instr.operands[1]; + size_t size = get_register_size(src1.reg); + + il.AddInstruction(il.SetRegister(size, LLIL_TEMP(0), + il.And(size, ReadRegisterOrPointer(il, src1, addr), ReadILOperand(il, src2, addr)))); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(size, il.Register(size, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(size, il.Register(size, LLIL_TEMP(0)), il.Const(size, 0)))); + + ExprId carry; + if (GetShiftCarryOut(il, src2, carry)) + il.AddInstruction(il.SetFlag(IL_FLAG_C, carry)); +} + +static void TestEquivalenceOperand(LowLevelILFunction& il, Instruction& instr, size_t addr) +{ + InstructionOperand& src1 = instr.operands[0]; + InstructionOperand& src2 = instr.operands[1]; + size_t size = get_register_size(src1.reg); + + il.AddInstruction(il.SetRegister(size, LLIL_TEMP(0), + il.Xor(size, ReadRegisterOrPointer(il, src1, addr), ReadILOperand(il, src2, addr)))); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(size, il.Register(size, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(size, il.Register(size, LLIL_TEMP(0)), il.Const(size, 0)))); + + ExprId carry; + if (GetShiftCarryOut(il, src2, carry)) + il.AddInstruction(il.SetFlag(IL_FLAG_C, carry)); +} + +static void BitClearOperand(LowLevelILFunction& il, Instruction& instr, bool writeFlags, size_t addr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src1 = instr.operands[1]; + InstructionOperand& src2 = instr.operands[2]; + size_t size = get_register_size(dst.reg); + ExprId value = il.And(size, + ReadRegisterOrPointer(il, src1, addr), + il.Not(size, ReadILOperand(il, src2, addr))); + + if (!writeFlags) + { + il.AddInstruction(SetRegisterOrBranch(il, dst.reg, value)); + return; + } + + il.AddInstruction(il.SetRegister(size, LLIL_TEMP(0), value)); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(size, il.Register(size, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(size, il.Register(size, LLIL_TEMP(0)), il.Const(size, 0)))); + + ExprId carry; + if (GetShiftCarryOut(il, src2, carry)) + il.AddInstruction(il.SetFlag(IL_FLAG_C, carry)); + + il.AddInstruction(SetRegisterOrBranch(il, dst.reg, il.Register(size, LLIL_TEMP(0)))); +} + +static void MoveNotOperand(LowLevelILFunction& il, Instruction& instr, bool writeFlags, size_t addr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src = instr.operands[1]; + size_t size = get_register_size(dst.reg); + ExprId value = il.Not(size, ReadILOperand(il, src, addr)); + + if (!writeFlags) + { + il.AddInstruction(SetRegisterOrBranch(il, dst.reg, value)); + return; + } + + il.AddInstruction(il.SetRegister(size, LLIL_TEMP(0), value)); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(size, il.Register(size, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(size, il.Register(size, LLIL_TEMP(0)), il.Const(size, 0)))); + + ExprId carry; + if (GetShiftCarryOut(il, src, carry)) + il.AddInstruction(il.SetFlag(IL_FLAG_C, carry)); + + il.AddInstruction(SetRegisterOrBranch(il, dst.reg, il.Register(size, LLIL_TEMP(0)))); +} + +static void RotateRightOperand(LowLevelILFunction& il, Instruction& instr, bool writeFlags, size_t addr) +{ + InstructionOperand& dst = instr.operands[0]; + InstructionOperand& src = instr.operands[1]; + InstructionOperand& shift = instr.operands[2]; + size_t size = get_register_size(dst.reg); + ExprId source = ReadRegisterOrPointer(il, src, addr); + ExprId shiftValue = il.And(4, ReadILOperand(il, shift, addr), il.Const(4, 0xff)); + ExprId value = il.RotateRight(size, source, shiftValue); + if (!writeFlags) + { + il.AddInstruction(SetRegisterOrBranch(il, dst.reg, value)); + return; + } + + il.AddInstruction(il.SetRegister(size, LLIL_TEMP(0), value)); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(size, il.Register(size, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(size, il.Register(size, LLIL_TEMP(0)), il.Const(size, 0)))); + + LowLevelILLabel zeroShift, setCarry, done; + il.AddInstruction(il.If(il.CompareEqual(4, shiftValue, il.Const(4, 0)), zeroShift, setCarry)); + il.MarkLabel(zeroShift); + il.AddInstruction(il.Goto(done)); + il.MarkLabel(setCarry); + il.AddInstruction(il.SetFlag(IL_FLAG_C, + il.TestBit(size, source, + il.And(1, il.Sub(1, il.LowPart(1, shiftValue), il.Const(1, 1)), il.Const(1, 0x1f))))); + il.MarkLabel(done); + il.AddInstruction(SetRegisterOrBranch(il, dst.reg, il.Register(size, LLIL_TEMP(0)))); +} + static void Load( LowLevelILFunction& il, @@ -510,20 +1557,345 @@ static void Store( } } - -static void StoreExclusive( - LowLevelILFunction& il, - uint8_t size, - InstructionOperand& status, - InstructionOperand& src, - InstructionOperand& dst, - size_t addr) +static void StoreVst1(LowLevelILFunction& il, Instruction& instr, size_t addr) { - ExprId address = ReadAddress(il, dst, addr); - size_t dstSize = get_register_size(dst.reg); + InstructionOperand& regs = instr.operands[0]; + InstructionOperand& mem = instr.operands[1]; + InstructionOperand& writeback = instr.operands[2]; + uint32_t regMask = (uint32_t)regs.reg; + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t offset = 0; + size_t totalSize = 0; + ExprId base = ReadRegisterOrPointer(il, mem, addr); + + if (regs.cls != REG_LIST_DOUBLE || mem.cls != MEM_ALIGNED || elementSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } - LowLevelILLabel trueCode, falseCode; - size_t statusSize = get_register_size(status.reg); + for (uint32_t i = 0; i < 32; i++) + { + if (((regMask >> i) & 1) == 0) + continue; + + Register reg = (Register)(REG_D0 + i); + size_t storeSize = regs.flags.hasElements ? elementSize : get_register_size(reg); + ExprId address = (offset == 0) ? base : il.Add(4, base, il.Const(4, offset)); + ExprId value = regs.flags.hasElements ? ReadVectorElement(il, reg, elementSize, regs.imm) : il.Register(storeSize, reg); + il.AddInstruction(il.Store(storeSize, address, value)); + offset += storeSize; + totalSize += storeSize; + } + + if (mem.flags.wb) + { + il.AddInstruction(il.SetRegister(get_register_size(mem.reg), mem.reg, + il.Add(get_register_size(mem.reg), base, il.Const(get_register_size(mem.reg), totalSize)))); + } + else if (writeback.cls == REG) + { + il.AddInstruction(il.SetRegister(get_register_size(mem.reg), mem.reg, + il.Add(get_register_size(mem.reg), base, il.Register(get_register_size(writeback.reg), writeback.reg)))); + } +} + +static void StoreStructuredVector(LowLevelILFunction& il, Instruction& instr, size_t addr, uint32_t intrinsic, + size_t structureCount) +{ + InstructionOperand& regs = instr.operands[0]; + InstructionOperand& mem = instr.operands[1]; + InstructionOperand& writeback = instr.operands[2]; + uint32_t regMask = (uint32_t)regs.reg; + size_t elementSize = GetDataTypeSize(instr.dataType); + ExprId sources[4] = {il.Const(8, 0), il.Const(8, 0), il.Const(8, 0), il.Const(8, 0)}; + size_t regCount = 0; + ExprId base = ReadRegisterOrPointer(il, mem, addr); + + if (regs.cls != REG_LIST_DOUBLE || mem.cls != MEM_ALIGNED || elementSize == 0 || structureCount == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + for (uint32_t i = 0; i < 32 && regCount < 4; i++) + { + if (((regMask >> i) & 1) == 0) + continue; + Register reg = (Register)(REG_D0 + i); + sources[regCount++] = il.Register(get_register_size(reg), reg); + } + + if ((structureCount == 4 && regCount != 4) || (structureCount == 2 && regCount != 2 && regCount != 4)) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + il.AddInstruction(il.Intrinsic({}, intrinsic, { + base, + il.Const(1, elementSize * 8), + il.Const(1, mem.imm), + il.Const(1, regs.flags.hasElements ? regs.imm : 0xff), + sources[0], + sources[1], + sources[2], + sources[3], + })); + + size_t totalSize = regs.flags.hasElements ? structureCount * elementSize : regCount * 8; + if (mem.flags.wb) + { + il.AddInstruction(il.SetRegister(get_register_size(mem.reg), mem.reg, + il.Add(get_register_size(mem.reg), base, il.Const(get_register_size(mem.reg), totalSize)))); + } + else if (writeback.cls == REG) + { + il.AddInstruction(il.SetRegister(get_register_size(mem.reg), mem.reg, + il.Add(get_register_size(mem.reg), base, il.Register(get_register_size(writeback.reg), writeback.reg)))); + } +} + +static void LoadStructuredVector(LowLevelILFunction& il, Instruction& instr, size_t addr, uint32_t intrinsic, + size_t structureCount) +{ + InstructionOperand& regs = instr.operands[0]; + InstructionOperand& mem = instr.operands[1]; + InstructionOperand& writeback = instr.operands[2]; + uint32_t regMask = (uint32_t)regs.reg; + size_t elementSize = GetDataTypeSize(instr.dataType); + std::vector outputs; + size_t regCount = 0; + ExprId base = ReadRegisterOrPointer(il, mem, addr); + + if (regs.cls != REG_LIST_DOUBLE || mem.cls != MEM_ALIGNED || elementSize == 0 || structureCount == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + for (uint32_t i = 0; i < 32 && regCount < 4; i++) + { + if (((regMask >> i) & 1) == 0) + continue; + outputs.push_back(RegisterOrFlag::Register((Register)(REG_D0 + i))); + regCount++; + } + + if ((structureCount == 4 && regCount != 4) || (structureCount == 2 && regCount != 2 && regCount != 4)) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + il.AddInstruction(il.Intrinsic(outputs, intrinsic, { + base, + il.Const(1, elementSize * 8), + il.Const(1, mem.imm), + il.Const(1, regs.flags.hasElements ? regs.imm : 0xff), + })); + + size_t totalSize = regs.flags.hasElements ? structureCount * elementSize : regCount * 8; + if (mem.flags.wb) + { + il.AddInstruction(il.SetRegister(get_register_size(mem.reg), mem.reg, + il.Add(get_register_size(mem.reg), base, il.Const(get_register_size(mem.reg), totalSize)))); + } + else if (writeback.cls == REG) + { + il.AddInstruction(il.SetRegister(get_register_size(mem.reg), mem.reg, + il.Add(get_register_size(mem.reg), base, il.Register(get_register_size(writeback.reg), writeback.reg)))); + } +} + +static void StoreVpush(LowLevelILFunction& il, Instruction& instr, size_t addr) +{ + (void) addr; + InstructionOperand& regs = instr.operands[0]; + uint32_t regMask = (uint32_t)regs.reg; + Register baseReg; + size_t regSize; + + if (regs.cls == REG_LIST_SINGLE) + { + baseReg = REG_S0; + regSize = 4; + } + else if (regs.cls == REG_LIST_DOUBLE) + { + baseReg = REG_D0; + regSize = 8; + } + else + { + il.AddInstruction(il.Unimplemented()); + return; + } + + for (uint32_t i = 0; i < 32; i++) + { + if (((regMask >> i) & 1) == 1) + { + Register reg = (Register)(baseReg + i); + il.AddInstruction(il.Push(regSize, il.Register(regSize, reg))); + } + } +} + +static void LoadVpop(LowLevelILFunction& il, Instruction& instr, size_t addr) +{ + (void) addr; + InstructionOperand& regs = instr.operands[0]; + uint32_t regMask = (uint32_t)regs.reg; + Register baseReg; + size_t regSize; + + if (regs.cls == REG_LIST_SINGLE) + { + baseReg = REG_S0; + regSize = 4; + } + else if (regs.cls == REG_LIST_DOUBLE) + { + baseReg = REG_D0; + regSize = 8; + } + else + { + il.AddInstruction(il.Unimplemented()); + return; + } + + for (uint32_t i = 0; i < 32; i++) + { + if (((regMask >> i) & 1) == 1) + { + Register reg = (Register)(baseReg + i); + il.AddInstruction(il.SetRegister(regSize, reg, il.Pop(regSize))); + } + } +} + +static void VfpLoadStoreMultiple(LowLevelILFunction& il, InstructionOperand& base, InstructionOperand& regs, bool load, + bool decrementBefore) +{ + uint32_t regMask = (uint32_t)regs.reg; + Register baseReg; + size_t regSize; + + if (base.cls != REG) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + if (regs.cls == REG_LIST_SINGLE) + { + baseReg = REG_S0; + regSize = 4; + } + else if (regs.cls == REG_LIST_DOUBLE) + { + baseReg = REG_D0; + regSize = 8; + } + else + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t count = 0; + for (uint32_t i = 0; i < 32; i++) + { + if (((regMask >> i) & 1) == 1) + count++; + } + size_t totalSize = count * regSize; + ExprId start = decrementBefore ? il.Sub(4, il.Register(4, base.reg), il.Const(4, totalSize)) : il.Register(4, base.reg); + + uint32_t index = 0; + for (uint32_t i = 0; i < 32; i++) + { + if (((regMask >> i) & 1) == 0) + continue; + + Register reg = (Register)(baseReg + i); + ExprId address = index == 0 ? start : il.Add(4, start, il.Const(4, index * regSize)); + if (load) + il.AddInstruction(il.SetRegister(regSize, reg, il.Load(regSize, address))); + else + il.AddInstruction(il.Store(regSize, address, il.Register(regSize, reg))); + index++; + } + + if (base.flags.wb) + { + ExprId newBase = decrementBefore ? il.Sub(4, il.Register(4, base.reg), il.Const(4, totalSize)) + : il.Add(4, il.Register(4, base.reg), il.Const(4, totalSize)); + il.AddInstruction(il.SetRegister(4, base.reg, newBase)); + } +} + +static void LoadVld1(LowLevelILFunction& il, Instruction& instr, size_t addr) +{ + InstructionOperand& regs = instr.operands[0]; + InstructionOperand& mem = instr.operands[1]; + InstructionOperand& writeback = instr.operands[2]; + uint32_t regMask = (uint32_t)regs.reg; + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t offset = 0; + size_t totalSize = 0; + ExprId base = ReadRegisterOrPointer(il, mem, addr); + + if (regs.cls != REG_LIST_DOUBLE || mem.cls != MEM_ALIGNED || elementSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + for (uint32_t i = 0; i < 32; i++) + { + if (((regMask >> i) & 1) == 0) + continue; + + Register reg = (Register)(REG_D0 + i); + size_t loadSize = regs.flags.hasElements ? elementSize : get_register_size(reg); + ExprId address = (offset == 0) ? base : il.Add(4, base, il.Const(4, offset)); + ExprId value = il.Load(loadSize, address); + if (regs.flags.hasElements) + value = InsertVectorElement(il, reg, value, elementSize, regs.imm); + il.AddInstruction(il.SetRegister(get_register_size(reg), reg, value)); + offset += loadSize; + totalSize += loadSize; + } + + if (mem.flags.wb) + { + il.AddInstruction(il.SetRegister(get_register_size(mem.reg), mem.reg, + il.Add(get_register_size(mem.reg), base, il.Const(get_register_size(mem.reg), totalSize)))); + } + else if (writeback.cls == REG) + { + il.AddInstruction(il.SetRegister(get_register_size(mem.reg), mem.reg, + il.Add(get_register_size(mem.reg), base, il.Register(get_register_size(writeback.reg), writeback.reg)))); + } +} + + +static void StoreExclusive( + LowLevelILFunction& il, + uint8_t size, + InstructionOperand& status, + InstructionOperand& src, + InstructionOperand& dst, + size_t addr) +{ + ExprId address = ReadAddress(il, dst, addr); + size_t dstSize = get_register_size(dst.reg); + + LowLevelILLabel trueCode, falseCode; + size_t statusSize = get_register_size(status.reg); il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(status.reg) }, ARMV7_INTRIN_EXCLUSIVE_MONITORS_PASS, { address, il.Const(1, dstSize) })); @@ -565,6 +1937,52 @@ static void StorePair( il.AddInstruction(SetRegisterOrBranch(il, dst.reg, ReadAddress(il, dst, addr))); } +static void CoprocStore( + LowLevelILFunction& il, + InstructionOperand& coproc, + InstructionOperand& coprocReg, + InstructionOperand& dst, + bool longTransfer, + size_t addr) +{ + ExprId address = (dst.cls == MEM_POST_IDX) ? ILREG(dst) : ReadAddress(il, dst, addr); + + il.AddInstruction(il.Intrinsic({ }, + ARMV7_INTRIN_COPROC_STORE, + { + address, + il.Const(1, coproc.reg), + il.Const(1, coprocReg.reg), + il.Const(1, longTransfer ? 1 : 0), + })); + + if (dst.cls == MEM_POST_IDX || dst.cls == MEM_PRE_IDX) + il.AddInstruction(SetRegisterOrBranch(il, dst.reg, ReadAddress(il, dst, addr))); +} + +static void CoprocLoad( + LowLevelILFunction& il, + InstructionOperand& coproc, + InstructionOperand& coprocReg, + InstructionOperand& src, + bool longTransfer, + size_t addr) +{ + ExprId address = (src.cls == MEM_POST_IDX || src.cls == MEM_OPTION) ? ILREG(src) : ReadAddress(il, src, addr); + + il.AddInstruction(il.Intrinsic({ }, + ARMV7_INTRIN_COPROC_LOAD, + { + address, + il.Const(1, coproc.reg), + il.Const(1, coprocReg.reg), + il.Const(1, longTransfer ? 1 : 0), + })); + + if (src.cls == MEM_POST_IDX || src.cls == MEM_PRE_IDX) + il.AddInstruction(SetRegisterOrBranch(il, src.reg, ReadAddress(il, src, addr))); +} + static void StorePairExclusive( Architecture* arch, @@ -634,7 +2052,6 @@ static void Saturate(LowLevelILFunction& il, uint32_t dest, ExprId to_saturate, } } - uint32_t GetNumberOfRegs(uint16_t regList) { uint32_t nregs = 0; @@ -716,6 +2133,7 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI (void)arch; (void)addr; (void)addrSize; + InstructionOperand& op1 = instr.operands[0]; InstructionOperand& op2 = instr.operands[1]; InstructionOperand& op3 = instr.operands[2]; @@ -751,10 +2169,13 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI il.ConstPointer(get_register_size(op1.reg), op2.imm))); break; case ARMV7_AND: - ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, - il.And(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op2, addr), - ReadILOperand(il, op3, addr), flagOperation[instr.setsFlags]))); + case ARMV7_ANDS: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + LogicalOperand(il, instr, instr.operation == ARMV7_ANDS || instr.setsFlags, false, addr); + }); break; case ARMV7_ASR: ConditionExecute(il, instr.cond, @@ -796,6 +2217,130 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI case ARMV7_BKPT: il.AddInstruction(il.Breakpoint()); break; + case ARMV7_CLREX: + ConditionExecute(il, instr.cond, il.Intrinsic({}, ARMV7_INTRIN_CLREX, {})); + break; + case ARMV7_PLD: + ConditionExecute(il, instr.cond, + il.Intrinsic({}, ARMV7_INTRIN_PLD, {ReadILOperand(il, op1, addr, true)}) + ); + break; + case ARMV7_CRC32B: + case ARMV7_CRC32CB: + case ARMV7_CRC32CH: + case ARMV7_CRC32CW: + case ARMV7_CRC32H: + case ARMV7_CRC32W: + { + size_t valueSize = GetCrc32ValueSize(instr.operation); + ExprId value = ReadILOperand(il, op3, addr); + if (valueSize < 4) + value = il.LowPart(valueSize, value); + ConditionExecute(il, instr.cond, + il.Intrinsic( + { RegisterOrFlag::Register(op1.reg) }, + GetCrc32Intrinsic(instr.operation), + { + ReadILOperand(il, op2, addr), + value, + } + ) + ); + break; + } + case ARMV7_YIELD: + ConditionExecute(il, instr.cond, il.Intrinsic({}, ARMV7_INTRIN_YIELD, {})); + break; + case ARMV7_SEV: + ConditionExecute(il, instr.cond, il.Intrinsic({}, ARMV7_INTRIN_SEV, {})); + break; + case ARMV7_WFE: + ConditionExecute(il, instr.cond, il.Intrinsic({}, ARMV7_INTRIN_WFE, {})); + break; + case ARMV7_WFI: + ConditionExecute(il, instr.cond, il.Intrinsic({}, ARMV7_INTRIN_WFI, {})); + break; + case ARMV7_DBG: + ConditionExecute(il, instr.cond, il.Intrinsic({}, ARMV7_INTRIN_DBG, {il.Const(1, op1.imm)})); + break; + case ARMV7_HINT: + ConditionExecute(il, instr.cond, il.Intrinsic({}, ARMV7_INTRIN_HINT, {il.Const(1, op1.imm)})); + break; + case ARMV7_UNPREDICTABLE: + ConditionExecute(il, instr.cond, il.Intrinsic({}, ARMV7_INTRIN_UNPREDICTABLE, {})); + break; + case ARMV7_CPS: + case ARMV7_CPSIE: + case ARMV7_CPSID: + { + uint8_t iflags = IFL_NONE; + uint8_t mode = 0; + + for (size_t i = 0; i < 4; i++) + { + if (instr.operands[i].cls == IFLAGS) + iflags = instr.operands[i].iflag; + else if (instr.operands[i].cls == IMM) + mode = instr.operands[i].imm; + } + + if (instr.operation == ARMV7_CPS) + { + ConditionExecute(il, instr.cond, + il.Intrinsic({}, ARMV7_INTRIN_CPS, {il.Const(1, mode)}) + ); + } + else + { + ConditionExecute(il, instr.cond, + il.Intrinsic({}, (instr.operation == ARMV7_CPSIE) ? ARMV7_INTRIN_CPSIE : ARMV7_INTRIN_CPSID, { + il.Const(1, iflags), + il.Const(1, mode) + }) + ); + } + break; + } + case ARMV7_SETEND: + ConditionExecute(il, instr.cond, + il.Intrinsic({}, ARMV7_INTRIN_SETEND, {il.Const(1, op1.endian)})); + break; + case ARMV7_SRS: + case ARMV7_SRSDA: + case ARMV7_SRSDB: + case ARMV7_SRSIA: + case ARMV7_SRSIB: + { + bool increment = (instr.operation == ARMV7_SRSIA) || (instr.operation == ARMV7_SRSIB); + bool wordhigher = (instr.operation == ARMV7_SRSDA) || (instr.operation == ARMV7_SRSIB); + ConditionExecute(il, instr.cond, + il.Intrinsic({}, ARMV7_INTRIN_SRS, { + il.Const(1, op2.imm), + il.Const(1, increment ? 1 : 0), + il.Const(1, wordhigher ? 1 : 0), + il.Const(1, op1.flags.wb ? 1 : 0), + }) + ); + break; + } + case ARMV7_RFE: + case ARMV7_RFEDA: + case ARMV7_RFEDB: + case ARMV7_RFEIA: + case ARMV7_RFEIB: + { + bool increment = (instr.operation == ARMV7_RFEIA) || (instr.operation == ARMV7_RFEIB); + bool wordhigher = (instr.operation == ARMV7_RFEDA) || (instr.operation == ARMV7_RFEIB); + ConditionExecute(il, instr.cond, + il.Intrinsic({}, ARMV7_INTRIN_RFE, { + ReadILOperand(il, op1, addr), + il.Const(1, increment ? 1 : 0), + il.Const(1, wordhigher ? 1 : 0), + il.Const(1, op1.flags.wb ? 1 : 0), + }) + ); + break; + } case ARMV7_BL: ConditionExecute(il, instr.cond, il.Call(il.ConstPointer(4, op1.imm))); break; @@ -807,12 +2352,13 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI ConditionExecute(il, instr.cond, il.Call(ReadILOperand(il, op1, addr, true))); break; case ARMV7_BIC: - ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, - il.And(get_register_size(op2.reg), - ReadRegisterOrPointer(il, op2, addr), - il.Not(get_register_size(op2.reg), - ReadILOperand(il, op3, addr)), flagOperation[instr.setsFlags] - ))); + case ARMV7_BICS: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + BitClearOperand(il, instr, instr.operation == ARMV7_BICS || instr.setsFlags, addr); + }); break; case ARMV7_CLZ: ConditionExecute(addr, instr.cond, instr, il, [&](size_t, Instruction&, LowLevelILFunction& il){ @@ -831,10 +2377,13 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI ReadILOperand(il, op2, addr), IL_FLAGWRITE_ALL)); break; case ARMV7_EOR: - ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, - il.Xor(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op2, addr), - ReadILOperand(il, op3, addr), flagOperation[instr.setsFlags]))); + case ARMV7_EORS: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + LogicalOperand(il, instr, instr.operation == ARMV7_EORS || instr.setsFlags, true, addr); + }); break; case ARMV7_LDM: case ARMV7_LDMIA: @@ -924,6 +2473,7 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI }); break; case ARMV7_LDREX: + case ARMV7_LDAEX: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) { @@ -943,6 +2493,7 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI }); break; case ARMV7_LDREXH: + case ARMV7_LDAEXH: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) { @@ -962,6 +2513,7 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI }); break; case ARMV7_LDREXB: + case ARMV7_LDAEXB: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) { @@ -1001,6 +2553,7 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI }); break; case ARMV7_LDREXD: + case ARMV7_LDAEXD: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) { @@ -1030,25 +2583,69 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI ReadRegisterOrPointer(il, op2, addr), ReadILOperand(il, op3, addr), flagOperation[instr.setsFlags]))); break; - case ARMV7_MCR: - case ARMV7_MCR2: + case ARMV7_STC: + case ARMV7_STC2: + case ARMV7_STCL: + case ARMV7_STC2L: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + CoprocStore(il, op1, op2, op3, + (instr.operation == ARMV7_STCL) || (instr.operation == ARMV7_STC2L), addr); + }); + break; + case ARMV7_LDC: + case ARMV7_LDC2: + case ARMV7_LDCL: + case ARMV7_LDC2L: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + CoprocLoad(il, op1, op2, op3, + (instr.operation == ARMV7_LDCL) || (instr.operation == ARMV7_LDC2L), addr); + }); + break; + case ARMV7_CDP: + case ARMV7_CDP2: + { + uint32_t opc2 = (op6.cls == IMM) ? op6.imm : 0; ConditionExecute(il, instr.cond, - il.Intrinsic({ }, ARMV7_INTRIN_COPROC_SENDONEWORD, + il.Intrinsic({}, ARMV7_INTRIN_COPROC_DATAPROCESSING, { - il.Register(4, op3.reg), il.Const(1, op1.reg), il.Const(1, op2.imm), + il.Const(1, op3.reg), il.Const(1, op4.reg), il.Const(1, op5.reg), - il.Const(1, op6.imm), + il.Const(1, opc2), } ) ); break; - case ARMV7_MCRR: - case ARMV7_MCRR2: - ConditionExecute(il, instr.cond, - il.Intrinsic({ }, ARMV7_INTRIN_COPROC_SENDTWOWORDS, + } + case ARMV7_MCR: + case ARMV7_MCR2: + ConditionExecute(il, instr.cond, + il.Intrinsic({ }, ARMV7_INTRIN_COPROC_SENDONEWORD, + { + il.Register(4, op3.reg), + il.Const(1, op1.reg), + il.Const(1, op2.imm), + il.Const(1, op4.reg), + il.Const(1, op5.reg), + il.Const(1, op6.imm), + } + ) + ); + break; + case ARMV7_MCRR: + case ARMV7_MCRR2: + ConditionExecute(il, instr.cond, + il.Intrinsic({ }, ARMV7_INTRIN_COPROC_SENDTWOWORDS, { il.Register(4, op4.reg), il.Register(4, op3.reg), @@ -1151,6 +2748,89 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI ) ); break; + case ARMV7_MRS: + if (op2.cls != REG_SPEC) + { + il.AddInstruction(il.Unimplemented()); + break; + } + ConditionExecute(il, instr.cond, + il.Intrinsic( + { RegisterOrFlag::Register(op1.reg) }, + ARMV7_INTRIN_MRS, + { il.Const(4, op2.regs) } + ) + ); + break; + case ARMV7_MSR: + if ((op1.cls != REG_SPEC) || ((op2.cls != REG) && (op2.cls != IMM))) + { + il.AddInstruction(il.Unimplemented()); + break; + } + ConditionExecute(il, instr.cond, + il.Intrinsic( + {}, + ARMV7_INTRIN_MSR, + { il.Const(4, op1.regs), ReadILOperand(il, op2, addr) } + ) + ); + break; + case ARMV7_VMSR: + if ((op1.cls != REG_SPEC) || (op2.cls != REG)) + { + il.AddInstruction(il.Unimplemented()); + break; + } + ConditionExecute(il, instr.cond, + il.Intrinsic( + {}, + ARMV7_INTRIN_VMSR, + { il.Const(4, op1.regs), il.Register(get_register_size(op2.reg), op2.reg) } + ) + ); + break; + case ARMV7_VMRS: + if (op2.cls != REG_SPEC) + { + il.AddInstruction(il.Unimplemented()); + break; + } + if (op1.cls == REG_SPEC) + { + if (op1.regs != REGS_APSR_NZCV) + { + il.AddInstruction(il.Unimplemented()); + break; + } + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t, Instruction&, LowLevelILFunction& il) + { + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(LLIL_TEMP(0)) }, + ARMV7_INTRIN_VMRS, + { il.Const(4, op2.regs) } + )); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 30)))); + il.AddInstruction(il.SetFlag(IL_FLAG_C, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 29)))); + il.AddInstruction(il.SetFlag(IL_FLAG_V, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 28)))); + }); + break; + } + if (op1.cls != REG) + { + il.AddInstruction(il.Unimplemented()); + break; + } + ConditionExecute(il, instr.cond, + il.Intrinsic( + { RegisterOrFlag::Register(op1.reg) }, + ARMV7_INTRIN_VMRS, + { il.Const(4, op2.regs) } + ) + ); + break; case ARMV7_MUL: ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, il.Mult(get_register_size(op2.reg), @@ -1159,21 +2839,43 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI instr.setsFlags ? IL_FLAGWRITE_NZ : IL_FLAGWRITE_NONE))); break; case ARMV7_MVN: - ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, - il.Not(get_register_size(op2.reg), - ReadILOperand(il, op2, addr), flagOperation[instr.setsFlags]))); + case ARMV7_MVNS: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + MoveNotOperand(il, instr, instr.operation == ARMV7_MVNS || instr.setsFlags, addr); + }); break; case ARMV7_NOP: - case ARMV7_DSB: + ConditionExecute(il, instr.cond, il.Nop()); + break; case ARMV7_DMB: + { + uint32_t intrinsic = GetDmbIntrinsic(op1.dsbOpt); + if (intrinsic == 0) + il.AddInstruction(il.Unimplemented()); + else + ConditionExecute(il, instr.cond, il.Intrinsic({}, intrinsic, {})); + break; + } + case ARMV7_DSB: + { + uint32_t intrinsic = GetDsbIntrinsic(op1.dsbOpt); + if (intrinsic == 0) + il.AddInstruction(il.Unimplemented()); + else + ConditionExecute(il, instr.cond, il.Intrinsic({}, intrinsic, {})); + break; + } case ARMV7_ISB: - ConditionExecute(il, instr.cond, il.Nop()); + ConditionExecute(il, instr.cond, il.Intrinsic({}, ARMV7_INTRIN_ISB, {})); break; case ARMV7_ORR: ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, il.Or(get_register_size(op1.reg), ReadRegisterOrPointer(il, op2, addr), - ReadILOperand(il, op3, addr), flagOperation[instr.setsFlags]))); + ReadILOperand(il, op3, addr), instr.setsFlags ? IL_FLAGWRITE_CNZ : IL_FLAGWRITE_NONE))); break; case ARMV7_PKHBT: ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, @@ -1246,245 +2948,73 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI } }); break; - case ARMV7_QADD: + case ARMV7_VPUSH: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) { (void) addrSize; - (void) instr; - il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, - il.Add(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op2, addr), - ReadRegisterOrPointer(il, op3, addr) - ))); - il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, - il.Or(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op1, addr), - il.Neg(get_register_size(op1.reg), - il.CompareSignedLessThan(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op1, addr), - ReadRegisterOrPointer(il, op2, addr) - ))))); + StoreVpush(il, instr, addr); }); break; - case ARMV7_QADD16: + case ARMV7_VPOP: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) { (void) addrSize; - (void) instr; - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), - il.Add(2, - il.LowPart(2, - ReadRegisterOrPointer(il, op2, addr)), - il.LowPart(2, - ReadRegisterOrPointer(il, op3, addr)) - ))); - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), - il.Or(2, - il.Register(2, LLIL_TEMP(0)), - il.LowPart(2, - il.Neg(2, - il.CompareSignedLessThan(2, - il.Register(2, LLIL_TEMP(0)), - il.LowPart(2, ReadRegisterOrPointer(il, op2, addr)))))) - )); - - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), - il.Add(2, - il.LowPart(2, il.ArithShiftRight(2, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 16))), - il.LowPart(2, il.ArithShiftRight(2, - ReadRegisterOrPointer(il, op3, addr), - il.Const(1, 16))) - ))); - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), - il.Or(2, - il.Register(2, LLIL_TEMP(1)), - il.LowPart(2, - il.Neg(2, - il.CompareSignedLessThan(get_register_size(op2.reg), - il.Register(2, LLIL_TEMP(1)), - il.LowPart(2, - il.ArithShiftRight(2, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 16))))) - )))); - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, il.Register(2, LLIL_TEMP(1)), il.Const(1, 0x10)), - il.Register(2, LLIL_TEMP(0)) - ))); + LoadVpop(il, instr, addr); }); break; - case ARMV7_UQADD16: + case ARMV7_VSTM: + case ARMV7_VSTMIA: + case ARMV7_VSTMDB: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) { (void) addrSize; (void) instr; - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), - il.Add(2, - il.LowPart(2, - ReadRegisterOrPointer(il, op2, addr)), - il.LowPart(2, - ReadRegisterOrPointer(il, op3, addr)) - ))); - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), - il.Or(2, - il.Register(2, LLIL_TEMP(0)), - il.LowPart(2, - il.Neg(2, - il.CompareUnsignedLessThan(2, - il.Register(2, LLIL_TEMP(0)), - il.LowPart(2, ReadRegisterOrPointer(il, op2, addr)))))) - )); - - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), - il.Add(2, - il.LowPart(2, il.LogicalShiftRight(2, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 16))), - il.LowPart(2, il.LogicalShiftRight(2, - ReadRegisterOrPointer(il, op3, addr), - il.Const(1, 16))) - ))); - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), - il.Or(2, - il.Register(2, LLIL_TEMP(1)), - il.LowPart(2, - il.Neg(2, - il.CompareUnsignedLessThan(get_register_size(op2.reg), - il.Register(2, LLIL_TEMP(1)), - il.LowPart(2, - il.LogicalShiftRight(2, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 16))))) - )))); - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, il.Register(2, LLIL_TEMP(1)), il.Const(1, 0x10)), - il.Register(2, LLIL_TEMP(0)) - ))); + VfpLoadStoreMultiple(il, op1, op2, false, instr.operation == ARMV7_VSTMDB); }); break; - case ARMV7_QADD8: + case ARMV7_VLDM: + case ARMV7_VLDMIA: + case ARMV7_VLDMDB: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) { (void) addrSize; (void) instr; - - for (int i = 0; i < 4; i++) - { - il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), - il.Add(1, - il.LowPart(1, - il.ArithShiftRight(4, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 8*i))), - il.LowPart(1, - il.ArithShiftRight(4, - ReadRegisterOrPointer(il, op3, addr), - il.Const(1, 8*i)))))); - il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), - il.Or(1, - il.Register(1, LLIL_TEMP(i)), - il.Neg(1, - il.CompareSignedLessThan(1, - il.Register(1, LLIL_TEMP(i)), - il.LowPart(1, - il.ArithShiftRight(4, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 8*i)))))))); - } - - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.Or(4, - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(3)), - il.Const(1,24)), - il.ShiftLeft(3, - il.Register(1, LLIL_TEMP(2)), - il.Const(1,16))), - il.Or(2, - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(1)), - il.Const(1,8)), - il.Register(1, LLIL_TEMP(0)))))); + VfpLoadStoreMultiple(il, op1, op2, true, instr.operation == ARMV7_VLDMDB); }); break; + case ARMV7_QADD: + ConditionExecute(il, instr.cond, + il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_QADD, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); + break; + case ARMV7_QADD16: + ConditionExecute(il, instr.cond, + il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_QADD16, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); + break; + case ARMV7_UQADD16: + ConditionExecute(il, instr.cond, + il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_UQADD16, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); + break; + case ARMV7_QADD8: + ConditionExecute(il, instr.cond, + il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_QADD8, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); + break; case ARMV7_UQADD8: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - for (int i = 0; i < 4; i++) - { - il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), - il.Add(1, - il.LowPart(1, - il.LogicalShiftRight(4, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 8*i))), - il.LowPart(1, - il.LogicalShiftRight(4, - ReadRegisterOrPointer(il, op3, addr), - il.Const(1, 8*i)))))); - il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), - il.Or(1, - il.Register(1, LLIL_TEMP(i)), - il.Neg(1, - il.CompareUnsignedLessThan(1, - il.Register(1, LLIL_TEMP(i)), - il.LowPart(1, - il.LogicalShiftRight(4, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 8*i)))))))); - } - - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.Or(4, - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(3)), - il.Const(1,24)), - il.ShiftLeft(3, - il.Register(1, LLIL_TEMP(2)), - il.Const(1,16))), - il.Or(2, - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(1)), - il.Const(1,8)), - il.Register(1, LLIL_TEMP(0)))))); - }); + ConditionExecute(il, instr.cond, + il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_UQADD8, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_QDADD: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, - il.Add(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op2, addr), - il.Mult(4, - ReadRegisterOrPointer(il, op3, addr), - il.Const(1, 2)) - ))); - il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, - il.Or(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op1, addr), - il.Neg(get_register_size(op1.reg), - il.CompareSignedLessThan(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op1, addr), - ReadRegisterOrPointer(il, op2, addr) - ))))); - }); + ConditionExecute(il, instr.cond, + il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_QDADD, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_QASX: ConditionExecute(addrSize, instr.cond, instr, il, @@ -1531,288 +3061,55 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI }); break; case ARMV7_QSAX: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - il.Add(4, - il.LowPart(2, - ReadILOperand(il, op2, addr) - ), - il.ArithShiftRight(2, - ReadILOperand(il, op3, addr), - il.Const(1,16) - ) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), - il.Sub(4, - il.ArithShiftRight(2, - ReadILOperand(il, op2, addr), - il.Const(1,16) - ), - il.LowPart(2, - ReadILOperand(il, op3, addr) - ) - ) - )); - - Saturate(il, LLIL_TEMP(2), il.Register(4, LLIL_TEMP(0)), il.Const(2, 0x7fff), true); - Saturate(il, LLIL_TEMP(3), il.Register(4, LLIL_TEMP(1)), il.Const(2, 0x7fff), true); - - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, - il.Register(2, LLIL_TEMP(3)), - il.Const(1, 16) - ), - il.Register(2, LLIL_TEMP(2)) - ) - )); - }); + ConditionExecute(il, instr.cond, + il.Intrinsic( + { RegisterOrFlag::Register(op1.reg) }, + ARMV7_INTRIN_QSAX, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); + break; + case ARMV7_UQASX: + ConditionExecute(il, instr.cond, + il.Intrinsic( + { RegisterOrFlag::Register(op1.reg) }, + ARMV7_INTRIN_UQASX, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); + break; + case ARMV7_UQSAX: + ConditionExecute(il, instr.cond, + il.Intrinsic( + { RegisterOrFlag::Register(op1.reg) }, + ARMV7_INTRIN_UQSAX, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_QDSUB: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, - il.Sub(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op2, addr), - il.Mult(4, - ReadRegisterOrPointer(il, op3, addr), - il.Const(1, 2)) - ))); - il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, - il.And(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op1, addr), - il.Neg(get_register_size(op1.reg), - il.CompareSignedLessEqual(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op1, addr), - ReadRegisterOrPointer(il, op2, addr) - ))))); - }); + ConditionExecute(il, instr.cond, + il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_QDSUB, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_QSUB: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, - il.Sub(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op2, addr), - ReadRegisterOrPointer(il, op3, addr) - ))); - il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, - il.And(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op1, addr), - il.Neg(get_register_size(op1.reg), - il.CompareSignedLessEqual(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op1, addr), - ReadRegisterOrPointer(il, op2, addr) - ))))); - }); + ConditionExecute(il, instr.cond, + il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_QSUB, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_QSUB16: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), - il.Sub(2, - il.LowPart(2, - ReadRegisterOrPointer(il, op2, addr)), - il.LowPart(2, - ReadRegisterOrPointer(il, op3, addr)) - ))); - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), - il.And(2, - il.Register(2, LLIL_TEMP(0)), - il.LowPart(2, - il.Neg(2, - il.CompareSignedLessEqual(2, - il.Register(2, LLIL_TEMP(0)), - il.LowPart(2, ReadRegisterOrPointer(il, op2, addr)))))) - )); - - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), - il.Sub(2, - il.LowPart(2, il.ArithShiftRight(2, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 16))), - il.LowPart(2, il.ArithShiftRight(2, - ReadRegisterOrPointer(il, op3, addr), - il.Const(1, 16))) - ))); - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), - il.And(2, - il.Register(2, LLIL_TEMP(1)), - il.LowPart(2, - il.Neg(2, - il.CompareSignedLessEqual(get_register_size(op2.reg), - il.Register(2, LLIL_TEMP(1)), - il.LowPart(2, - il.ArithShiftRight(2, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 16))))) - )))); - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, il.Register(2, LLIL_TEMP(1)), il.Const(1, 0x10)), - il.Register(2, LLIL_TEMP(0)) - ))); - }); + ConditionExecute(il, instr.cond, + il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_QSUB16, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_UQSUB16: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), - il.Sub(2, - il.LowPart(2, - ReadRegisterOrPointer(il, op2, addr)), - il.LowPart(2, - ReadRegisterOrPointer(il, op3, addr)) - ))); - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), - il.And(2, - il.Register(2, LLIL_TEMP(0)), - il.LowPart(2, - il.Neg(2, - il.CompareUnsignedLessEqual(2, - il.Register(2, LLIL_TEMP(0)), - il.LowPart(2, ReadRegisterOrPointer(il, op2, addr)))))) - )); - - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), - il.Sub(2, - il.LowPart(2, il.LogicalShiftRight(2, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 16))), - il.LowPart(2, il.LogicalShiftRight(2, - ReadRegisterOrPointer(il, op3, addr), - il.Const(1, 16))) - ))); - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), - il.And(2, - il.Register(2, LLIL_TEMP(1)), - il.LowPart(2, - il.Neg(2, - il.CompareUnsignedLessEqual(get_register_size(op2.reg), - il.Register(2, LLIL_TEMP(1)), - il.LowPart(2, - il.LogicalShiftRight(2, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 16))))) - )))); - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, il.Register(2, LLIL_TEMP(1)), il.Const(1, 0x10)), - il.Register(2, LLIL_TEMP(0)) - ))); - }); + ConditionExecute(il, instr.cond, + il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_UQSUB16, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_QSUB8: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - for (int i = 0; i < 4; i++) - { - il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), - il.Sub(1, - il.LowPart(1, - il.ArithShiftRight(4, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 8*i))), - il.LowPart(1, - il.ArithShiftRight(4, - ReadRegisterOrPointer(il, op3, addr), - il.Const(1, 8*i)))))); - il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), - il.And(1, - il.Register(1, LLIL_TEMP(i)), - il.Neg(1, - il.CompareSignedLessEqual(1, - il.Register(1, LLIL_TEMP(i)), - il.LowPart(1, - il.ArithShiftRight(4, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 8*i)))))))); - } - - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.Or(4, - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(3)), - il.Const(1,24)), - il.ShiftLeft(3, - il.Register(1, LLIL_TEMP(2)), - il.Const(1,16))), - il.Or(2, - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(1)), - il.Const(1,8)), - il.Register(1, LLIL_TEMP(0)))))); - }); + ConditionExecute(il, instr.cond, + il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_QSUB8, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_UQSUB8: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - for (int i = 0; i < 4; i++) - { - il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), - il.Sub(1, - il.LowPart(1, - il.LogicalShiftRight(4, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 8*i))), - il.LowPart(1, - il.LogicalShiftRight(4, - ReadRegisterOrPointer(il, op3, addr), - il.Const(1, 8*i)))))); - il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), - il.And(1, - il.Register(1, LLIL_TEMP(i)), - il.Neg(1, - il.CompareSignedLessEqual(1, - il.Register(1, LLIL_TEMP(i)), - il.LowPart(1, - il.LogicalShiftRight(4, - ReadRegisterOrPointer(il, op2, addr), - il.Const(1, 8*i)))))))); - } - - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.Or(4, - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(3)), - il.Const(1,24)), - il.ShiftLeft(3, - il.Register(1, LLIL_TEMP(2)), - il.Const(1,16))), - il.Or(2, - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(1)), - il.Const(1,8)), - il.Register(1, LLIL_TEMP(0)))))); - }); + ConditionExecute(il, instr.cond, + il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_UQSUB8, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_RBIT: ConditionExecute(addr, instr.cond, instr, il, [&](size_t, Instruction&, LowLevelILFunction& il){ @@ -1860,18 +3157,12 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI break; case ARMV7_ROR: case ARMV7_RORS: - ConditionExecute(il, instr.cond, - SetRegisterOrBranch(il, op1.reg, - il.RotateRight(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op2, addr), - il.And(1, - ReadILOperand(il, op3, addr), - il.Const(1, 0xff) - ), - flagOperation[instr.setsFlags] - ) - ) - ); + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + RotateRightOperand(il, instr, instr.operation == ARMV7_RORS || instr.setsFlags, addr); + }); break; case ARMV7_RRX: ConditionExecute(addrSize, instr.cond, instr, il, @@ -1888,46 +3179,17 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI )); }); break; - case ARMV7_SADD16: //TODO: APSR - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - il.And(2, - il.Add(2, - ReadILOperand(il, op2, addr), - ReadILOperand(il, op3, addr) - ), - il.Const(2, 0xffff) - ))); - il.AddInstruction( - il.SetRegister(4, LLIL_TEMP(1), - il.And(2, - il.Add(2, - il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), - il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) - ), - il.Const(2, 0xffff) - ))); - il.AddInstruction( - il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, - il.And(2, - il.Register(4, LLIL_TEMP(1)), il.Const(2, 0xffff) - ), - il.Const(1, 16) - ), - il.And(2, - il.Register(4, LLIL_TEMP(0)), - il.Const(2, 0xffff) - ) - ) - )); - }); + case ARMV7_SEL: + ConditionExecute(il, instr.cond, + il.Intrinsic( + { RegisterOrFlag::Register(op1.reg) }, + ARMV7_INTRIN_SEL, + { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) } + ) + ); + break; + case ARMV7_SADD16: + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_SADD16, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_UADD16: //TODO: APSR ConditionExecute(addrSize, instr.cond, instr, il, @@ -1970,71 +3232,8 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI )); }); break; - case ARMV7_SADD8: //TODO: APSR - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - il.And(1, - il.Add(1, - ReadILOperand(il, op2, addr), - ReadILOperand(il, op3, addr) - ), - il.Const(1, 0xff) - ))); - il.AddInstruction( - il.SetRegister(1, LLIL_TEMP(1), - il.And(1, - il.Add(1, - il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 8)), - il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 8)) - ), - il.Const(1, 0xff) - ))); - il.AddInstruction( - il.SetRegister(1, LLIL_TEMP(2), - il.And(1, - il.Add(1, - il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), - il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) - ), - il.Const(1, 0xff) - ))); - il.AddInstruction( - il.SetRegister(1, LLIL_TEMP(3), - il.And(1, - il.Add(1, - il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 24)), - il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 24)) - ), - il.Const(1, 0xff) - ))); - il.AddInstruction( - il.SetRegister(4, op1.reg, - il.Or(4, - il.Or(4, - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(3)), - il.Const(1, 24) - ), - il.ShiftLeft(3, - il.Register(1, LLIL_TEMP(2)), - il.Const(1, 16) - ) - ), - il.Or(4, - il.ShiftLeft(2, - il.Register(1, LLIL_TEMP(1)), - il.Const(1, 8) - ), - il.Register(1, LLIL_TEMP(0)) - ) - ) - )); - }); + case ARMV7_SADD8: + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_SADD8, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_UADD8: ConditionExecute(addrSize, instr.cond, instr, il, @@ -2086,14 +3285,14 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI il.Register(1, LLIL_TEMP(3)), il.Const(1, 24) ), - il.ShiftLeft(3, - il.Register(1, LLIL_TEMP(2)), + il.ShiftLeft(4, + il.ZeroExtend(4, il.Register(1, LLIL_TEMP(2))), il.Const(1, 16) ) ), il.Or(4, - il.ShiftLeft(2, - il.Register(1, LLIL_TEMP(1)), + il.ShiftLeft(4, + il.ZeroExtend(4, il.Register(1, LLIL_TEMP(1))), il.Const(1, 8) ), il.Register(1, LLIL_TEMP(0)) @@ -2440,8 +3639,8 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI il.Register(4, op3.reg) ), il.Add(8, - il.Register(4, op2.reg), - il.Register(4, op1.reg) + il.ZeroExtend(8, il.Register(4, op2.reg)), + il.ZeroExtend(8, il.Register(4, op1.reg)) ) ) ) @@ -2517,7 +3716,45 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI )); }); break; - case ARMV7_USUB16: //TODO: APSR + case ARMV7_USUB16: + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_USUB16, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); + break; + case ARMV7_SSUB8: + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_SSUB8, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); + break; + case ARMV7_USUB8: + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_USUB8, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); + break; + case ARMV7_SBC: + case ARMV7_SBCS: + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.SubBorrow(get_register_size(op2.reg), + ReadILOperand(il, op2, addr), + ReadRegisterOrPointer(il, op3, addr), + il.Not(1,il.Flag(IL_FLAG_C))), + flagOperation[instr.setsFlags])); + break; + case ARMV7_SBFX: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.ArithShiftRight(get_register_size(op1.reg), + il.ShiftLeft(get_register_size(op2.reg), + ReadILOperand(il, op2, addr), + il.Const(1, (get_register_size(op2.reg) * 8) - op3.imm - op4.imm)), + il.Const(1, (get_register_size(op2.reg) * 8) - op4.imm)))); + break; + case ARMV7_SDIV: + if (op3.cls == NONE) + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.DivSigned(get_register_size(op1.reg), ReadRegisterOrPointer(il, op1, addr), ReadRegisterOrPointer(il, op2, addr)))); + else + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.DivSigned(get_register_size(op2.reg), ReadRegisterOrPointer(il, op2, addr), ReadRegisterOrPointer(il, op3, addr)))); + break; + case ARMV7_SHADD16: + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_SHADD16, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); + break; + case ARMV7_UHADD16: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) { @@ -2525,295 +3762,27 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI (void) instr; il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - il.And(2, - il.Sub(2, - ReadILOperand(il, op2, addr), - ReadILOperand(il, op3, addr) - ), - il.Const(2, 0xffff) - ))); - il.AddInstruction( - il.SetRegister(4, LLIL_TEMP(1), - il.And(2, - il.Sub(2, - il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), - il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) - ), - il.Const(2, 0xffff) - ))); - il.AddInstruction( - il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, - il.And(2, - il.Register(4, LLIL_TEMP(1)), il.Const(2, 0xffff) - ), - il.Const(1, 16) - ), - il.And(2, - il.Register(4, LLIL_TEMP(0)), - il.Const(2, 0xffff) - ) - ) - )); - }); - break; - case ARMV7_SSUB8: //TODO: APSR - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - il.And(1, - il.Sub(1, - ReadILOperand(il, op2, addr), - ReadILOperand(il, op3, addr) - ), - il.Const(1, 0xff) - ))); - il.AddInstruction( - il.SetRegister(1, LLIL_TEMP(1), - il.And(1, - il.Sub(1, - il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 8)), - il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 8)) - ), - il.Const(1, 0xff) - ))); - il.AddInstruction( - il.SetRegister(1, LLIL_TEMP(2), - il.And(1, - il.Sub(1, - il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), - il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) - ), - il.Const(1, 0xff) - ))); - il.AddInstruction( - il.SetRegister(1, LLIL_TEMP(3), - il.And(1, - il.Sub(1, - il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 24)), - il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 24)) - ), - il.Const(1, 0xff) - ))); - il.AddInstruction( - il.SetRegister(4, op1.reg, - il.Or(4, - il.Or(4, - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(3)), - il.Const(1, 24) - ), - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(2)), - il.Const(1, 16) - ) - ), - il.Or(4, - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(1)), - il.Const(1, 8) - ), - il.Register(1, LLIL_TEMP(0)) - ) - ) - )); - }); - break; - case ARMV7_USUB8: //TODO: APSR - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - il.And(1, - il.Sub(1, - ReadILOperand(il, op2, addr), - ReadILOperand(il, op3, addr) - ), - il.Const(1, 0xff) - ))); - il.AddInstruction( - il.SetRegister(1, LLIL_TEMP(1), - il.And(1, - il.Sub(1, - il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 8)), - il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 8)) - ), - il.Const(1, 0xff) - ))); - il.AddInstruction( - il.SetRegister(1, LLIL_TEMP(2), - il.And(1, - il.Sub(1, - il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), - il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) - ), - il.Const(1, 0xff) - ))); - il.AddInstruction( - il.SetRegister(1, LLIL_TEMP(3), - il.And(1, - il.Sub(1, - il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 24)), - il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 24)) - ), - il.Const(1, 0xff) - ))); - il.AddInstruction( - il.SetRegister(4, op1.reg, - il.Or(4, - il.Or(4, - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(3)), - il.Const(1, 24) - ), - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(2)), - il.Const(1, 16) - ) - ), - il.Or(4, - il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(1)), - il.Const(1, 8) - ), - il.Register(1, LLIL_TEMP(0)) - ) - ) - )); - }); - break; - case ARMV7_SBC: - case ARMV7_SBCS: - ConditionExecute(il, instr.cond, - SetRegisterOrBranch(il, op1.reg, - il.SubBorrow(get_register_size(op2.reg), - ReadILOperand(il, op2, addr), - ReadRegisterOrPointer(il, op3, addr), - il.Not(1,il.Flag(IL_FLAG_C))), - flagOperation[instr.setsFlags])); - break; - case ARMV7_SBFX: - ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, - il.ArithShiftRight(get_register_size(op1.reg), - il.ShiftLeft(get_register_size(op2.reg), - ReadILOperand(il, op2, addr), - il.Const(1, (get_register_size(op2.reg) * 8) - op3.imm - op4.imm)), - il.Const(1, (get_register_size(op2.reg) * 8) - op4.imm)))); - break; - case ARMV7_SDIV: - if (op3.cls == NONE) - ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, - il.DivSigned(get_register_size(op1.reg), ReadRegisterOrPointer(il, op1, addr), ReadRegisterOrPointer(il, op2, addr)))); - else - ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, - il.DivSigned(get_register_size(op2.reg), ReadRegisterOrPointer(il, op2, addr), ReadRegisterOrPointer(il, op3, addr)))); - break; - case ARMV7_SHADD16: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - il.Add(4, - il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), - il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), - il.Add(4, - il.LowPart(2, ReadILOperand(il, op2, addr)), - il.LowPart(2, ReadILOperand(il, op3, addr)) - ) - )); - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,16)), - il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)) - ) - )); - }); - break; - case ARMV7_UHADD16: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - il.Add(4, - il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), - il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), - il.Add(4, - il.LowPart(2, ReadILOperand(il, op2, addr)), - il.LowPart(2, ReadILOperand(il, op3, addr)) - ) - )); - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,16)), - il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)) - ) - )); + il.Add(4, + il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Add(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,16)), + il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)) + ) + )); }); break; case ARMV7_SHADD8: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - il.Add(4, - il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 24)), - il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 24)) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), - il.Add(4, - il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16))), - il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16))) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(2), - il.Add(4, - il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 8))), - il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 8))) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(3), - il.Add(4, - il.LowPart(1, ReadILOperand(il, op2, addr)), - il.LowPart(1, ReadILOperand(il, op3, addr)) - ) - )); - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.Or(4, - il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,24)), - il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)), il.Const(1,16)) - ), - il.Or(4, - il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(2)), il.Const(1,1)), il.Const(1,8)), - il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(3)), il.Const(1,1)) - ) - ) - )); - }); + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_SHADD8, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_UHADD8: ConditionExecute(addrSize, instr.cond, instr, il, @@ -2861,148 +3830,16 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI }); break; case ARMV7_SHSUB16: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - il.Sub(4, - il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), - il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), - il.Sub(4, - il.LowPart(2, ReadILOperand(il, op2, addr)), - il.LowPart(2, ReadILOperand(il, op3, addr)) - ) - )); - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,16)), - il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)) - ) - )); - }); + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_SHSUB16, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_UHSUB16: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - il.Sub(4, - il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), - il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), - il.Sub(4, - il.LowPart(2, ReadILOperand(il, op2, addr)), - il.LowPart(2, ReadILOperand(il, op3, addr)) - ) - )); - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,16)), - il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)) - ) - )); - }); + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_UHSUB16, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_SHSUB8: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - il.Sub(4, - il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 24)), - il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 24)) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), - il.Sub(4, - il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16))), - il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16))) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(2), - il.Sub(4, - il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 8))), - il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 8))) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(3), - il.Sub(4, - il.LowPart(1, ReadILOperand(il, op2, addr)), - il.LowPart(1, ReadILOperand(il, op3, addr)) - ) - )); - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.Or(4, - il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,24)), - il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)), il.Const(1,16)) - ), - il.Or(4, - il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(2)), il.Const(1,1)), il.Const(1,8)), - il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(3)), il.Const(1,1)) - ) - ) - )); - }); + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_SHSUB8, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_UHSUB8: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - il.Sub(4, - il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 24)), - il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 24)) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), - il.Sub(4, - il.LowPart(1, il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16))), - il.LowPart(1, il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16))) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(2), - il.Sub(4, - il.LowPart(1, il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 8))), - il.LowPart(1, il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 8))) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(3), - il.Sub(4, - il.LowPart(1, ReadILOperand(il, op2, addr)), - il.LowPart(1, ReadILOperand(il, op3, addr)) - ) - )); - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.Or(4, - il.ShiftLeft(4, il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,24)), - il.ShiftLeft(4, il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)), il.Const(1,16)) - ), - il.Or(4, - il.ShiftLeft(4, il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(2)), il.Const(1,1)), il.Const(1,8)), - il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(3)), il.Const(1,1)) - ) - ) - )); - }); + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_UHSUB8, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_SMLABB: ConditionExecute(addrSize, instr.cond, instr, il, @@ -3170,65 +4007,8 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI }); break; case ARMV7_SMLALBB: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), - il.Add(8, - il.SignExtend(8, - il.Mult(4, - il.LowPart(2, ReadILOperand(il, op2, addr)), - il.LowPart(2, ReadILOperand(il, op3, addr)) - ) - ), - ReadILOperand(il, op4, addr) - ) - )); - }); - break; case ARMV7_SMLALBT: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), - il.Add(8, - il.SignExtend(8, - il.Mult(4, - il.LowPart(2, ReadILOperand(il, op2, addr)), - il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1, 16)) - ) - ), - ReadILOperand(il, op4, addr) - ) - )); - }); - break; case ARMV7_SMLALTB: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), - il.Add(8, - il.SignExtend(8, - il.Mult(4, - il.ArithShiftRight(2, ReadILOperand(il, op2, addr), il.Const(1, 16)), - il.LowPart(2, ReadILOperand(il, op3, addr)) - ) - ), - ReadILOperand(il, op4, addr) - ) - )); - }); - break; case ARMV7_SMLALTT: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) @@ -3236,17 +4016,20 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI (void) addrSize; (void) instr; - il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + bool nTop = instr.operation == ARMV7_SMLALTB || instr.operation == ARMV7_SMLALTT; + bool mTop = instr.operation == ARMV7_SMLALBT || instr.operation == ARMV7_SMLALTT; + ExprId source1 = nTop + ? il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1, 16)) + : il.LowPart(2, ReadILOperand(il, op3, addr)); + ExprId source2 = mTop + ? il.ArithShiftRight(2, ReadILOperand(il, op4, addr), il.Const(1, 16)) + : il.LowPart(2, ReadILOperand(il, op4, addr)); + + il.AddInstruction(il.SetRegisterSplit(4, op2.reg, op1.reg, il.Add(8, il.SignExtend(8, - il.Mult(4, - il.ArithShiftRight(2, ReadILOperand(il, op2, addr), il.Const(1, 16)), - il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1, 16)) - ) - ), - ReadILOperand(il, op4, addr) - ) - )); + il.Mult(4, source1, source2)), + il.RegisterSplit(4, op2.reg, op1.reg)))); }); break; case ARMV7_SMLALD: @@ -3563,7 +4346,11 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI { (void) addrSize; (void) instr; - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), il.ArithShiftRight(8, il.Mult(8, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)), il.Const(1, 32)))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.LowPart(4, + il.ArithShiftRight(8, + il.MultDoublePrecSigned(4, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)), + il.Const(1, 32))))); il.AddInstruction(il.SetRegister(4, op1.reg, il.Add(4, il.Register(4, LLIL_TEMP(0)), @@ -3578,13 +4365,16 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI { (void) addrSize; (void) instr; - il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), il.Add(8, il.Mult(8, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)), il.Const(8, 0x80000000)))); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + il.Add(8, + il.MultDoublePrecSigned(4, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)), + il.Const(8, 0x80000000)))); il.AddInstruction(il.SetRegister(4, op1.reg, il.Add(4, - il.ArithShiftRight(4, - il.Register(8, LLIL_TEMP(0)), - il.Const(1, 32) - ), + il.LowPart(4, + il.ArithShiftRight(8, + il.Register(8, LLIL_TEMP(0)), + il.Const(1, 32))), ReadILOperand(il, op4, addr) ) )); @@ -3596,16 +4386,17 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI { (void) addrSize; (void) instr; - il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), il.Mult(8, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)))); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + il.MultDoublePrecSigned(4, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)))); il.AddInstruction(il.SetRegister(8, LLIL_TEMP(1), il.ShiftLeft(8, ReadILOperand(il, op4, addr), il.Const(1, 32)))); il.AddInstruction(il.SetRegister(4, op1.reg, - il.ArithShiftRight(4, - il.Sub(8, - il.Register(8, LLIL_TEMP(1)), - il.Register(8, LLIL_TEMP(0)) - ), - il.Const(1, 32) - ) + il.LowPart(4, + il.ArithShiftRight(8, + il.Sub(8, + il.Register(8, LLIL_TEMP(1)), + il.Register(8, LLIL_TEMP(0)) + ), + il.Const(1, 32))) )); }); break; @@ -3615,19 +4406,20 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI { (void) addrSize; (void) instr; - il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), il.Mult(8, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)))); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + il.MultDoublePrecSigned(4, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)))); il.AddInstruction(il.SetRegister(8, LLIL_TEMP(1), il.ShiftLeft(8, ReadILOperand(il, op4, addr), il.Const(1, 32)))); il.AddInstruction(il.SetRegister(4, op1.reg, - il.ArithShiftRight(4, - il.Add(8, - il.Sub(8, - il.Register(8, LLIL_TEMP(1)), - il.Register(8, LLIL_TEMP(0)) + il.LowPart(4, + il.ArithShiftRight(8, + il.Add(8, + il.Sub(8, + il.Register(8, LLIL_TEMP(1)), + il.Register(8, LLIL_TEMP(0)) + ), + il.Const(8, 0x80000000) ), - il.Const(8, 0x80000000) - ), - il.Const(1, 32) - ) + il.Const(1, 32))) )); }); break; @@ -3692,7 +4484,8 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI (void) addrSize; (void) instr; - il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), il.Mult(8, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)))); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + il.MultDoublePrecSigned(4, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)))); il.AddInstruction(il.SetRegister(4, op1.reg, il.ArithShiftRight(4, il.Register(8, LLIL_TEMP(0)), il.Const(1, 32)))); }); break; @@ -3703,7 +4496,10 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI (void) addrSize; (void) instr; - il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), il.Add(8, il.Mult(8, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)), il.Const(4, 0x80000000)))); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + il.Add(8, + il.MultDoublePrecSigned(4, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)), + il.Const(8, 0x80000000)))); il.AddInstruction(il.SetRegister(4, op1.reg, il.ArithShiftRight(4, il.Register(8, LLIL_TEMP(0)), il.Const(1, 32)))); }); break; @@ -3932,16 +4728,11 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI { (void) addrSize; (void) instr; - uint32_t lowestSetBit = 1337; uint32_t numToLoad = 0; for (uint32_t j = 0; j < 15; j++) { if (((op2.reg >> j) & 1) == 1) - { numToLoad++; - if (j < lowestSetBit) - lowestSetBit = j; - } } //Set base address il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), @@ -3955,24 +4746,12 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI { if (((op2.reg >> j) & 1) == 1) { - if (j == op1.reg && op1.flags.wb == 1 && j != lowestSetBit) - { - il.AddInstruction( - il.Store(4, - il.Register(4, LLIL_TEMP(0)), - il.Unimplemented() - ) - ); - } - else - { - il.AddInstruction( - il.Store(4, - il.Register(4, LLIL_TEMP(0)), - il.Register(get_register_size((enum Register)j), j) - ) - ); - } + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(get_register_size((enum Register)j), j) + ) + ); il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), il.Add(4, il.Register(4, LLIL_TEMP(0)), @@ -4009,16 +4788,11 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI { (void) addrSize; (void) instr; - uint32_t lowestSetBit = 1337; uint32_t numToLoad = 0; for (uint32_t j = 0; j < 15; j++) { if (((op2.reg >> j) & 1) == 1) - { numToLoad++; - if (j < lowestSetBit) - lowestSetBit = j; - } } //Set base address il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), @@ -4032,24 +4806,12 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI { if (((op2.reg >> j) & 1) == 1) { - if (j == op1.reg && op1.flags.wb == 1 && j != lowestSetBit) - { - il.AddInstruction( - il.Store(4, - il.Register(4, LLIL_TEMP(0)), - il.Unimplemented() - ) - ); - } - else - { - il.AddInstruction( - il.Store(4, - il.Register(4, LLIL_TEMP(0)), - il.Register(get_register_size((enum Register)j), j) - ) - ); - } + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(get_register_size((enum Register)j), j) + ) + ); il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), il.Add(4, il.Register(4, LLIL_TEMP(0)), @@ -4086,16 +4848,11 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI { (void) addrSize; (void) instr; - uint32_t lowestSetBit = 1337; uint32_t numToLoad = 0; for (uint32_t j = 0; j < 15; j++) { if (((op2.reg >> j) & 1) == 1) - { numToLoad++; - if (j < lowestSetBit) - lowestSetBit = j; - } } //Set base address il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), @@ -4109,24 +4866,12 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI { if (((op2.reg >> j) & 1) == 1) { - if (j == op1.reg && op1.flags.wb == 1 && j != lowestSetBit) - { - il.AddInstruction( - il.Store(4, - il.Register(4, LLIL_TEMP(0)), - il.Unimplemented() - ) - ); - } - else - { - il.AddInstruction( - il.Store(4, - il.Register(4, LLIL_TEMP(0)), - il.Register(get_register_size((enum Register)j), j) - ) - ); - } + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(get_register_size((enum Register)j), j) + ) + ); il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), il.Add(4, il.Register(4, LLIL_TEMP(0)), @@ -4164,16 +4909,11 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI { (void) addrSize; (void) instr; - uint32_t lowestSetBit = 1337; uint32_t numToLoad = 0; for (uint32_t j = 0; j < 15; j++) { if (((op2.reg >> j) & 1) == 1) - { numToLoad++; - if (j < lowestSetBit) - lowestSetBit = j; - } } //Set base address il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), @@ -4184,24 +4924,12 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI { if (((op2.reg >> j) & 1) == 1) { - if (j == op1.reg && op1.flags.wb == 1 && j != lowestSetBit) - { - il.AddInstruction( - il.Store(4, - il.Register(4, LLIL_TEMP(0)), - il.Unimplemented() - ) - ); - } - else - { - il.AddInstruction( - il.Store(4, - il.Register(4, LLIL_TEMP(0)), - il.Register(get_register_size((enum Register)j), j) - ) - ); - } + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(get_register_size((enum Register)j), j) + ) + ); il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), il.Add(4, il.Register(4, LLIL_TEMP(0)), @@ -4233,6 +4961,7 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI }); break; case ARMV7_STREX: + case ARMV7_STLEX: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) { @@ -4242,6 +4971,7 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI }); break; case ARMV7_STREXH: + case ARMV7_STLEXH: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) { @@ -4251,6 +4981,7 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI }); break; case ARMV7_STREXB: + case ARMV7_STLEXB: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) { @@ -4290,6 +5021,7 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI }); break; case ARMV7_STREXD: + case ARMV7_STLEXD: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) { @@ -4314,6 +5046,12 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI ReadRegisterOrPointer(il, op2, addr), ReadILOperand(il, op3, addr), flagOperation[instr.setsFlags]))); break; + case ARMV7_HVC: + ConditionExecute(il, instr.cond, il.Intrinsic({}, ARMV7_INTRIN_HVC, {il.Const(2, op1.imm)})); + break; + case ARMV7_SMC: + ConditionExecute(il, instr.cond, il.Intrinsic({}, ARMV7_INTRIN_SMC, {il.Const(1, op1.imm)})); + break; case ARMV7_SVC: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) @@ -4441,45 +5179,7 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI }); break; case ARMV7_SXTAB16: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - ReadILOperand(il, op3, addr) - )); - - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, - il.Add(2, - il.LowPart(2, - ReadILOperand(il, op2, addr) - ), - il.SignExtend(2, - il.LowPart(1, - il.ArithShiftRight(4, - il.Register(4, LLIL_TEMP(0)), - il.Const(1, 16) - ) - ) - ) - ), - il.Const(1, 16) - ), - il.Add(2, - il.LowPart(2, - ReadILOperand(il, op2, addr) - ), - il.SignExtend(2, - il.Register(1, LLIL_TEMP(0)) - ) - ) - ) - )); - }); + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_SXTAB16, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_SXTAH: ConditionExecute(addrSize, instr.cond, instr, il, @@ -4505,35 +5205,7 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI il.Const(get_register_size(op1.reg), (get_register_size(op1.reg)*8)-8)))); break; case ARMV7_SXTB16: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), - ReadILOperand(il, op2, addr) - )); - - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, - il.SignExtend(2, - il.LowPart(1, - il.ArithShiftRight(4, - il.Register(4, LLIL_TEMP(0)), - il.Const(1, 16) - ) - ) - ), - il.Const(1, 16) - ), - il.SignExtend(2, - il.Register(1, LLIL_TEMP(0)) - ) - ) - )); - }); + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_SXTB16, { ReadILOperand(il, op2, addr) })); break; case ARMV7_SXTH: { @@ -4564,14 +5236,20 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI break; */ case ARMV7_TEQ: - ConditionExecute(il, instr.cond, il.Xor(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op1, addr), - ReadILOperand(il, op2, addr), IL_FLAGWRITE_CNZ)); + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + TestEquivalenceOperand(il, instr, addr); + }); break; case ARMV7_TST: - ConditionExecute(il, instr.cond, il.And(get_register_size(op1.reg), - ReadRegisterOrPointer(il, op1, addr), - ReadILOperand(il, op2, addr), IL_FLAGWRITE_ALL)); + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + TestOperand(il, instr, addr); + }); break; case ARMV7_UBFX: ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, @@ -4580,121 +5258,10 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI il.Const(get_register_size(op2.reg), BITMASK(op4.imm, 0))))); break; case ARMV7_USAD8: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - for (int i = 0; i < 4; i++) - { - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i), - il.Sub(4, - il.LowPart(1, - il.ArithShiftRight(4, - ReadILOperand(il, op2, addr), - il.Const(1, i*8) - ) - ), - il.LowPart(1, - il.ArithShiftRight(4, - ReadILOperand(il, op3, addr), - il.Const(1, i*8) - ) - ) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i), - il.Sub(4, - il.Xor(4, - il.Register(4, LLIL_TEMP(i)), - il.ArithShiftRight(4, - il.Register(4, LLIL_TEMP(i)), - il.Const(1, 31) - ) - ), - il.ArithShiftRight(4, - il.Register(4, LLIL_TEMP(i)), - il.Const(1, 31) - ) - ) - )); - } - il.AddInstruction(il.SetRegister(4, op1.reg, - il.LowPart(4, - il.Add(4, - il.Add(4, - il.Register(4, LLIL_TEMP(0)), - il.Register(4, LLIL_TEMP(1)) - ), - il.Add(4, - il.Register(4, LLIL_TEMP(2)), - il.Register(4, LLIL_TEMP(3)) - ) - ) - ) - )); - }); + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_USAD8, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_USADA8: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - for (int i = 0; i < 4; i++) - { - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i), - il.Sub(4, - il.LowPart(1, - il.ArithShiftRight(4, - ReadILOperand(il, op2, addr), - il.Const(1, i*8) - ) - ), - il.LowPart(1, - il.ArithShiftRight(4, - ReadILOperand(il, op3, addr), - il.Const(1, i*8) - ) - ) - ) - )); - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i), - il.Sub(4, - il.Xor(4, - il.Register(4, LLIL_TEMP(i)), - il.ArithShiftRight(4, - il.Register(4, LLIL_TEMP(i)), - il.Const(1, 31) - ) - ), - il.ArithShiftRight(4, - il.Register(4, LLIL_TEMP(i)), - il.Const(1, 31) - ) - ) - )); - } - il.AddInstruction(il.SetRegister(4, op1.reg, - il.LowPart(4, - il.Add(4, - ReadILOperand(il, op4, addr), - il.Add(4, - il.Add(4, - il.Register(4, LLIL_TEMP(0)), - il.Register(4, LLIL_TEMP(1)) - ), - il.Add(4, - il.Register(4, LLIL_TEMP(2)), - il.Register(4, LLIL_TEMP(3)) - ) - ) - ) - ) - )); - }); + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_USADA8, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr), ReadILOperand(il, op4, addr) })); break; case ARMV7_USAT: ConditionExecute(addr, instr.cond, instr, il, [&](size_t, Instruction&, LowLevelILFunction& il){ @@ -4787,39 +5354,7 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI GetShiftedRegister(il, op3), il.Const(get_register_size(op3.reg), 0xff))))); break; case ARMV7_UXTAB16: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), ReadILOperand(il, op3, addr))); - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, - il.Add(4, - il.LowPart(2, ReadILOperand(il, op2, addr)), - il.ZeroExtend(2, il.Register(1, LLIL_TEMP(0))) - ), - il.Const(1, 32) - ), - il.Add(4, - il.LogicalShiftRight(2, - ReadILOperand(il, op2, addr), - il.Const(1, 16) - ), - il.ZeroExtend(2, - il.LowPart(1, - il.LogicalShiftRight(2, - il.Register(4, LLIL_TEMP(0)), - il.Const(1, 16) - ) - ) - ) - ) - ) - )); - }); + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_UXTAB16, { ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr) })); break; case ARMV7_UXTAH: ConditionExecute(addrSize, instr.cond, instr, il, @@ -4845,30 +5380,7 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI il.And(get_register_size(op2.reg), GetShiftedRegister(il, op2), il.Const(get_register_size(op2.reg), 0xff)))); break; case ARMV7_UXTB16: - ConditionExecute(addrSize, instr.cond, instr, il, - [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) - { - (void) addrSize; - (void) instr; - - il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), ReadILOperand(il, op2, addr))); - il.AddInstruction(il.SetRegister(4, op1.reg, - il.Or(4, - il.ShiftLeft(4, - il.ZeroExtend(2, - il.LowPart(1, - il.LogicalShiftRight(2, - il.Register(4, LLIL_TEMP(0)), - il.Const(1, 16) - ) - ) - ), - il.Const(1, 16) - ), - il.ZeroExtend(2, il.Register(1, LLIL_TEMP(0))) - ) - )); - }); + ConditionExecute(il, instr.cond, il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, ARMV7_INTRIN_UXTB16, { ReadILOperand(il, op2, addr) })); break; case ARMV7_UXTH: ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, @@ -4886,6 +5398,66 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI il.DivUnsigned(get_register_size(op2.reg), ReadRegisterOrPointer(il, op2, addr), ReadRegisterOrPointer(il, op3, addr)))); break; case ARMV7_VCVT: + if (op3.cls == IMM) + { + size_t destSize = get_register_size(op1.reg); + size_t sourceSize = GetDataTypeSize(instr.dataType2); + if (!sourceSize) + sourceSize = get_register_size(op2.reg); + auto source = [&]() { + ExprId value = il.Register(get_register_size(op2.reg), op2.reg); + if (sourceSize < get_register_size(op2.reg)) + value = il.LowPart(sourceSize, value); + return value; + }; + switch (instr.dataType) + { + case DT_S16: + case DT_S32: + ConditionExecute(il, instr.cond, il.SetRegister(destSize, op1.reg, + il.FloatToInt(destSize, + il.RoundToInt(destSize, + il.FloatMult(destSize, + il.Register(destSize, op2.reg), + FixedPointScale(il, destSize, op3.imm)))))); + break; + case DT_U16: + case DT_U32: + ConditionExecute(il, instr.cond, il.SetRegister(destSize, op1.reg, + il.ZeroExtend(destSize, + il.FloatToInt(destSize, + il.RoundToInt(destSize, + il.FloatMult(destSize, + il.Register(destSize, op2.reg), + FixedPointScale(il, destSize, op3.imm))))))); + break; + case DT_F32: + case DT_F64: + switch (instr.dataType2) + { + case DT_S16: + case DT_S32: + ConditionExecute(il, instr.cond, il.SetRegister(destSize, op1.reg, + il.FloatDiv(destSize, + il.IntToFloat(destSize, il.SignExtend(destSize, source())), + FixedPointScale(il, destSize, op3.imm)))); + break; + case DT_U16: + case DT_U32: + ConditionExecute(il, instr.cond, il.SetRegister(destSize, op1.reg, + il.FloatDiv(destSize, + il.IntToFloat(destSize, il.ZeroExtend(destSize, source())), + FixedPointScale(il, destSize, op3.imm)))); + break; + default: + break; + } + break; + default: + break; + } + break; + } switch (instr.dataType) { // To integer cases @@ -4938,36 +5510,317 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI break; } break; - default: + default: + break; + } + break; + case ARMV7_VADD: + if (op1.cls != REG || op2.cls != REG || op3.cls != REG) + { + ConditionExecute(il, instr.cond, il.Unimplemented()); + break; + } + + if ((instr.dataType == DT_F32) || (instr.dataType == DT_F64)) + { + ConditionExecute(il, instr.cond, + il.SetRegister(get_register_size(op1.reg), op1.reg, + il.FloatAdd(get_register_size(op1.reg), + il.Register(get_register_size(op2.reg), op2.reg), + il.Register(get_register_size(op3.reg), op3.reg) + ) + ) + ); + } + else + { + size_t size = get_register_size(op1.reg); + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.Add(size, + il.Register(size, op2.reg), + il.Register(size, op3.reg)), + flagOperation[instr.setsFlags])); + } + break; + case ARMV7_VCMP: + case ARMV7_VCMPE: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + FloatCompare(il, instr); + }); + break; + case ARMV7_VCEQ: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + VectorCompareEqual(il, instr); + }); + break; + case ARMV7_VCGT: + ConditionExecute(il, instr.cond, VectorCompareGreaterThan(il, instr)); + break; + case ARMV7_VAND: + if (op1.cls != REG || op2.cls != REG || op3.cls != REG) + { + ConditionExecute(il, instr.cond, il.Unimplemented()); + break; + } + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.And(get_register_size(op1.reg), + il.Register(get_register_size(op2.reg), op2.reg), + il.Register(get_register_size(op3.reg), op3.reg)), + flagOperation[instr.setsFlags])); + break; + case ARMV7_VORR: + if (op1.cls != REG || op2.cls != REG || op3.cls != REG) + { + ConditionExecute(il, instr.cond, il.Unimplemented()); break; } + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.Or(get_register_size(op1.reg), + il.Register(get_register_size(op2.reg), op2.reg), + il.Register(get_register_size(op3.reg), op3.reg)), + flagOperation[instr.setsFlags])); break; - case ARMV7_VADD: + case ARMV7_VDUP: + { + ConditionExecute(il, instr.cond, VectorDuplicate(il, instr)); + break; + } + case ARMV7_VTBL: + case ARMV7_VTBX: + ConditionExecute(il, instr.cond, VectorTableLookup(il, instr)); + break; + case ARMV7_VDIV: if((instr.dataType != DT_F32) && (instr.dataType != DT_F64)) break; ConditionExecute(il, instr.cond, il.SetRegister(get_register_size(op1.reg), op1.reg, - il.FloatAdd(get_register_size(op1.reg), + il.FloatDiv(get_register_size(op1.reg), il.Register(get_register_size(op2.reg), op2.reg), il.Register(get_register_size(op3.reg), op3.reg) ) ) ); break; - case ARMV7_VDIV: + case ARMV7_VHADD: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + HalvingVectorAdd(il, instr); + }); + break; + case ARMV7_VSQRT: if((instr.dataType != DT_F32) && (instr.dataType != DT_F64)) break; ConditionExecute(il, instr.cond, il.SetRegister(get_register_size(op1.reg), op1.reg, - il.FloatDiv(get_register_size(op1.reg), - il.Register(get_register_size(op2.reg), op2.reg), - il.Register(get_register_size(op3.reg), op3.reg) + il.FloatSqrt(get_register_size(op1.reg), + il.Register(get_register_size(op2.reg), op2.reg) ) ) ); break; + case ARMV7_VRINTA: + if((instr.dataType != DT_F32) && (instr.dataType != DT_F64)) + break; + ConditionExecute(il, instr.cond, + il.Intrinsic( + { RegisterOrFlag::Register(op1.reg) }, + ARMV7_INTRIN_VRINTA, + { il.Register(get_register_size(op2.reg), op2.reg) } + ) + ); + break; + case ARMV7_VRINTN: + case ARMV7_VRINTP: + case ARMV7_VRINTM: + case ARMV7_VRINTR: + case ARMV7_VRINTX: + case ARMV7_VRINTZ: + if((instr.dataType != DT_F32) && (instr.dataType != DT_F64)) + break; + ConditionExecute(il, instr.cond, + il.SetRegister(get_register_size(op1.reg), op1.reg, + RoundFloatOperand(il, instr, il.Register(get_register_size(op2.reg), op2.reg), get_register_size(op1.reg)) + ) + ); + break; + case ARMV7_VMAXNM: + case ARMV7_VMINM: + if((instr.dataType != DT_F32) && (instr.dataType != DT_F64)) + break; + ConditionExecute(il, instr.cond, + il.Intrinsic( + { RegisterOrFlag::Register(op1.reg) }, + (instr.operation == ARMV7_VMAXNM) ? ARMV7_INTRIN_VMAXNM : ARMV7_INTRIN_VMINNM, + { il.Register(get_register_size(op2.reg), op2.reg), + il.Register(get_register_size(op3.reg), op3.reg) } + ) + ); + break; + case ARMV7_VMAX: + ConditionExecute(il, instr.cond, VectorMaximumMinimum(il, instr, ARMV7_INTRIN_VMAX)); + break; + case ARMV7_VMIN: + ConditionExecute(il, instr.cond, VectorMaximumMinimum(il, instr, ARMV7_INTRIN_VMIN)); + break; + case ARMV7_VPMAX: + ConditionExecute(il, instr.cond, VectorMaximumMinimum(il, instr, ARMV7_INTRIN_VPMAX)); + break; + case ARMV7_VPMIN: + ConditionExecute(il, instr.cond, VectorMaximumMinimum(il, instr, ARMV7_INTRIN_VPMIN)); + break; + case ARMV7_VREV16: + ConditionExecute(il, instr.cond, VectorReverse(il, instr, ARMV7_INTRIN_VREV16)); + break; + case ARMV7_VREV32: + ConditionExecute(il, instr.cond, VectorReverse(il, instr, ARMV7_INTRIN_VREV32)); + break; + case ARMV7_VREV64: + ConditionExecute(il, instr.cond, VectorReverse(il, instr, ARMV7_INTRIN_VREV64)); + break; + case ARMV7_VEXT: + ConditionExecute(il, instr.cond, VectorExtract(il, instr)); + break; + case ARMV7_VQSHRN: + case ARMV7_VQSHRUN: + case ARMV7_VQRSHRN: + case ARMV7_VQRSHRUN: + ConditionExecute(il, instr.cond, SaturatingVectorShiftRightNarrow(il, instr)); + break; + case ARMV7_VQMOVN: + case ARMV7_VQMOVUN: + ConditionExecute(il, instr.cond, SaturatingVectorMoveNarrow(il, instr)); + break; + case ARMV7_VQADD: + ConditionExecute(il, instr.cond, SaturatingVectorAdd(il, instr)); + break; + case ARMV7_VABD: + ConditionExecute(il, instr.cond, + VectorAbsoluteDifference(il, instr, ARMV7_INTRIN_VABD)); + break; + case ARMV7_VABDL: + ConditionExecute(il, instr.cond, + VectorAbsoluteDifference(il, instr, ARMV7_INTRIN_VABDL)); + break; + case ARMV7_VABA: + ConditionExecute(il, instr.cond, + VectorAbsoluteDifferenceAccumulate(il, instr, ARMV7_INTRIN_VABA)); + break; + case ARMV7_VABAL: + ConditionExecute(il, instr.cond, + VectorAbsoluteDifferenceAccumulate(il, instr, ARMV7_INTRIN_VABAL)); + break; + case ARMV7_VADDL: + ConditionExecute(il, instr.cond, + VectorWideningAdd(il, instr, ARMV7_INTRIN_VADDL)); + break; + case ARMV7_VADDW: + ConditionExecute(il, instr.cond, + VectorWideningAdd(il, instr, ARMV7_INTRIN_VADDW)); + break; + case ARMV7_VRADDHN: + ConditionExecute(il, instr.cond, VectorRoundingAddNarrow(il, instr)); + break; + case ARMV7_VQSHL: + ConditionExecute(il, instr.cond, SaturatingVectorShiftLeft(il, instr, ARMV7_INTRIN_VQSHL)); + break; + case ARMV7_VQRSHL: + ConditionExecute(il, instr.cond, SaturatingVectorShiftLeft(il, instr, ARMV7_INTRIN_VQRSHL)); + break; + case ARMV7_VRSHR: + case ARMV7_VRSHL: + ConditionExecute(il, instr.cond, RoundedVectorShift(il, instr)); + break; + case ARMV7_VSRA: + ConditionExecute(il, instr.cond, ShiftRightAccumulateOrInsert(il, instr, ARMV7_INTRIN_VSRA)); + break; + case ARMV7_VRSRA: + ConditionExecute(il, instr.cond, ShiftRightAccumulateOrInsert(il, instr, ARMV7_INTRIN_VRSRA)); + break; + case ARMV7_VSRI: + ConditionExecute(il, instr.cond, ShiftRightAccumulateOrInsert(il, instr, ARMV7_INTRIN_VSRI)); + break; + case ARMV7_VSLI: + ConditionExecute(il, instr.cond, ShiftRightAccumulateOrInsert(il, instr, ARMV7_INTRIN_VSLI)); + break; + case ARMV7_VFMA: + case ARMV7_VFMS: + { + if ((instr.dataType != DT_F32) && (instr.dataType != DT_F64)) + break; + + size_t size = get_register_size(op1.reg); + ExprId product = il.FloatMult(size, + il.Register(get_register_size(op2.reg), op2.reg), + il.Register(get_register_size(op3.reg), op3.reg)); + ExprId value = (instr.operation == ARMV7_VFMA) + ? il.FloatAdd(size, il.Register(size, op1.reg), product) + : il.FloatSub(size, il.Register(size, op1.reg), product); + ConditionExecute(il, instr.cond, il.SetRegister(size, op1.reg, value)); + break; + } + case ARMV7_VMLA: + case ARMV7_VMLS: + { + if ((instr.dataType != DT_F32) && (instr.dataType != DT_F64)) + { + ConditionExecute(il, instr.cond, VectorMultiplyAccumulateIntrinsic(il, instr, + (instr.operation == ARMV7_VMLS) ? ARMV7_INTRIN_VMLS : ARMV7_INTRIN_VMLA)); + break; + } + + if ((instr.dataType != DT_F32) && (instr.dataType != DT_F64)) + break; + + size_t size = get_register_size(op1.reg); + ExprId product = il.FloatMult(size, + il.Register(get_register_size(op2.reg), op2.reg), + il.Register(get_register_size(op3.reg), op3.reg)); + ExprId value = (instr.operation == ARMV7_VMLA) + ? il.FloatAdd(size, il.Register(size, op1.reg), product) + : il.FloatSub(size, il.Register(size, op1.reg), product); + ConditionExecute(il, instr.cond, + il.SetRegister(size, op1.reg, value)); + break; + } + case ARMV7_VMLAL: + case ARMV7_VMLSL: + { + ConditionExecute(il, instr.cond, VectorMultiplyAccumulateIntrinsic(il, instr, + (instr.operation == ARMV7_VMLSL) ? ARMV7_INTRIN_VMLSL : ARMV7_INTRIN_VMLAL)); + break; + } + case ARMV7_VFNMA: + case ARMV7_VFNMS: + case ARMV7_VNMLA: + case ARMV7_VNMLS: + { + if ((instr.dataType != DT_F32) && (instr.dataType != DT_F64)) + break; + + size_t size = get_register_size(op1.reg); + ExprId product = il.FloatMult(size, + il.Register(get_register_size(op2.reg), op2.reg), + il.Register(get_register_size(op3.reg), op3.reg)); + ExprId value = ((instr.operation == ARMV7_VFNMA) || (instr.operation == ARMV7_VNMLA)) + ? il.FloatNeg(size, il.FloatAdd(size, il.Register(size, op1.reg), product)) + : il.FloatNeg(size, il.FloatSub(size, il.Register(size, op1.reg), product)); + ConditionExecute(il, instr.cond, + il.SetRegister(size, op1.reg, value)); + break; + } case ARMV7_VLDR: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) @@ -4978,32 +5831,88 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI }); break; case ARMV7_VMOV: + if (op1.cls == REG && op1.flags.hasElements == 1 && op2.cls == REG && op3.cls == NONE) + { + size_t elementSize = GetDataTypeSize(instr.dataType); + if (elementSize == 0) + { + ConditionExecute(il, instr.cond, il.Unimplemented()); + break; + } + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + InsertVectorElement(il, op1, il.Register(get_register_size(op2.reg), op2.reg), elementSize), + flagOperation[instr.setsFlags])); + break; + } + if (op1.cls == REG && op2.cls == REG && op2.flags.hasElements == 1 && op3.cls == NONE) + { + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t outputSize = get_register_size(op1.reg); + if (elementSize == 0) + { + ConditionExecute(il, instr.cond, il.Unimplemented()); + break; + } + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + ReadVectorElement(il, op2, elementSize, outputSize, IsSignedDataType(instr.dataType)), + flagOperation[instr.setsFlags])); + break; + } /* VMOV(register) */ - if (op1.cls == REG && op2.cls == REG && op3.cls == NONE) + if (op1.cls == REG && op2.cls == REG && op3.cls == REG && op4.cls == NONE) + { + if (get_register_size(op1.reg) == (get_register_size(op2.reg) + get_register_size(op3.reg))) + { + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.RegisterSplit(get_register_size(op2.reg), op3.reg, op2.reg), + flagOperation[instr.setsFlags])); + } + else + { + ConditionExecute(il, instr.cond, + il.SetRegisterSplit(get_register_size(op1.reg), op2.reg, op1.reg, + il.Register(get_register_size(op3.reg), op3.reg), + flagOperation[instr.setsFlags])); + } + } + else if (op1.cls == REG && op2.cls == REG && op3.cls == NONE) { ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, ReadILOperand(il, op2, addr), flagOperation[instr.setsFlags])); - } else if (op1.cls == REG && (op2.cls == IMM || op2.cls == IMM64) && op3.cls == NONE) { + } else if (op1.cls == REG && (op2.cls == IMM || op2.cls == IMM64 || op2.cls == FIMM32 || op2.cls == FIMM64) && op3.cls == NONE) { /* VMOV(immediate) */ + uint64_t imm = (op2.cls == FIMM32) ? op2.imm : op2.imm64; if (get_register_size(op1.reg) == 16) { ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, - il.Or(16, il.Const(8, op2.imm64), il.ShiftLeft(16, il.Const(8, op2.imm64), il.Const(8, 64))), + il.Or(16, il.Const(8, imm), il.ShiftLeft(16, il.Const(8, imm), il.Const(8, 64))), flagOperation[instr.setsFlags])); } else { ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, - il.Const(get_register_size(op1.reg), op2.imm64), flagOperation[instr.setsFlags])); + il.Const(get_register_size(op1.reg), imm), flagOperation[instr.setsFlags])); } } else { ConditionExecute(il, instr.cond, il.Unimplemented()); } break; + case ARMV7_VQDMULL: + ConditionExecute(il, instr.cond, VectorSaturatingDoublingMultiplyLongIntrinsic(il, instr)); + break; case ARMV7_VMUL: + if((instr.dataType != DT_F32) && (instr.dataType != DT_F64)) + { + ConditionExecute(il, instr.cond, VectorMultiply(il, instr)); + break; + } + if((instr.dataType != DT_F32) && (instr.dataType != DT_F64)) break; @@ -5016,6 +5925,21 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI ) ); break; + case ARMV7_VNMUL: + if((instr.dataType != DT_F32) && (instr.dataType != DT_F64)) + break; + + ConditionExecute(il, instr.cond, + il.SetRegister(get_register_size(op1.reg), op1.reg, + il.FloatNeg(get_register_size(op1.reg), + il.FloatMult(get_register_size(op1.reg), + il.Register(get_register_size(op2.reg), op2.reg), + il.Register(get_register_size(op3.reg), op3.reg) + ) + ) + ) + ); + break; case ARMV7_VSTR: ConditionExecute(addrSize, instr.cond, instr, il, [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) @@ -5025,18 +5949,148 @@ bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelI Store(il, get_register_size(op1.reg), op1, op2, addr); }); break; - case ARMV7_VSUB: - if((instr.dataType != DT_F32) && (instr.dataType != DT_F64)) + case ARMV7_VST1: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + StoreVst1(il, instr, addr); + }); + break; + case ARMV7_VST2: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + StoreStructuredVector(il, instr, addr, ARMV7_INTRIN_VST2, 2); + }); + break; + case ARMV7_VST4: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + StoreStructuredVector(il, instr, addr, ARMV7_INTRIN_VST4, 4); + }); + break; + case ARMV7_VLD2: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + LoadStructuredVector(il, instr, addr, ARMV7_INTRIN_VLD2, 2); + }); + break; + case ARMV7_VLD4: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + LoadStructuredVector(il, instr, addr, ARMV7_INTRIN_VLD4, 4); + }); + break; + case ARMV7_VLD1: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + LoadVld1(il, instr, addr); + }); + break; + case ARMV7_VSHR: + { + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t size = get_register_size(op1.reg); + if (op1.cls != REG || op2.cls != REG || op3.cls != IMM || elementSize != size) + { + ConditionExecute(il, instr.cond, il.Unimplemented()); break; + } + ExprId value = IsSignedDataType(instr.dataType) + ? il.ArithShiftRight(size, il.Register(size, op2.reg), il.Const(1, op3.imm)) + : il.LogicalShiftRight(size, il.Register(size, op2.reg), il.Const(1, op3.imm)); ConditionExecute(il, instr.cond, - il.SetRegister(get_register_size(op1.reg), op1.reg, - il.FloatSub(get_register_size(op1.reg), - il.Register(get_register_size(op2.reg), op2.reg), - il.Register(get_register_size(op3.reg), op3.reg) + SetRegisterOrBranch(il, op1.reg, value, flagOperation[instr.setsFlags])); + break; + } + case ARMV7_VSHL: + { + size_t elementSize = GetDataTypeSize(instr.dataType); + size_t size = get_register_size(op1.reg); + if (op1.cls != REG || op2.cls != REG || elementSize != size) + { + ConditionExecute(il, instr.cond, il.Unimplemented()); + break; + } + + if (op3.cls == IMM) + { + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.ShiftLeft(size, il.Register(size, op2.reg), il.Const(1, op3.imm)), + flagOperation[instr.setsFlags])); + break; + } + + if (op3.cls != REG || get_register_size(op3.reg) != size) + { + ConditionExecute(il, instr.cond, il.Unimplemented()); + break; + } + + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + LowLevelILLabel rightShift, leftShift, done; + il.AddInstruction(il.If( + il.CompareSignedLessThan(size, il.Register(size, op3.reg), il.Const(size, 0)), + rightShift, leftShift)); + il.MarkLabel(rightShift); + il.AddInstruction(SetRegisterOrBranch(il, op1.reg, + IsSignedDataType(instr.dataType) + ? il.ArithShiftRight(size, il.Register(size, op2.reg), il.Neg(size, il.Register(size, op3.reg))) + : il.LogicalShiftRight(size, il.Register(size, op2.reg), il.Neg(size, il.Register(size, op3.reg))), + flagOperation[instr.setsFlags])); + il.AddInstruction(il.Goto(done)); + il.MarkLabel(leftShift); + il.AddInstruction(SetRegisterOrBranch(il, op1.reg, + il.ShiftLeft(size, il.Register(size, op2.reg), il.Register(size, op3.reg)), + flagOperation[instr.setsFlags])); + il.MarkLabel(done); + }); + break; + } + case ARMV7_VSUB: + if (op1.cls != REG || op2.cls != REG || op3.cls != REG) + { + ConditionExecute(il, instr.cond, il.Unimplemented()); + break; + } + + if ((instr.dataType == DT_F32) || (instr.dataType == DT_F64)) + { + ConditionExecute(il, instr.cond, + il.SetRegister(get_register_size(op1.reg), op1.reg, + il.FloatSub(get_register_size(op1.reg), + il.Register(get_register_size(op2.reg), op2.reg), + il.Register(get_register_size(op3.reg), op3.reg) + ) ) - ) - ); + ); + } + else + { + size_t size = get_register_size(op1.reg); + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.Sub(size, + il.Register(size, op2.reg), + il.Register(size, op3.reg)), + flagOperation[instr.setsFlags])); + } break; default: //printf("Instruction: %s\n", get_operation(instr.operation)); diff --git a/arch/armv7/il.h b/arch/armv7/il.h index e4a579074e..61a46b14ff 100644 --- a/arch/armv7/il.h +++ b/arch/armv7/il.h @@ -36,11 +36,18 @@ enum Armv7Intrinsic : uint32_t ARMV7_INTRIN_DSB_OSH, ARMV7_INTRIN_DSB_OSHST, ARMV7_INTRIN_ISB, + ARMV7_INTRIN_YIELD, ARMV7_INTRIN_MRS, ARMV7_INTRIN_MSR, + ARMV7_INTRIN_VMRS, + ARMV7_INTRIN_VMSR, ARMV7_INTRIN_SEV, + ARMV7_INTRIN_HVC, + ARMV7_INTRIN_SMC, ARMV7_INTRIN_WFE, ARMV7_INTRIN_WFI, + ARMV7_INTRIN_HINT, + ARMV7_INTRIN_UNPREDICTABLE, ARM_M_INTRIN_SET_BASEPRI, // Following names are from Table D17-2 of ARM DDI 0406C.d, changed from // CamelCase to UPPERCASE with underscores preserved and ARMV7_INTRIN_ prefixed. @@ -48,11 +55,120 @@ enum Armv7Intrinsic : uint32_t ARMV7_INTRIN_COPROC_GETTWOWORDS, // MRRC, MRRC2 ARMV7_INTRIN_COPROC_SENDONEWORD, // MCR, MCR2 ARMV7_INTRIN_COPROC_SENDTWOWORDS, // MCRR, MCRR2 + ARMV7_INTRIN_COPROC_STORE, // STC, STC2, STCL, STC2L + ARMV7_INTRIN_COPROC_LOAD, // LDC, LDC2, LDCL, LDC2L + ARMV7_INTRIN_COPROC_DATAPROCESSING, // CDP, CDP2 ARMV7_INTRIN_EXCLUSIVE_MONITORS_PASS, ARMV7_INTRIN_SET_EXCLUSIVE_MONITORS, ARMV7_INTRIN_RBIT, ARMV7_INTRIN_CLZ, + ARMV7_INTRIN_CPS, + ARMV7_INTRIN_CPSID, + ARMV7_INTRIN_CPSIE, + ARMV7_INTRIN_SETEND, + ARMV7_INTRIN_CLREX, + ARMV7_INTRIN_PLD, + ARMV7_INTRIN_CRC32B, + ARMV7_INTRIN_CRC32CB, + ARMV7_INTRIN_CRC32CH, + ARMV7_INTRIN_CRC32CW, + ARMV7_INTRIN_CRC32H, + ARMV7_INTRIN_CRC32W, + ARMV7_INTRIN_SEL, + ARMV7_INTRIN_QADD, + ARMV7_INTRIN_QSUB, + ARMV7_INTRIN_QDADD, + ARMV7_INTRIN_QDSUB, + ARMV7_INTRIN_QADD16, + ARMV7_INTRIN_QADD8, + ARMV7_INTRIN_QSUB16, + ARMV7_INTRIN_QSUB8, + ARMV7_INTRIN_UQADD16, + ARMV7_INTRIN_UQADD8, + ARMV7_INTRIN_UQSUB16, + ARMV7_INTRIN_UQSUB8, + ARMV7_INTRIN_SXTAB16, + ARMV7_INTRIN_SXTB16, + ARMV7_INTRIN_UXTAB16, + ARMV7_INTRIN_UXTB16, + ARMV7_INTRIN_SADD16, + ARMV7_INTRIN_SADD8, + ARMV7_INTRIN_SHADD16, + ARMV7_INTRIN_SHADD8, + ARMV7_INTRIN_SSUB8, + ARMV7_INTRIN_SHSUB8, + ARMV7_INTRIN_SHSUB16, + ARMV7_INTRIN_UHSUB8, + ARMV7_INTRIN_UHSUB16, + ARMV7_INTRIN_USUB8, + ARMV7_INTRIN_USUB16, + ARMV7_INTRIN_USAD8, + ARMV7_INTRIN_USADA8, + ARMV7_INTRIN_QSAX, + ARMV7_INTRIN_UQASX, + ARMV7_INTRIN_UQSAX, + ARMV7_INTRIN_VRINTA, + ARMV7_INTRIN_VMAXNM, + ARMV7_INTRIN_VMINNM, + ARMV7_INTRIN_VMAX, + ARMV7_INTRIN_VMIN, + ARMV7_INTRIN_VPMAX, + ARMV7_INTRIN_VPMIN, + ARMV7_INTRIN_VREV16, + ARMV7_INTRIN_VREV32, + ARMV7_INTRIN_VREV64, + ARMV7_INTRIN_VEXT, + ARMV7_INTRIN_VCGT, + ARMV7_INTRIN_VCEQ, + ARMV7_INTRIN_VTBL, + ARMV7_INTRIN_VTBX, + ARMV7_INTRIN_VDUP, + ARMV7_INTRIN_VABD, + ARMV7_INTRIN_VABDL, + ARMV7_INTRIN_VABA, + ARMV7_INTRIN_VABAL, + ARMV7_INTRIN_VADDL, + ARMV7_INTRIN_VADDW, + ARMV7_INTRIN_VRADDHN, + ARMV7_INTRIN_VRSHR, + ARMV7_INTRIN_VRSHL, + ARMV7_INTRIN_VSRA, + ARMV7_INTRIN_VRSRA, + ARMV7_INTRIN_VSRI, + ARMV7_INTRIN_VSLI, + ARMV7_INTRIN_VLD2, + ARMV7_INTRIN_VLD4, + ARMV7_INTRIN_VST2, + ARMV7_INTRIN_VST4, + ARMV7_INTRIN_VSHL, + ARMV7_INTRIN_VSHR, + ARMV7_INTRIN_VSHLL, + ARMV7_INTRIN_VBIF, + ARMV7_INTRIN_VBIT, + ARMV7_INTRIN_VBSL, + ARMV7_INTRIN_VQADD, + ARMV7_INTRIN_VHADD, + ARMV7_INTRIN_VQSHL, + ARMV7_INTRIN_VQRSHL, + ARMV7_INTRIN_VQSHRN, + ARMV7_INTRIN_VQSHRUN, + ARMV7_INTRIN_VQRSHRN, + ARMV7_INTRIN_VQRSHRUN, + ARMV7_INTRIN_VQMOVN, + ARMV7_INTRIN_VQMOVUN, + ARMV7_INTRIN_VMLA, + ARMV7_INTRIN_VMLS, + ARMV7_INTRIN_VMLAL, + ARMV7_INTRIN_VMLSL, + ARMV7_INTRIN_VMUL, + ARMV7_INTRIN_VQDMULL, + ARMV7_INTRIN_SSAT, + ARMV7_INTRIN_SSAT16, + ARMV7_INTRIN_USAT, + ARMV7_INTRIN_USAT16, + ARMV7_INTRIN_SRS, + ARMV7_INTRIN_RFE, }; enum ArmFakeRegister: uint32_t diff --git a/arch/armv7/test_lift.py b/arch/armv7/test_lift.py index 983ff092df..9c312162d0 100755 --- a/arch/armv7/test_lift.py +++ b/arch/armv7/test_lift.py @@ -1,5 +1,56 @@ #!/usr/bin/env python +def scalar_intrinsic_expected(dst, intrinsic, *sources): + inputs = ','.join(f'LLIL_REG.d({src})' for src in sources) + return f'LLIL_INTRINSIC([{dst}],__{intrinsic},[{inputs}])' + +def vector_intrinsic_expected(dst, intrinsic, size, modifier, src1, src2): + return f'LLIL_INTRINSIC([{dst}],__{intrinsic},[LLIL_CONST.b(0x{size:X}),LLIL_CONST.b(0x{modifier:X}),LLIL_REG.q({src1}),LLIL_REG.q({src2})])' + +def saturating_scalar_expected(dst, src1, src2, intrinsic): + return f'LLIL_INTRINSIC([{dst}],__{intrinsic},[LLIL_REG.d({src1}),LLIL_REG.d({src2})])' + +def vmlal_expected(size, unsigned): + return ( + f'LLIL_INTRINSIC([q8],__vmlal,[LLIL_CONST.b(0x{size:X}),LLIL_CONST.b(0x{unsigned:X}),' + 'LLIL_REG.o(q8),LLIL_REG.q(d0),LLIL_REG.q(d1),LLIL_CONST.b(0xFF)])' + ) + +def usat_expected(dst, src, bits): + max_value = f'LLIL_SUB.d(LLIL_LSL.d(LLIL_CONST.d(0x1),LLIL_CONST.d(0x{bits:X})),LLIL_CONST.d(0x1))' + result = [f'LLIL_SET_REG.d(temp0,{max_value})'] + result.append(f'LLIL_IF(LLIL_CMP_SLT.d(LLIL_REG.d({src}),LLIL_CONST.d(0x0)),2,4)') + result.append(f'LLIL_SET_REG.d({dst},LLIL_CONST.d(0x0))') + result.append('LLIL_GOTO(8)') + result.append(f'LLIL_IF(LLIL_CMP_SGT.d(LLIL_REG.d({src}),LLIL_REG.d(temp0)),5,7)') + result.append(f'LLIL_SET_REG.d({dst},LLIL_REG.d(temp0))') + result.append('LLIL_GOTO(8)') + result.append(f'LLIL_SET_REG.d({dst},LLIL_REG.d({src}))') + return '; '.join(result) + +def usat16_expected(dst, src, bits): + max_value = f'LLIL_SUB.d(LLIL_LSL.d(LLIL_CONST.d(0x1),LLIL_CONST.d(0x{bits:X})),LLIL_CONST.d(0x1))' + low = f'LLIL_SX.d(LLIL_LOW_PART.w(LLIL_REG.d({src})))' + high = f'LLIL_ASR.d(LLIL_REG.d({src}),LLIL_CONST.b(0x10))' + packed = 'LLIL_OR.d(LLIL_LSL.d(LLIL_ZX.d(LLIL_LOW_PART.w(LLIL_REG.d(temp2))),LLIL_CONST.b(0x10)),LLIL_ZX.d(LLIL_LOW_PART.w(LLIL_REG.d(temp1))))' + result = [f'LLIL_SET_REG.d(temp0,{max_value})'] + result.append(f'LLIL_IF(LLIL_CMP_SLT.d({low},LLIL_CONST.d(0x0)),2,4)') + result.append('LLIL_SET_REG.d(temp1,LLIL_CONST.d(0x0))') + result.append('LLIL_GOTO(8)') + result.append(f'LLIL_IF(LLIL_CMP_SGT.d({low},LLIL_REG.d(temp0)),5,7)') + result.append('LLIL_SET_REG.d(temp1,LLIL_REG.d(temp0))') + result.append('LLIL_GOTO(8)') + result.append(f'LLIL_SET_REG.d(temp1,{low})') + result.append(f'LLIL_IF(LLIL_CMP_SLT.d({high},LLIL_CONST.d(0x0)),9,11)') + result.append('LLIL_SET_REG.d(temp2,LLIL_CONST.d(0x0))') + result.append('LLIL_GOTO(15)') + result.append(f'LLIL_IF(LLIL_CMP_SGT.d({high},LLIL_REG.d(temp0)),12,14)') + result.append('LLIL_SET_REG.d(temp2,LLIL_REG.d(temp0))') + result.append('LLIL_GOTO(15)') + result.append(f'LLIL_SET_REG.d(temp2,{high})') + result.append(f'LLIL_SET_REG.d({dst},{packed})') + return '; '.join(result) + test_cases = \ [ # Post-Indexed addressing (normal) @@ -24,7 +75,8 @@ ('A', b'\x04\xf0\x9d\xe4', 'LLIL_SET_REG.d(temp0,LLIL_LOAD.d(LLIL_REG.d(sp))); LLIL_SET_REG.d(sp,LLIL_ADD.d(LLIL_REG.d(sp),LLIL_CONST.d(0x4))); LLIL_JUMP(LLIL_REG.d(temp0))'), # umaal r0, r1, r2, r3 - ('A', b'\x92\x03\x41\xe0', 'LLIL_SET_REG_SPLIT.d(r1,r0,LLIL_ADD.q(LLIL_MULU_DP.d(LLIL_REG.d(r3),LLIL_REG.d(r2)),LLIL_ADD.q(LLIL_REG.d(r1),LLIL_REG.d(r0))))'), + ('A', b'\x92\x03\x41\xe0', 'LLIL_SET_REG_SPLIT.d(r1,r0,LLIL_ADD.q(LLIL_MULU_DP.d(LLIL_REG.d(r3),LLIL_REG.d(r2)),LLIL_ADD.q(LLIL_ZX.q(LLIL_REG.d(r1)),LLIL_ZX.q(LLIL_REG.d(r0)))))'), + ('T', b'\xe2\xfb\x63\x01', 'LLIL_SET_REG_SPLIT.d(r1,r0,LLIL_ADD.q(LLIL_MULU_DP.d(LLIL_REG.d(r3),LLIL_REG.d(r2)),LLIL_ADD.q(LLIL_ZX.q(LLIL_REG.d(r1)),LLIL_ZX.q(LLIL_REG.d(r0)))))'), # umlal r0, r1, r2, r3 ('A', b'\x92\x03\xa1\xe0', 'LLIL_SET_REG_SPLIT.d(r1,r0,LLIL_ADD.q(LLIL_MULU_DP.d(LLIL_REG.d(r3),LLIL_REG.d(r2)),LLIL_REG_SPLIT.d(r1,r0)))'), # umlals r0, r1, r2, r3 @@ -33,14 +85,92 @@ ('A', b'\x92\x03\x81\xe0', 'LLIL_SET_REG_SPLIT.d(r1,r0,LLIL_MULU_DP.d(LLIL_REG.d(r2),LLIL_REG.d(r3)))'), # smull r0, r1, r2, r3 ('A', b'\x92\x03\xc1\xe0', 'LLIL_SET_REG_SPLIT.d(r1,r0,LLIL_MULS_DP.d(LLIL_REG.d(r2),LLIL_REG.d(r3)))'), + # stlex r1, r2, [r3] + ('A', b'\x92\x1e\x83\xe1', 'LLIL_INTRINSIC([r1],ExclusiveMonitorsPass,[LLIL_ADD.d(LLIL_REG.d(r3),LLIL_CONST.d(0x0)),LLIL_CONST.b(0x4)]); LLIL_IF(LLIL_CMP_E.d(LLIL_REG.d(r1),LLIL_CONST.d(0x1)),2,4); LLIL_STORE.d(LLIL_ADD.d(LLIL_REG.d(r3),LLIL_CONST.d(0x0)),LLIL_REG.d(r2)); LLIL_GOTO(4)'), + # stc2l p8, c0, [r5, #0x48]! + ('T', b'\xe5\xfd\x12\x08', 'LLIL_INTRINSIC([],Coproc_Store,[LLIL_ADD.d(LLIL_REG.d(r5),LLIL_CONST.d(0x48)),LLIL_CONST.b(0x8),LLIL_CONST.b(0x0),LLIL_CONST.b(0x1)]); LLIL_SET_REG.d(r5,LLIL_ADD.d(LLIL_REG.d(r5),LLIL_CONST.d(0x48)))'), + # stc2 p8, c0, [sp, #-0x48]! + ('T', b'\x2d\xfd\x12\x08', 'LLIL_INTRINSIC([],Coproc_Store,[LLIL_SUB.d(LLIL_REG.d(sp),LLIL_CONST.d(0x48)),LLIL_CONST.b(0x8),LLIL_CONST.b(0x0),LLIL_CONST.b(0x0)]); LLIL_SET_REG.d(sp,LLIL_SUB.d(LLIL_REG.d(sp),LLIL_CONST.d(0x48)))'), + # ldc p8, c0, [r12], {0x1b} + ('T', b'\x9c\xec\x1b\x08', 'LLIL_INTRINSIC([],Coproc_Load,[LLIL_REG.d(r12),LLIL_CONST.b(0x8),LLIL_CONST.b(0x0),LLIL_CONST.b(0x0)])'), + # ldc2l p8, c0, [sp], #0x48 + ('T', b'\xdd\xfc\x12\x08', 'LLIL_INTRINSIC([],Coproc_Load,[LLIL_REG.d(sp),LLIL_CONST.b(0x8),LLIL_CONST.b(0x0),LLIL_CONST.b(0x1)]); LLIL_SET_REG.d(sp,LLIL_ADD.d(LLIL_REG.d(sp),LLIL_CONST.d(0x48)))'), + # ldc2 p8, c0, [sp], {0x12} + ('T', b'\x9d\xfc\x12\x08', 'LLIL_INTRINSIC([],Coproc_Load,[LLIL_REG.d(sp),LLIL_CONST.b(0x8),LLIL_CONST.b(0x0),LLIL_CONST.b(0x0)])'), + # cdp2 p8, #8, c0, c5, c5, #0 + ('T', b'\x85\xfe\x05\x08', 'LLIL_INTRINSIC([],Coproc_DataProcessing,[LLIL_CONST.b(0x8),LLIL_CONST.b(0x8),LLIL_CONST.b(0x0),LLIL_CONST.b(0x5),LLIL_CONST.b(0x5),LLIL_CONST.b(0x0)])'), + # ands r0, r5 + ('T', b'\x28\x40', 'LLIL_SET_REG.d(temp0,LLIL_AND.d(LLIL_REG.d(r0),LLIL_REG.d(r5))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0))); LLIL_SET_REG.d(r0,LLIL_REG.d(temp0))'), + # bics r3, r3 + ('T', b'\x9b\x43', 'LLIL_SET_REG.d(temp0,LLIL_AND.d(LLIL_REG.d(r3),LLIL_NOT.d(LLIL_REG.d(r3)))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0))); LLIL_SET_REG.d(r3,LLIL_REG.d(temp0))'), + # mvns r3, r6 + ('T', b'\xf3\x43', 'LLIL_SET_REG.d(temp0,LLIL_NOT.d(LLIL_REG.d(r6))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0))); LLIL_SET_REG.d(r3,LLIL_REG.d(temp0))'), + # eors r2, r0 + ('T', b'\x42\x40', 'LLIL_SET_REG.d(temp0,LLIL_XOR.d(LLIL_REG.d(r2),LLIL_REG.d(r0))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0))); LLIL_SET_REG.d(r2,LLIL_REG.d(temp0))'), + # eors r10, r9, r1, lsl #18 + ('T', b'\x99\xea\x81\x4a', 'LLIL_SET_REG.d(temp0,LLIL_XOR.d(LLIL_REG.d(r9),LLIL_LSL.d(LLIL_REG.d(r1),LLIL_CONST.d(0x12)))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0))); LLIL_SET_FLAG(c,LLIL_TEST_BIT.d(LLIL_REG.d(r1),LLIL_CONST.b(0xE))); LLIL_SET_REG.d(r10,LLIL_REG.d(temp0))'), + # ands r2, sp, r8, lsl #6 + ('T', b'\x1d\xea\x88\x12', 'LLIL_SET_REG.d(temp0,LLIL_AND.d(LLIL_REG.d(sp),LLIL_LSL.d(LLIL_REG.d(r8),LLIL_CONST.d(0x6)))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0))); LLIL_SET_FLAG(c,LLIL_TEST_BIT.d(LLIL_REG.d(r8),LLIL_CONST.b(0x1A))); LLIL_SET_REG.d(r2,LLIL_REG.d(temp0))'), # teq r0, #0 - ('A', b'\x00\x00\x30\xe3', 'LLIL_XOR.d{cnz}(LLIL_REG.d(r0),LLIL_CONST.d(0x0))'), + ('A', b'\x00\x00\x30\xe3', 'LLIL_SET_REG.d(temp0,LLIL_XOR.d(LLIL_REG.d(r0),LLIL_CONST.d(0x0))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0)))'), # teq r1, #1 - ('A', b'\x01\x00\x31\xe3', 'LLIL_XOR.d{cnz}(LLIL_REG.d(r1),LLIL_CONST.d(0x1))'), + ('A', b'\x01\x00\x31\xe3', 'LLIL_SET_REG.d(temp0,LLIL_XOR.d(LLIL_REG.d(r1),LLIL_CONST.d(0x1))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0)))'), # teq r2, #2 - ('A', b'\x02\x00\x32\xe3', 'LLIL_XOR.d{cnz}(LLIL_REG.d(r2),LLIL_CONST.d(0x2))'), + ('A', b'\x02\x00\x32\xe3', 'LLIL_SET_REG.d(temp0,LLIL_XOR.d(LLIL_REG.d(r2),LLIL_CONST.d(0x2))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0)))'), # teq r3, #3 - ('A', b'\x03\x00\x33\xe3', 'LLIL_XOR.d{cnz}(LLIL_REG.d(r3),LLIL_CONST.d(0x3))'), + ('A', b'\x03\x00\x33\xe3', 'LLIL_SET_REG.d(temp0,LLIL_XOR.d(LLIL_REG.d(r3),LLIL_CONST.d(0x3))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0)))'), + # crc32b r0, r1, r2 + ('A', b'\x42\x00\x01\xe1', 'LLIL_INTRINSIC([r0],__crc32b,[LLIL_REG.d(r1),LLIL_LOW_PART.b(LLIL_REG.d(r2))])'), + # crc32h r0, r1, r2 + ('A', b'\x42\x00\x21\xe1', 'LLIL_INTRINSIC([r0],__crc32h,[LLIL_REG.d(r1),LLIL_LOW_PART.w(LLIL_REG.d(r2))])'), + # crc32w r0, r1, r2 + ('A', b'\x42\x00\x41\xe1', 'LLIL_INTRINSIC([r0],__crc32w,[LLIL_REG.d(r1),LLIL_REG.d(r2)])'), + # crc32cb r0, r1, r2 + ('A', b'\x42\x02\x01\xe1', 'LLIL_INTRINSIC([r0],__crc32cb,[LLIL_REG.d(r1),LLIL_LOW_PART.b(LLIL_REG.d(r2))])'), + # crc32ch r0, r1, r2 + ('A', b'\x42\x02\x21\xe1', 'LLIL_INTRINSIC([r0],__crc32ch,[LLIL_REG.d(r1),LLIL_LOW_PART.w(LLIL_REG.d(r2))])'), + # crc32cw r0, r1, r2 + ('A', b'\x42\x02\x41\xe1', 'LLIL_INTRINSIC([r0],__crc32cw,[LLIL_REG.d(r1),LLIL_REG.d(r2)])'), + # crc32b r0, r1, r2 (Thumb2) + ('T', b'\xc1\xfa\x82\xf0', 'LLIL_INTRINSIC([r0],__crc32b,[LLIL_REG.d(r1),LLIL_LOW_PART.b(LLIL_REG.d(r2))])'), + # crc32h r0, r1, r2 (Thumb2) + ('T', b'\xc1\xfa\x92\xf0', 'LLIL_INTRINSIC([r0],__crc32h,[LLIL_REG.d(r1),LLIL_LOW_PART.w(LLIL_REG.d(r2))])'), + # crc32w r0, r1, r2 (Thumb2) + ('T', b'\xc1\xfa\xa2\xf0', 'LLIL_INTRINSIC([r0],__crc32w,[LLIL_REG.d(r1),LLIL_REG.d(r2)])'), + # crc32cb r0, r1, r2 (Thumb2) + ('T', b'\xd1\xfa\x82\xf0', 'LLIL_INTRINSIC([r0],__crc32cb,[LLIL_REG.d(r1),LLIL_LOW_PART.b(LLIL_REG.d(r2))])'), + # crc32ch r0, r1, r2 (Thumb2) + ('T', b'\xd1\xfa\x92\xf0', 'LLIL_INTRINSIC([r0],__crc32ch,[LLIL_REG.d(r1),LLIL_LOW_PART.w(LLIL_REG.d(r2))])'), + # crc32cw r0, r1, r2 (Thumb2) + ('T', b'\xd1\xfa\xa2\xf0', 'LLIL_INTRINSIC([r0],__crc32cw,[LLIL_REG.d(r1),LLIL_REG.d(r2)])'), + # mrs lr, spsr + ('A', b'\x00\xe0\x4f\xe1', 'LLIL_INTRINSIC([lr],__mrs,[LLIL_CONST.d(0x95)])'), + # mrs r0, apsr + ('A', b'\x00\x00\x0f\xe1', 'LLIL_INTRINSIC([r0],__mrs,[LLIL_CONST.d(0x81)])'), + # mrs r9, apsr + ('A', b'\x00\x90\x0f\xe1', 'LLIL_INTRINSIC([r9],__mrs,[LLIL_CONST.d(0x81)])'), + # uqasx r0, r1, r2 + ('A', b'\x32\x0f\x61\xe6', 'LLIL_INTRINSIC([r0],__uqasx,[LLIL_REG.d(r1),LLIL_REG.d(r2)])'), + # uqsax r0, r1, r2 + ('A', b'\x52\x0f\x61\xe6', 'LLIL_INTRINSIC([r0],__uqsax,[LLIL_REG.d(r1),LLIL_REG.d(r2)])'), + # msr cpsr_c, r9 + ('A', b'\x09\xf0\x21\xe1', 'LLIL_INTRINSIC([],__msr,[LLIL_CONST.d(0x86),LLIL_REG.d(r9)])'), + # msr cpsr_fc, r0 + ('A', b'\x00\xf0\x29\xe1', 'LLIL_INTRINSIC([],__msr,[LLIL_CONST.d(0x8E),LLIL_REG.d(r0)])'), + # msr spsr_fc, sp + ('A', b'\x0d\xf0\x69\xe1', 'LLIL_INTRINSIC([],__msr,[LLIL_CONST.d(0x9E),LLIL_REG.d(sp)])'), + # msrmi cpsr_fsx, #0x3100 + ('A', b'\x31\x0c\x2e\x43', 'LLIL_IF(LLIL_FLAG_COND(LowLevelILFlagCondition.LLFC_NEG,None),1,3); LLIL_INTRINSIC([],__msr,[LLIL_CONST.d(0x93),LLIL_CONST.d(0x3100)]); LLIL_GOTO(3)'), + # vmsr fpexc, r1 + ('A', b'\x10\x1a\xe8\xee', 'LLIL_INTRINSIC([],__vmsr,[LLIL_CONST.d(0xAB),LLIL_REG.d(r1)])'), + # vmsr fpscr, r0 (Thumb2) + ('T', b'\xe1\xee\x10\x0a', 'LLIL_INTRINSIC([],__vmsr,[LLIL_CONST.d(0xA7),LLIL_REG.d(r0)])'), + # vmrs r1, fpexc + ('A', b'\x10\x1a\xf8\xee', 'LLIL_INTRINSIC([r1],__vmrs,[LLIL_CONST.d(0xAB)])'), + # vmrs apsr_nzcv, fpscr + ('A', b'\x10\xfa\xf1\xee', 'LLIL_INTRINSIC([temp0],__vmrs,[LLIL_CONST.d(0xA7)]); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1E))); LLIL_SET_FLAG(c,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1D))); LLIL_SET_FLAG(v,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1C)))'), + # vmrs apsr_nzcv, fpscr (Thumb2) + ('T', b'\xf1\xee\x10\xfa', 'LLIL_INTRINSIC([temp0],__vmrs,[LLIL_CONST.d(0xA7)]); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1E))); LLIL_SET_FLAG(c,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1D))); LLIL_SET_FLAG(v,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1C)))'), # sxth r0, r1, ror #0 ('A', b'\x71\x00\xbf\xe6', 'LLIL_SET_REG.d(r0,LLIL_SX.d(LLIL_LOW_PART.w(LLIL_REG.d(r1))))'), @@ -50,15 +180,51 @@ ('A', b'\x71\x08\xbf\xe6', 'LLIL_SET_REG.d(r0,LLIL_SX.d(LLIL_LOW_PART.w(LLIL_ROR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x10)))))'), # sxth r0, r1, ror #0x18 ('A', b'\x71\x0c\xbf\xe6', 'LLIL_SET_REG.d(r0,LLIL_SX.d(LLIL_LOW_PART.w(LLIL_ROR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x18)))))'), + # sxtab16 r0, r1, r2 + ('T', b'\x21\xfa\x82\xf0', scalar_intrinsic_expected('r0', 'sxtab16', 'r1', 'r2')), + # sxtb16 r0, r1 + ('T', b'\x2f\xfa\x81\xf0', scalar_intrinsic_expected('r0', 'sxtb16', 'r1')), + # uxtab16 r0, r1, r2 + ('T', b'\x31\xfa\x82\xf0', scalar_intrinsic_expected('r0', 'uxtab16', 'r1', 'r2')), + # uxtb16 r0, r1 + ('T', b'\x3f\xfa\x81\xf0', scalar_intrinsic_expected('r0', 'uxtb16', 'r1')), # ror r0, r1 - ('A', b'\x70\x01\xa0\xe1', 'LLIL_SET_REG.d(r0,LLIL_ROR.d(LLIL_REG.d(r0),LLIL_AND.b(LLIL_REG.d(r1),LLIL_CONST.b(0xFF))))'), + ('A', b'\x70\x01\xa0\xe1', 'LLIL_SET_REG.d(r0,LLIL_ROR.d(LLIL_REG.d(r0),LLIL_AND.d(LLIL_REG.d(r1),LLIL_CONST.d(0xFF))))'), # ror r0, 7 - ('A', b'\xe0\x03\xa0\xe1', 'LLIL_SET_REG.d(r0,LLIL_ROR.d(LLIL_REG.d(r0),LLIL_AND.b(LLIL_CONST.d(0x7),LLIL_CONST.b(0xFF))))'), + ('A', b'\xe0\x03\xa0\xe1', 'LLIL_SET_REG.d(r0,LLIL_ROR.d(LLIL_REG.d(r0),LLIL_AND.d(LLIL_CONST.d(0x7),LLIL_CONST.d(0xFF))))'), # rors r0, r1 - ('A', b'\x70\x01\xb0\xe1', 'LLIL_SET_REG.d(r0,LLIL_ROR.d{*}(LLIL_REG.d(r0),LLIL_AND.b(LLIL_REG.d(r1),LLIL_CONST.b(0xFF))))'), + ('A', b'\x70\x01\xb0\xe1', 'LLIL_SET_REG.d(temp0,LLIL_ROR.d(LLIL_REG.d(r0),LLIL_AND.d(LLIL_REG.d(r1),LLIL_CONST.d(0xFF)))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0))); LLIL_IF(LLIL_CMP_E.d(LLIL_AND.d(LLIL_REG.d(r1),LLIL_CONST.d(0xFF)),LLIL_CONST.d(0x0)),4,5); LLIL_GOTO(7); LLIL_SET_FLAG(c,LLIL_TEST_BIT.d(LLIL_REG.d(r0),LLIL_AND.b(LLIL_SUB.b(LLIL_LOW_PART.b(LLIL_AND.d(LLIL_REG.d(r1),LLIL_CONST.d(0xFF))),LLIL_CONST.b(0x1)),LLIL_CONST.b(0x1F)))); LLIL_GOTO(7); LLIL_SET_REG.d(r0,LLIL_REG.d(temp0))'), # rors r0, 7 - ('A', b'\xe0\x03\xb0\xe1', 'LLIL_SET_REG.d(r0,LLIL_ROR.d{*}(LLIL_REG.d(r0),LLIL_AND.b(LLIL_CONST.d(0x7),LLIL_CONST.b(0xFF))))'), + ('A', b'\xe0\x03\xb0\xe1', 'LLIL_SET_REG.d(temp0,LLIL_ROR.d(LLIL_REG.d(r0),LLIL_AND.d(LLIL_CONST.d(0x7),LLIL_CONST.d(0xFF)))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0))); LLIL_IF(LLIL_CMP_E.d(LLIL_AND.d(LLIL_CONST.d(0x7),LLIL_CONST.d(0xFF)),LLIL_CONST.d(0x0)),4,5); LLIL_GOTO(7); LLIL_SET_FLAG(c,LLIL_TEST_BIT.d(LLIL_REG.d(r0),LLIL_AND.b(LLIL_SUB.b(LLIL_LOW_PART.b(LLIL_AND.d(LLIL_CONST.d(0x7),LLIL_CONST.d(0xFF))),LLIL_CONST.b(0x1)),LLIL_CONST.b(0x1F)))); LLIL_GOTO(7); LLIL_SET_REG.d(r0,LLIL_REG.d(temp0))'), + # rors r3, r5 + ('T', b'\xeb\x41', 'LLIL_SET_REG.d(temp0,LLIL_ROR.d(LLIL_REG.d(r3),LLIL_AND.d(LLIL_REG.d(r5),LLIL_CONST.d(0xFF)))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0))); LLIL_IF(LLIL_CMP_E.d(LLIL_AND.d(LLIL_REG.d(r5),LLIL_CONST.d(0xFF)),LLIL_CONST.d(0x0)),4,5); LLIL_GOTO(7); LLIL_SET_FLAG(c,LLIL_TEST_BIT.d(LLIL_REG.d(r3),LLIL_AND.b(LLIL_SUB.b(LLIL_LOW_PART.b(LLIL_AND.d(LLIL_REG.d(r5),LLIL_CONST.d(0xFF))),LLIL_CONST.b(0x1)),LLIL_CONST.b(0x1F)))); LLIL_GOTO(7); LLIL_SET_REG.d(r3,LLIL_REG.d(temp0))'), + # orrs r0, r0, r12, lsl #1 + ('T', b'\x50\xea\x4c\x00', 'LLIL_SET_REG.d(temp0,LLIL_OR.d(LLIL_REG.d(r0),LLIL_LSL.d(LLIL_REG.d(r12),LLIL_CONST.d(0x1)))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0))); LLIL_SET_FLAG(c,LLIL_TEST_BIT.d(LLIL_REG.d(r12),LLIL_CONST.b(0x1F))); LLIL_SET_REG.d(r0,LLIL_REG.d(temp0))'), + # asrs r5, r5, #0x1e + ('T', b'\xad\x17', 'LLIL_SET_REG.d(temp0,LLIL_ASR.d(LLIL_REG.d(r5),LLIL_CONST.d(0x1E))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0))); LLIL_SET_FLAG(c,LLIL_TEST_BIT.d(LLIL_REG.d(r5),LLIL_CONST.b(0x1D))); LLIL_SET_REG.d(r5,LLIL_REG.d(temp0))'), + # adcs r2, r7 + ('T', b'\x7a\x41', 'LLIL_SET_REG.d(temp0,LLIL_ADC.d(LLIL_REG.d(r2),LLIL_REG.d(r7),LLIL_FLAG(c))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0))); LLIL_SET_FLAG(c,LLIL_OR.b(LLIL_CMP_ULT.d(LLIL_REG.d(temp0),LLIL_REG.d(r2)),LLIL_AND.b(LLIL_FLAG(c),LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_REG.d(r2))))); LLIL_SET_FLAG(v,LLIL_AND.b(LLIL_TEST_BIT.d(LLIL_XOR.d(LLIL_REG.d(r2),LLIL_REG.d(temp0)),LLIL_CONST.b(0x1F)),LLIL_TEST_BIT.d(LLIL_XOR.d(LLIL_REG.d(r7),LLIL_REG.d(temp0)),LLIL_CONST.b(0x1F)))); LLIL_SET_REG.d(r2,LLIL_REG.d(temp0))'), + # strht r3, [r3, #0x7f] + ('T', b'\x23\xf8\x7f\x3e', 'LLIL_STORE.w(LLIL_ADD.d(LLIL_REG.d(r3),LLIL_CONST.d(0x7F)),LLIL_LOW_PART.w(LLIL_REG.d(r3)))'), + # srsia sp!, #0x1c + ('T', b'\xa3\xe9\x1c\x3f', 'LLIL_INTRINSIC([],__srs,[LLIL_CONST.b(0x1C),LLIL_CONST.b(0x1),LLIL_CONST.b(0x0),LLIL_CONST.b(0x1)])'), + # srsdb sp!, #0x17 + ('T', b'\x2d\xe8\x17\x08', 'LLIL_INTRINSIC([],__srs,[LLIL_CONST.b(0x17),LLIL_CONST.b(0x0),LLIL_CONST.b(0x0),LLIL_CONST.b(0x1)])'), + # rfeia r5! + ('T', b'\xb5\xe9\x5b\xc2', 'LLIL_INTRINSIC([],__rfe,[LLIL_REG.d(r5),LLIL_CONST.b(0x1),LLIL_CONST.b(0x0),LLIL_CONST.b(0x1)])'), + # rfedb r9 + ('T', b'\x19\xe8\x92\xd1', 'LLIL_INTRINSIC([],__rfe,[LLIL_REG.d(r9),LLIL_CONST.b(0x0),LLIL_CONST.b(0x0),LLIL_CONST.b(0x0)])'), + # usat16 r8, #8, r9 + ('T', b'\xa9\xf7\x08\x08', 'LLIL_INTRINSIC([r8],__usat16,[LLIL_CONST.d(0x8),LLIL_REG.d(r9)])'), + # usat r1, #8, r1 + ('T', b'\x81\xf3\x08\x01', 'LLIL_INTRINSIC([r1],__usat,[LLIL_CONST.d(0x8),LLIL_REG.d(r1)])'), + # tst r0, r6 + ('T', b'\x30\x42', 'LLIL_SET_REG.d(temp0,LLIL_AND.d(LLIL_REG.d(r0),LLIL_REG.d(r6))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0)))'), + # teq r0, r1 + ('T', b'\x90\xea\x01\x0f', 'LLIL_SET_REG.d(temp0,LLIL_XOR.d(LLIL_REG.d(r0),LLIL_REG.d(r1))); LLIL_SET_FLAG(n,LLIL_TEST_BIT.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x1F))); LLIL_SET_FLAG(z,LLIL_CMP_E.d(LLIL_REG.d(temp0),LLIL_CONST.d(0x0)))'), + # stmdavs r5!, {r1, r2, r3, r5, r6, r9, r11, r12, sp} + ('A', b'\x6e\x3a\x25\x68', 'LLIL_IF(LLIL_FLAG_COND(LowLevelILFlagCondition.LLFC_O,None),1,22); LLIL_SET_REG.d(temp0,LLIL_SUB.d(LLIL_REG.d(r5),LLIL_CONST.d(0x20))); LLIL_STORE.d(LLIL_REG.d(temp0),LLIL_REG.d(r1)); LLIL_SET_REG.d(temp0,LLIL_ADD.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x4))); LLIL_STORE.d(LLIL_REG.d(temp0),LLIL_REG.d(r2)); LLIL_SET_REG.d(temp0,LLIL_ADD.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x4))); LLIL_STORE.d(LLIL_REG.d(temp0),LLIL_REG.d(r3)); LLIL_SET_REG.d(temp0,LLIL_ADD.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x4))); LLIL_STORE.d(LLIL_REG.d(temp0),LLIL_REG.d(r5)); LLIL_SET_REG.d(temp0,LLIL_ADD.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x4))); LLIL_STORE.d(LLIL_REG.d(temp0),LLIL_REG.d(r6)); LLIL_SET_REG.d(temp0,LLIL_ADD.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x4))); LLIL_STORE.d(LLIL_REG.d(temp0),LLIL_REG.d(r9)); LLIL_SET_REG.d(temp0,LLIL_ADD.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x4))); LLIL_STORE.d(LLIL_REG.d(temp0),LLIL_REG.d(r11)); LLIL_SET_REG.d(temp0,LLIL_ADD.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x4))); LLIL_STORE.d(LLIL_REG.d(temp0),LLIL_REG.d(r12)); LLIL_SET_REG.d(temp0,LLIL_ADD.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x4))); LLIL_STORE.d(LLIL_REG.d(temp0),LLIL_REG.d(sp)); LLIL_SET_REG.d(temp0,LLIL_ADD.d(LLIL_REG.d(temp0),LLIL_CONST.b(0x4))); LLIL_SET_REG.d(r5,LLIL_SUB.d(LLIL_REG.d(r5),LLIL_CONST.d(0x24))); LLIL_GOTO(22)'), # vadd.f32 s0, s1, s2 ('A', b'\x81\x0a\x30\xee', 'LLIL_SET_REG.d(s0,LLIL_FADD.d(LLIL_REG.d(s1),LLIL_REG.d(s2)))'), # vsub.f32 s0, s1, s2 @@ -67,6 +233,16 @@ ('A', b'\x81\x0a\x20\xee', 'LLIL_SET_REG.d(s0,LLIL_FMUL.d(LLIL_REG.d(s1),LLIL_REG.d(s2)))'), # vdiv.f32 s0, s1, s2 ('A', b'\x81\x0a\x80\xee', 'LLIL_SET_REG.d(s0,LLIL_FDIV.d(LLIL_REG.d(s1),LLIL_REG.d(s2)))'), + # hvc #0 + ('A', b'\x70\x00\x40\xe1', 'LLIL_INTRINSIC([],__hvc,[LLIL_CONST.w(0x0)])'), + # smc #0 + ('A', b'\x70\x00\x60\xe1', 'LLIL_INTRINSIC([],__smc,[LLIL_CONST.b(0x0)])'), + # smc #0 + ('T', b'\xf0\xf7\xfa\x8d', 'LLIL_INTRINSIC([],__smc,[LLIL_CONST.b(0x0)])'), + # hint #0x5 + ('A', b'\x05\xf0\x20\xe3', 'LLIL_INTRINSIC([],__hint,[LLIL_CONST.b(0x5)])'), + # hint #0xf + ('T', b'\xf0\xbf', 'LLIL_INTRINSIC([],__hint,[LLIL_CONST.b(0xF)])'), # svc #0; svc #1; svc #2; svc #3 ('A', b'\x00\x00\x00\xef', 'LLIL_SET_REG.d(syscall_info,LLIL_CONST.d(0x0)); LLIL_SYSCALL()'), ('A', b'\x01\x00\x00\xef', 'LLIL_SET_REG.d(syscall_info,LLIL_CONST.d(0x1)); LLIL_SYSCALL()'), @@ -80,6 +256,236 @@ ('A', b'\x01\x00\xa0\xe1', 'LLIL_SET_REG.d(r0,LLIL_REG.d(r1))'), # nop ('A', b'\x00\xf0\x20\xe3', 'LLIL_NOP()'), + # clrex + ('A', b'\x1f\xf0\x7f\xf5', 'LLIL_INTRINSIC([],__clrex,[])'), + ('T', b'\xbf\xf3\x2f\x8f', 'LLIL_INTRINSIC([],__clrex,[])'), + # strexd r0, r2, r3, [r4] + ('T', b'\xc4\xe8\x70\x23', 'LLIL_INTRINSIC([r0],ExclusiveMonitorsPass,[LLIL_REG.d(r4),LLIL_CONST.b(0x8)]); LLIL_IF(LLIL_CMP_E.d(LLIL_REG.d(r0),LLIL_CONST.d(0x1)),2,4); LLIL_STORE.q(LLIL_REG.d(r4),LLIL_REG_SPLIT.d(r3,r2)); LLIL_GOTO(4)'), + # pld [r0] + ('A', b'\x00\xf0\xd0\xf5', 'LLIL_INTRINSIC([],__pld,[LLIL_REG.d(r0)])'), + ('T', b'\x90\xf8\x00\xf0', 'LLIL_INTRINSIC([],__pld,[LLIL_ADD.d(LLIL_REG.d(r0),LLIL_CONST.d(0x0))])'), + # bxj r0 + ('T', b'\xc0\xf3\x00\x8f', 'LLIL_JUMP(LLIL_REG.d(r0))'), + # pkhbt r0, r1, r2, lsl #8 + ('T', b'\xc1\xea\x02\x20', 'LLIL_SET_REG.d(r0,LLIL_OR.d(LLIL_AND.d(LLIL_REG.d(r1),LLIL_CONST.d(0xFFFF0000)),LLIL_AND.d(LLIL_LSL.d(LLIL_REG.d(r2),LLIL_CONST.d(0x8)),LLIL_CONST.d(0xFFFF))))'), + # pkhtb r0, r1, r2, asr #8 + ('T', b'\xc1\xea\x22\x20', 'LLIL_SET_REG.d(r0,LLIL_OR.d(LLIL_AND.d(LLIL_ASR.d(LLIL_REG.d(r2),LLIL_CONST.d(0x8)),LLIL_CONST.d(0xFFFF0000)),LLIL_AND.d(LLIL_REG.d(r1),LLIL_CONST.d(0xFFFF))))'), + # qadd r0, r1, r2 + ('A', b'\x51\x00\x02\xe1', saturating_scalar_expected('r0', 'r1', 'r2', 'qadd')), + # qadd r0, r1, r2 + ('T', b'\x82\xfa\x81\xf0', saturating_scalar_expected('r0', 'r1', 'r2', 'qadd')), + # qsub r0, r1, r2 + ('A', b'\x51\x00\x22\xe1', saturating_scalar_expected('r0', 'r1', 'r2', 'qsub')), + # qsub r0, r1, r2 + ('T', b'\x82\xfa\xa1\xf0', saturating_scalar_expected('r0', 'r1', 'r2', 'qsub')), + # qadd16 r0, r1, r2 + ('A', b'\x12\x0f\x21\xe6', saturating_scalar_expected('r0', 'r1', 'r2', 'qadd16')), + # qadd16 r0, r1, r2 + ('T', b'\x91\xfa\x12\xf0', saturating_scalar_expected('r0', 'r1', 'r2', 'qadd16')), + # qadd8 r0, r1, r2 + ('A', b'\x92\x0f\x21\xe6', saturating_scalar_expected('r0', 'r1', 'r2', 'qadd8')), + # qadd8 r0, r1, r2 + ('T', b'\x81\xfa\x12\xf0', saturating_scalar_expected('r0', 'r1', 'r2', 'qadd8')), + # qdadd r0, r1, r2 + ('A', b'\x51\x00\x42\xe1', saturating_scalar_expected('r0', 'r1', 'r2', 'qdadd')), + # qdadd r0, r1, r2 + ('T', b'\x82\xfa\x91\xf0', saturating_scalar_expected('r0', 'r1', 'r2', 'qdadd')), + # qdsub r0, r1, r2 + ('A', b'\x51\x00\x62\xe1', saturating_scalar_expected('r0', 'r1', 'r2', 'qdsub')), + # qdsub r0, r1, r2 + ('T', b'\x82\xfa\xb1\xf0', saturating_scalar_expected('r0', 'r1', 'r2', 'qdsub')), + # qsub16 r0, r1, r2 + ('A', b'\x72\x0f\x21\xe6', saturating_scalar_expected('r0', 'r1', 'r2', 'qsub16')), + # qsub16 r0, r1, r2 + ('T', b'\xd1\xfa\x12\xf0', saturating_scalar_expected('r0', 'r1', 'r2', 'qsub16')), + # qsub8 r0, r1, r2 + ('A', b'\xf2\x0f\x21\xe6', saturating_scalar_expected('r0', 'r1', 'r2', 'qsub8')), + # qsub8 r0, r1, r2 + ('T', b'\xc1\xfa\x12\xf0', saturating_scalar_expected('r0', 'r1', 'r2', 'qsub8')), + # ssat r0, #8, r1 + ('T', b'\x01\xf3\x07\x00', 'LLIL_INTRINSIC([r0],__ssat,[LLIL_CONST.d(0x8),LLIL_REG.d(r1)])'), + # ssat16 r0, #8, r1 + ('T', b'\x21\xf3\x07\x00', 'LLIL_INTRINSIC([r0],__ssat16,[LLIL_CONST.d(0x8),LLIL_REG.d(r1)])'), + # sadd16 r0, r1, r2 + ('T', b'\x91\xfa\x02\xf0', scalar_intrinsic_expected('r0', 'sadd16', 'r1', 'r2')), + # sadd8 r0, r1, r2 + ('T', b'\x81\xfa\x02\xf0', scalar_intrinsic_expected('r0', 'sadd8', 'r1', 'r2')), + # shadd16 r0, r1, r2 + ('T', b'\x91\xfa\x22\xf0', scalar_intrinsic_expected('r0', 'shadd16', 'r1', 'r2')), + # shadd8 r0, r1, r2 + ('T', b'\x81\xfa\x22\xf0', scalar_intrinsic_expected('r0', 'shadd8', 'r1', 'r2')), + # shasx r0, r1, r2 + ('T', b'\xa1\xfa\x22\xf0', 'LLIL_SET_REG.d(temp0,LLIL_SUB.d(LLIL_LOW_PART.w(LLIL_REG.d(r1)),LLIL_ASR.w(LLIL_REG.d(r2),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(temp1,LLIL_ADD.d(LLIL_ASR.w(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_LOW_PART.w(LLIL_REG.d(r2)))); LLIL_SET_REG.d(r0,LLIL_OR.d(LLIL_LSL.d(LLIL_LOW_PART.w(LLIL_ASR.w(LLIL_REG.d(temp1),LLIL_CONST.b(0x1))),LLIL_CONST.b(0x10)),LLIL_LOW_PART.w(LLIL_ASR.w(LLIL_REG.d(temp0),LLIL_CONST.b(0x1)))))'), + # uhadd16 r0, r1, r2 + ('T', b'\x91\xfa\x62\xf0', 'LLIL_SET_REG.d(temp0,LLIL_AND.w(LLIL_LSR.d(LLIL_ADD.d(LLIL_LOW_PART.w(LLIL_REG.d(r1)),LLIL_LOW_PART.w(LLIL_REG.d(r2))),LLIL_CONST.b(0x1)),LLIL_CONST.w(0xFFFF))); LLIL_SET_REG.d(temp1,LLIL_AND.w(LLIL_LSR.d(LLIL_ADD.d(LLIL_LSR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_LSR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x10))),LLIL_CONST.b(0x1)),LLIL_CONST.w(0xFFFF))); LLIL_SET_REG.d(r0,LLIL_OR.d(LLIL_LSL.d(LLIL_AND.w(LLIL_REG.d(temp1),LLIL_CONST.w(0xFFFF)),LLIL_CONST.b(0x10)),LLIL_AND.w(LLIL_REG.d(temp0),LLIL_CONST.w(0xFFFF))))'), + # uhadd8 r0, r1, r2 + ('T', b'\x81\xfa\x62\xf0', 'LLIL_SET_REG.b(temp0,LLIL_AND.b(LLIL_LSR.d(LLIL_ADD.d(LLIL_LOW_PART.b(LLIL_REG.d(r1)),LLIL_LOW_PART.b(LLIL_REG.d(r2))),LLIL_CONST.b(0x1)),LLIL_CONST.b(0xFF))); LLIL_SET_REG.b(temp1,LLIL_AND.b(LLIL_LSR.d(LLIL_ADD.d(LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x8))),LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x8)))),LLIL_CONST.b(0x1)),LLIL_CONST.b(0xFF))); LLIL_SET_REG.b(temp2,LLIL_AND.b(LLIL_LSR.d(LLIL_ADD.d(LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x10))),LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x10)))),LLIL_CONST.b(0x1)),LLIL_CONST.b(0xFF))); LLIL_SET_REG.b(temp3,LLIL_AND.b(LLIL_LSR.d(LLIL_ADD.d(LLIL_LSR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x18)),LLIL_LSR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x18))),LLIL_CONST.b(0x1)),LLIL_CONST.b(0xFF))); LLIL_SET_REG.d(r0,LLIL_OR.d(LLIL_OR.d(LLIL_LSL.d(LLIL_ZX.d(LLIL_REG.b(temp3)),LLIL_CONST.b(0x18)),LLIL_LSL.d(LLIL_ZX.d(LLIL_REG.b(temp2)),LLIL_CONST.b(0x10))),LLIL_OR.d(LLIL_LSL.d(LLIL_ZX.d(LLIL_REG.b(temp1)),LLIL_CONST.b(0x8)),LLIL_REG.b(temp0))))'), + # uqadd16 r0, r1, r2 + ('A', b'\x12\x0f\x61\xe6', saturating_scalar_expected('r0', 'r1', 'r2', 'uqadd16')), + # uqadd16 r0, r1, r2 + ('T', b'\x91\xfa\x52\xf0', saturating_scalar_expected('r0', 'r1', 'r2', 'uqadd16')), + # uqadd8 r0, r1, r2 + ('A', b'\x92\x0f\x61\xe6', saturating_scalar_expected('r0', 'r1', 'r2', 'uqadd8')), + # uqadd8 r0, r1, r2 + ('T', b'\x81\xfa\x52\xf0', saturating_scalar_expected('r0', 'r1', 'r2', 'uqadd8')), + # sasx r0, r1, r2 + ('T', b'\xa1\xfa\x02\xf0', 'LLIL_SET_REG.d(temp0,LLIL_SUB.d(LLIL_LOW_PART.w(LLIL_REG.d(r1)),LLIL_ASR.w(LLIL_REG.d(r2),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(temp1,LLIL_ADD.d(LLIL_ASR.w(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_LOW_PART.w(LLIL_REG.d(r2)))); LLIL_SET_REG.d(r0,LLIL_OR.d(LLIL_LSL.d(LLIL_REG.w(temp1),LLIL_CONST.b(0x10)),LLIL_REG.w(temp0)))'), + # ssax r0, r1, r2 + ('T', b'\xe1\xfa\x02\xf0', 'LLIL_SET_REG.d(temp0,LLIL_ADD.d(LLIL_LOW_PART.w(LLIL_REG.d(r1)),LLIL_ASR.w(LLIL_REG.d(r2),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(temp1,LLIL_SUB.d(LLIL_ASR.w(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_LOW_PART.w(LLIL_REG.d(r2)))); LLIL_SET_REG.d(r0,LLIL_OR.d(LLIL_LSL.d(LLIL_REG.w(temp1),LLIL_CONST.b(0x10)),LLIL_REG.w(temp0)))'), + # qsax r0, r1, r2 + ('T', b'\xe1\xfa\x12\xf0', 'LLIL_INTRINSIC([r0],__qsax,[LLIL_REG.d(r1),LLIL_REG.d(r2)])'), + # uasx r0, r1, r2 + ('T', b'\xa1\xfa\x42\xf0', 'LLIL_SET_REG.d(temp0,LLIL_SUB.d(LLIL_LOW_PART.w(LLIL_REG.d(r1)),LLIL_LSR.w(LLIL_REG.d(r2),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(temp1,LLIL_ADD.d(LLIL_LSR.w(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_LOW_PART.w(LLIL_REG.d(r2)))); LLIL_SET_REG.d(r0,LLIL_OR.d(LLIL_LSL.d(LLIL_REG.w(temp1),LLIL_CONST.b(0x10)),LLIL_REG.w(temp0)))'), + # usax r0, r1, r2 + ('T', b'\xe1\xfa\x42\xf0', 'LLIL_SET_REG.d(temp0,LLIL_ADD.d(LLIL_LOW_PART.w(LLIL_REG.d(r1)),LLIL_LSR.w(LLIL_REG.d(r2),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(temp1,LLIL_SUB.d(LLIL_LSR.w(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_LOW_PART.w(LLIL_REG.d(r2)))); LLIL_SET_REG.d(r0,LLIL_OR.d(LLIL_LSL.d(LLIL_REG.w(temp1),LLIL_CONST.b(0x10)),LLIL_REG.w(temp0)))'), + # uqasx r0, r1, r2 + ('T', b'\xa1\xfa\x52\xf0', 'LLIL_INTRINSIC([r0],__uqasx,[LLIL_REG.d(r1),LLIL_REG.d(r2)])'), + # uqsax r0, r1, r2 + ('T', b'\xe1\xfa\x52\xf0', 'LLIL_INTRINSIC([r0],__uqsax,[LLIL_REG.d(r1),LLIL_REG.d(r2)])'), + # uhasx r0, r1, r2 + ('T', b'\xa1\xfa\x62\xf0', 'LLIL_SET_REG.d(temp0,LLIL_SUB.d(LLIL_LOW_PART.w(LLIL_REG.d(r1)),LLIL_LSR.w(LLIL_REG.d(r2),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(temp1,LLIL_ADD.d(LLIL_LSR.w(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_LOW_PART.w(LLIL_REG.d(r2)))); LLIL_SET_REG.d(r0,LLIL_OR.d(LLIL_LSL.d(LLIL_LOW_PART.w(LLIL_LSR.w(LLIL_REG.d(temp1),LLIL_CONST.b(0x1))),LLIL_CONST.b(0x10)),LLIL_LOW_PART.w(LLIL_LSR.w(LLIL_REG.d(temp0),LLIL_CONST.b(0x1)))))'), + # ssub16 r0, r1, r2 + ('T', b'\xd1\xfa\x02\xf0', 'LLIL_SET_REG.d(temp0,LLIL_AND.w(LLIL_SUB.w(LLIL_REG.d(r1),LLIL_REG.d(r2)),LLIL_CONST.w(0xFFFF))); LLIL_SET_REG.d(temp1,LLIL_AND.w(LLIL_SUB.w(LLIL_ASR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_ASR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x10))),LLIL_CONST.w(0xFFFF))); LLIL_SET_REG.d(r0,LLIL_OR.d(LLIL_LSL.d(LLIL_AND.w(LLIL_REG.d(temp1),LLIL_CONST.w(0xFFFF)),LLIL_CONST.b(0x10)),LLIL_AND.w(LLIL_REG.d(temp0),LLIL_CONST.w(0xFFFF))))'), + # ssub8 r0, r1, r2 + ('T', b'\xc1\xfa\x02\xf0', scalar_intrinsic_expected('r0', 'ssub8', 'r1', 'r2')), + # shsub16 r0, r1, r2 + ('T', b'\xd1\xfa\x22\xf0', scalar_intrinsic_expected('r0', 'shsub16', 'r1', 'r2')), + # shsub8 r0, r1, r2 + ('T', b'\xc1\xfa\x22\xf0', scalar_intrinsic_expected('r0', 'shsub8', 'r1', 'r2')), + # uhsub16 r0, r1, r2 + ('T', b'\xd1\xfa\x62\xf0', scalar_intrinsic_expected('r0', 'uhsub16', 'r1', 'r2')), + # uhsub8 r0, r1, r2 + ('T', b'\xc1\xfa\x62\xf0', scalar_intrinsic_expected('r0', 'uhsub8', 'r1', 'r2')), + # usub16 r0, r1, r2 + ('T', b'\xd1\xfa\x42\xf0', scalar_intrinsic_expected('r0', 'usub16', 'r1', 'r2')), + # usub8 r0, r1, r2 + ('T', b'\xc1\xfa\x42\xf0', scalar_intrinsic_expected('r0', 'usub8', 'r1', 'r2')), + # uqsub16 r0, r1, r2 + ('A', b'\x72\x0f\x61\xe6', saturating_scalar_expected('r0', 'r1', 'r2', 'uqsub16')), + # uqsub16 r0, r1, r2 + ('T', b'\xd1\xfa\x52\xf0', saturating_scalar_expected('r0', 'r1', 'r2', 'uqsub16')), + # uqsub8 r0, r1, r2 + ('A', b'\xf2\x0f\x61\xe6', saturating_scalar_expected('r0', 'r1', 'r2', 'uqsub8')), + # uqsub8 r0, r1, r2 + ('T', b'\xc1\xfa\x52\xf0', saturating_scalar_expected('r0', 'r1', 'r2', 'uqsub8')), + # dsb sy + ('A', b'\x4f\xf0\x7f\xf5', 'LLIL_INTRINSIC([],__dsb_SY,[])'), + # dmb sy + ('A', b'\x5f\xf0\x7f\xf5', 'LLIL_INTRINSIC([],__dmb_SY,[])'), + # isb sy + ('A', b'\x6f\xf0\x7f\xf5', 'LLIL_INTRINSIC([],__isb,[])'), + # yield + ('A', b'\x01\xf0\x20\xe3', 'LLIL_INTRINSIC([],__yield,[])'), + # wfe + ('A', b'\x02\xf0\x20\xe3', 'LLIL_INTRINSIC([],__wfe,[])'), + # wfi + ('A', b'\x03\xf0\x20\xe3', 'LLIL_INTRINSIC([],__wfi,[])'), + # sev + ('A', b'\x04\xf0\x20\xe3', 'LLIL_INTRINSIC([],__sev,[])'), + # dbg #0 + ('A', b'\xf0\xf0\x20\xe3', 'LLIL_INTRINSIC([],__dbg,[LLIL_CONST.b(0x0)])'), + # cps #0x13 + ('A', b'\x13\x00\x02\xf1', 'LLIL_INTRINSIC([],__cps,[LLIL_CONST.b(0x13)])'), + # cpsid i + ('A', b'\x80\x00\x0c\xf1', 'LLIL_INTRINSIC([],__cpsid,[LLIL_CONST.b(0x2),LLIL_CONST.b(0x0)])'), + # cpsie i + ('A', b'\x80\x00\x08\xf1', 'LLIL_INTRINSIC([],__cpsie,[LLIL_CONST.b(0x2),LLIL_CONST.b(0x0)])'), + # cpsid i (Thumb) + ('T', b'\x72\xb6', 'LLIL_INTRINSIC([],__cpsid,[LLIL_CONST.b(0x2),LLIL_CONST.b(0x0)])'), + # cpsie i (Thumb) + ('T', b'\x62\xb6', 'LLIL_INTRINSIC([],__cpsie,[LLIL_CONST.b(0x2),LLIL_CONST.b(0x0)])'), + # setend le (Thumb) + ('T', b'\x46\xb6', 'LLIL_INTRINSIC([],__setend,[LLIL_CONST.b(0x0)])'), + # setend be (Thumb) + ('T', b'\x49\xb6', 'LLIL_INTRINSIC([],__setend,[LLIL_CONST.b(0x1)])'), + # vmov.f32 d0, #2.000000 + ('A', b'\x60\x0a\xb0\xee', 'LLIL_SET_REG.q(d0,LLIL_CONST.q(0x40000000))'), + # vmov d0, r0, r1 + ('A', b'\x10\x0b\x41\xec', 'LLIL_SET_REG.q(d0,LLIL_REG_SPLIT.d(r1,r0))'), + # vst1.8 {d16, d17}, [r3:0x40] + ('A', b'\x1f\x0a\x43\xf4', 'LLIL_STORE.q(LLIL_REG.d(r3),LLIL_REG.q(d16)); LLIL_STORE.q(LLIL_ADD.d(LLIL_REG.d(r3),LLIL_CONST.d(0x8)),LLIL_REG.q(d17))'), + # vld1.64 {d16}, [r12]! + ('A', b'\xcd\x07\x6c\xf4', 'LLIL_SET_REG.q(d16,LLIL_LOAD.q(LLIL_REG.d(r12))); LLIL_SET_REG.d(r12,LLIL_ADD.d(LLIL_REG.d(r12),LLIL_CONST.d(0x8)))'), + # vpush {d8, d9} + ('A', b'\x04\x8b\x2d\xed', 'LLIL_PUSH.q(LLIL_REG.q(d8)); LLIL_PUSH.q(LLIL_REG.q(d9))'), + # vpop {d8, d9} + ('A', b'\x04\x8b\xbd\xec', 'LLIL_SET_REG.q(d8,LLIL_POP.q()); LLIL_SET_REG.q(d9,LLIL_POP.q())'), + # vcmpe.f32 s0, #0.000000 + ('A', b'\xc0\x0a\xb5\xee', 'LLIL_SET_FLAG(n,LLIL_FCMP_LT.d(LLIL_REG.d(s0),LLIL_FLOAT_CONST.d(0.0))); LLIL_SET_FLAG(z,LLIL_FCMP_E.d(LLIL_REG.d(s0),LLIL_FLOAT_CONST.d(0.0))); LLIL_SET_FLAG(c,LLIL_NOT.b(LLIL_FCMP_LT.d(LLIL_REG.d(s0),LLIL_FLOAT_CONST.d(0.0)))); LLIL_SET_FLAG(v,LLIL_FCMP_UO.d(LLIL_REG.d(s0),LLIL_FLOAT_CONST.d(0.0)))'), + # vcmpe.f32 s24, s18 + ('A', b'\xc9\xca\xb4\xee', 'LLIL_SET_FLAG(n,LLIL_FCMP_LT.d(LLIL_REG.d(s24),LLIL_REG.d(s18))); LLIL_SET_FLAG(z,LLIL_FCMP_E.d(LLIL_REG.d(s24),LLIL_REG.d(s18))); LLIL_SET_FLAG(c,LLIL_NOT.b(LLIL_FCMP_LT.d(LLIL_REG.d(s24),LLIL_REG.d(s18)))); LLIL_SET_FLAG(v,LLIL_FCMP_UO.d(LLIL_REG.d(s24),LLIL_REG.d(s18)))'), + # vcmpe.f64 d8, d16 + ('A', b'\xe0\x8b\xb4\xee', 'LLIL_SET_FLAG(n,LLIL_FCMP_LT.q(LLIL_REG.q(d8),LLIL_REG.q(d16))); LLIL_SET_FLAG(z,LLIL_FCMP_E.q(LLIL_REG.q(d8),LLIL_REG.q(d16))); LLIL_SET_FLAG(c,LLIL_NOT.b(LLIL_FCMP_LT.q(LLIL_REG.q(d8),LLIL_REG.q(d16)))); LLIL_SET_FLAG(v,LLIL_FCMP_UO.q(LLIL_REG.q(d8),LLIL_REG.q(d16)))'), + # vdup.32 d16, r1 + ('A', b'\x90\x1b\x80\xee', 'LLIL_INTRINSIC([d16],__vdup,[LLIL_CONST.b(0x20),LLIL_REG.d(r1),LLIL_CONST.b(0x0)])'), + # vdup.32 d8, r7 + ('A', b'\x10\x7b\x88\xee', 'LLIL_INTRINSIC([d8],__vdup,[LLIL_CONST.b(0x20),LLIL_REG.d(r7),LLIL_CONST.b(0x0)])'), + # vdup.8 d16, d1[7] + ('T', b'\xff\xff\x01\x0c', 'LLIL_INTRINSIC([d16],__vdup,[LLIL_CONST.b(0x8),LLIL_REG.q(d1),LLIL_CONST.b(0x7)])'), + # vorr d8, d17, d16 + ('A', b'\xb0\x81\x21\xf2', 'LLIL_SET_REG.q(d8,LLIL_OR.q(LLIL_REG.q(d17),LLIL_REG.q(d16)))'), + # vand d0, d16, d6 + ('T', b'\x00\xef\x96\x01', 'LLIL_SET_REG.q(d0,LLIL_AND.q(LLIL_REG.q(d16),LLIL_REG.q(d6)))'), + # vshr.u64 d16, d16, #0x20 + ('A', b'\xb0\x00\xe0\xf3', 'LLIL_SET_REG.q(d16,LLIL_LSR.q(LLIL_REG.q(d16),LLIL_CONST.b(0x20)))'), + # vshr.s64 d8, d8, #0x20 + ('A', b'\x98\x80\xa0\xf2', 'LLIL_SET_REG.q(d8,LLIL_ASR.q(LLIL_REG.q(d8),LLIL_CONST.b(0x20)))'), + # vshr.u32 d16, d24, #0xf + ('T', b'\xf1\xff\x38\x00', 'LLIL_INTRINSIC([d16],__vshr,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x1),LLIL_REG.q(d24),LLIL_CONST.q(0xF)])'), + # vrshr.u32 d16, d18, #0x10 + ('T', b'\xf0\xff\x32\x02', 'LLIL_INTRINSIC([d16],__vrshr,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x1),LLIL_REG.q(d18),LLIL_CONST.q(0x10)])'), + # vrshl.u8 d0, d15, d16 + ('T', b'\x00\xff\x8f\x05', 'LLIL_INTRINSIC([d0],__vrshl,[LLIL_CONST.b(0x8),LLIL_CONST.b(0x1),LLIL_REG.q(d15),LLIL_REG.q(d16)])'), + # vqrshl.u8 d0, d4, d16 + ('T', b'\x00\xff\x94\x05', 'LLIL_INTRINSIC([d0],__vqrshl,[LLIL_CONST.b(0x8),LLIL_CONST.b(0x1),LLIL_CONST.b(0x1),LLIL_REG.q(d4),LLIL_REG.q(d16)])'), + # vqrshl.s8 d0, d2, d16 + ('T', b'\x00\xef\x92\x05', 'LLIL_INTRINSIC([d0],__vqrshl,[LLIL_CONST.b(0x8),LLIL_CONST.b(0x0),LLIL_CONST.b(0x0),LLIL_REG.q(d2),LLIL_REG.q(d16)])'), + # vsra.u32 d16, d19, #0xf + ('T', b'\xf1\xff\x33\x01', 'LLIL_INTRINSIC([d16],__vsra,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x1),LLIL_REG.q(d16),LLIL_REG.q(d19),LLIL_CONST.q(0xF)])'), + # vrsra.u32 d26, d19, #0x10 + ('T', b'\xf0\xff\x33\xa3', 'LLIL_INTRINSIC([d26],__vrsra,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x1),LLIL_REG.q(d26),LLIL_REG.q(d19),LLIL_CONST.q(0x10)])'), + # vsri.32 d16, d16, #0x10 + ('T', b'\xf0\xff\x30\x04', 'LLIL_INTRINSIC([d16],__vsri,[LLIL_CONST.b(0x20),LLIL_REG.q(d16),LLIL_REG.q(d16),LLIL_CONST.q(0x10)])'), + # vsli.32 d16, d23, #0x10 + ('T', b'\xf0\xff\x37\x05', 'LLIL_INTRINSIC([d16],__vsli,[LLIL_CONST.b(0x20),LLIL_REG.q(d16),LLIL_REG.q(d23),LLIL_CONST.q(0x10)])'), + # vshl.i64 d17, d18, #0x7 + ('A', b'\xb2\x15\xc7\xf2', 'LLIL_SET_REG.q(d17,LLIL_LSL.q(LLIL_REG.q(d18),LLIL_CONST.b(0x7)))'), + # vshl.i64 d29, d25, #0x20 + ('T', b'\xe0\xef\xb9\xd5', 'LLIL_SET_REG.q(d29,LLIL_LSL.q(LLIL_REG.q(d25),LLIL_CONST.b(0x20)))'), + # vshll.u32 q8, d25, #0x10 + ('T', b'\xf0\xff\x39\x0a', 'LLIL_INTRINSIC([q8],__vshll,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x1),LLIL_REG.q(d25),LLIL_CONST.q(0x10)])'), + # vqshl.u32 d16, d21, #0x10 + ('T', b'\xf0\xff\x35\x07', 'LLIL_INTRINSIC([d16],__vqshl,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x1),LLIL_CONST.b(0x1),LLIL_REG.q(d21),LLIL_CONST.q(0x10)])'), + # vqshl.u8 d13, d8, d10 + ('T', b'\x0a\xff\x18\xd4', 'LLIL_INTRINSIC([d13],__vqshl,[LLIL_CONST.b(0x8),LLIL_CONST.b(0x1),LLIL_CONST.b(0x1),LLIL_REG.q(d8),LLIL_REG.q(d10)])'), + # vqshlu.s32 d16, d28, #0x11 + ('T', b'\xf1\xff\x3c\x06', 'LLIL_INTRINSIC([d16],__vqshl,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x0),LLIL_CONST.b(0x1),LLIL_REG.q(d28),LLIL_CONST.q(0x11)])'), + # vqshrun.s64 d17, q9, #0xf + ('T', b'\xf1\xff\x32\x18', 'LLIL_INTRINSIC([d17],__vqshrun,[LLIL_CONST.b(0x40),LLIL_CONST.b(0x0),LLIL_CONST.b(0x1),LLIL_REG.o(q9),LLIL_CONST.o(0xF)])'), + # vqshrn.u64 d31, q9, #0xe + ('T', b'\xf2\xff\x32\xf9', 'LLIL_INTRINSIC([d31],__vqshrn,[LLIL_CONST.b(0x40),LLIL_CONST.b(0x1),LLIL_CONST.b(0x1),LLIL_REG.o(q9),LLIL_CONST.o(0xE)])'), + # vqrshrn.u64 d31, q9, #0xa + ('T', b'\xf6\xff\x72\xf9', 'LLIL_INTRINSIC([d31],__vqrshrn,[LLIL_CONST.b(0x40),LLIL_CONST.b(0x1),LLIL_CONST.b(0x1),LLIL_REG.o(q9),LLIL_CONST.o(0xA)])'), + # vqrshrun.s64 d27, q9, #0xa + ('T', b'\xf6\xff\x72\xb8', 'LLIL_INTRINSIC([d27],__vqrshrun,[LLIL_CONST.b(0x40),LLIL_CONST.b(0x0),LLIL_CONST.b(0x1),LLIL_REG.o(q9),LLIL_CONST.o(0xA)])'), + # vqmovun.s32 d16, q9 + ('T', b'\xf6\xff\x62\x02', 'LLIL_INTRINSIC([d16],__vqmovun,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x0),LLIL_CONST.b(0x1),LLIL_REG.o(q9)])'), + # vshll.u32 q10, d19, #0x10 + ('T', b'\xf0\xff\x33\x4a', 'LLIL_INTRINSIC([q10],__vshll,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x1),LLIL_REG.q(d19),LLIL_CONST.q(0x10)])'), + # vqadd.u16 d0, d11, d8 + ('T', b'\x1b\xff\x18\x00', 'LLIL_INTRINSIC([d0],__vqadd,[LLIL_CONST.b(0x10),LLIL_CONST.b(0x1),LLIL_REG.q(d11),LLIL_REG.q(d8)])'), + # vqadd.u8 d16, d6, d10 + ('T', b'\x46\xff\x1a\x00', 'LLIL_INTRINSIC([d16],__vqadd,[LLIL_CONST.b(0x8),LLIL_CONST.b(0x1),LLIL_REG.q(d6),LLIL_REG.q(d10)])'), + # vmax.u8 d8, d13, d24 + ('T', b'\x0d\xff\x28\x86', 'LLIL_INTRINSIC([d8],__vmax,[LLIL_CONST.b(0x8),LLIL_CONST.b(0x1),LLIL_REG.q(d13),LLIL_REG.q(d24)])'), + # vrev64.8 d16, d8 + ('T', b'\xf0\xff\x08\x00', 'LLIL_INTRINSIC([d16],__vrev64,[LLIL_CONST.b(0x8),LLIL_REG.q(d8)])'), + # vext.8 d16, d8, d16, #4 + ('T', b'\xf8\xef\x20\x04', 'LLIL_INTRINSIC([d16],__vext,[LLIL_CONST.b(0x8),LLIL_REG.q(d8),LLIL_REG.q(d16),LLIL_CONST.b(0x4)])'), + # vpmin.f32 d4, d1, d19 + ('T', b'\x21\xff\x23\x4f', 'LLIL_INTRINSIC([d4],__vpmin,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x0),LLIL_REG.q(d1),LLIL_REG.q(d19)])'), + # vshl.u64 d16, d16, d17 + ('A', b'\xa0\x04\x71\xf3', 'LLIL_IF(LLIL_CMP_SLT.q(LLIL_REG.q(d17),LLIL_CONST.q(0x0)),1,3); LLIL_SET_REG.q(d16,LLIL_LSR.q(LLIL_REG.q(d16),LLIL_NEG.q(LLIL_REG.q(d17)))); LLIL_GOTO(5); LLIL_SET_REG.q(d16,LLIL_LSL.q(LLIL_REG.q(d16),LLIL_REG.q(d17))); LLIL_GOTO(5)'), # vmov.i32 d16, #0 ('A', b'\x10\x00\xc0\xf2', 'LLIL_SET_REG.q(d16,LLIL_CONST.q(0x0))'), # vmov.i32 q8, #0 @@ -100,6 +506,10 @@ ('A', b'\x02\x0a\x83\xed', 'LLIL_STORE.d(LLIL_ADD.d(LLIL_REG.d(r3),LLIL_CONST.d(0x8)),LLIL_REG.d(s0))'), # vstr d16, [r3, #0x8] ('A', b'\x02\x0b\xc3\xed', 'LLIL_STORE.q(LLIL_ADD.d(LLIL_REG.d(r3),LLIL_CONST.d(0x8)),LLIL_REG.q(d16))'), + # vldmia r0, {s0, s1, s2, s3} + ('A', b'\x04\x0a\x90\xec', 'LLIL_SET_REG.d(s0,LLIL_LOAD.d(LLIL_REG.d(r0))); LLIL_SET_REG.d(s1,LLIL_LOAD.d(LLIL_ADD.d(LLIL_REG.d(r0),LLIL_CONST.d(0x4)))); LLIL_SET_REG.d(s2,LLIL_LOAD.d(LLIL_ADD.d(LLIL_REG.d(r0),LLIL_CONST.d(0x8)))); LLIL_SET_REG.d(s3,LLIL_LOAD.d(LLIL_ADD.d(LLIL_REG.d(r0),LLIL_CONST.d(0xC))))'), + # vstmia r0, {s0, s1, s2, s3} + ('A', b'\x04\x0a\x80\xec', 'LLIL_STORE.d(LLIL_REG.d(r0),LLIL_REG.d(s0)); LLIL_STORE.d(LLIL_ADD.d(LLIL_REG.d(r0),LLIL_CONST.d(0x4)),LLIL_REG.d(s1)); LLIL_STORE.d(LLIL_ADD.d(LLIL_REG.d(r0),LLIL_CONST.d(0x8)),LLIL_REG.d(s2)); LLIL_STORE.d(LLIL_ADD.d(LLIL_REG.d(r0),LLIL_CONST.d(0xC)),LLIL_REG.d(s3))'), # orr r0, r1, r3, lsl r4 ('A', b'\x13\x04\x81\xe1', 'LLIL_SET_REG.d(r0,LLIL_OR.d(LLIL_REG.d(r1),LLIL_LSL.d(LLIL_REG.d(r3),LLIL_AND.d(LLIL_REG.d(r4),LLIL_CONST.d(0xFF)))))'), @@ -110,15 +520,203 @@ # cmp r1, r2, lsl #7 ('T', b'\xb1\xeb\xc2\x1f', 'LLIL_SUB.d{*}(LLIL_REG.d(r1),LLIL_LSL.d(LLIL_REG.d(r2),LLIL_CONST.d(0x7)))'), # uadd8 r5, r2, r12 - ('T', b'\x82\xfa\x4c\xf5', 'LLIL_SET_REG.d(temp0,LLIL_ADD.b(LLIL_LOW_PART.b(LLIL_REG.d(r2)),LLIL_LOW_PART.b(LLIL_REG.d(r12)))); LLIL_SET_REG.d(temp1,LLIL_ADD.b(LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x8))),LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r12),LLIL_CONST.b(0x8))))); LLIL_SET_REG.d(temp2,LLIL_ADD.b(LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x10))),LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r12),LLIL_CONST.b(0x10))))); LLIL_SET_REG.d(temp3,LLIL_ADD.b(LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x18))),LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r12),LLIL_CONST.b(0x18))))); LLIL_SET_REG.d(r5,LLIL_OR.d(LLIL_OR.d(LLIL_LSL.d(LLIL_REG.b(temp3),LLIL_CONST.b(0x18)),LLIL_LSL.d(LLIL_REG.b(temp2),LLIL_CONST.b(0x10))),LLIL_OR.d(LLIL_LSL.d(LLIL_REG.b(temp1),LLIL_CONST.b(0x8)),LLIL_REG.b(temp0))))'), + ('T', b'\x82\xfa\x4c\xf5', 'LLIL_SET_REG.d(temp0,LLIL_ADD.b(LLIL_LOW_PART.b(LLIL_REG.d(r2)),LLIL_LOW_PART.b(LLIL_REG.d(r12)))); LLIL_SET_REG.d(temp1,LLIL_ADD.b(LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x8))),LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r12),LLIL_CONST.b(0x8))))); LLIL_SET_REG.d(temp2,LLIL_ADD.b(LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x10))),LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r12),LLIL_CONST.b(0x10))))); LLIL_SET_REG.d(temp3,LLIL_ADD.b(LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x18))),LLIL_LOW_PART.b(LLIL_LSR.d(LLIL_REG.d(r12),LLIL_CONST.b(0x18))))); LLIL_SET_REG.d(r5,LLIL_OR.d(LLIL_OR.d(LLIL_LSL.d(LLIL_ZX.d(LLIL_REG.b(temp3)),LLIL_CONST.b(0x18)),LLIL_LSL.d(LLIL_ZX.d(LLIL_REG.b(temp2)),LLIL_CONST.b(0x10))),LLIL_OR.d(LLIL_LSL.d(LLIL_ZX.d(LLIL_REG.b(temp1)),LLIL_CONST.b(0x8)),LLIL_REG.b(temp0))))'), # ldrex r0, [r1, #4] ('T', b'\x51\xe8\x01\x0f', 'LLIL_SET_REG.d(r0,LLIL_LOAD.d(LLIL_ADD.d(LLIL_REG.d(r1),LLIL_CONST.d(0x4))))'), # ldrexb r0, [r1] ('T', b'\xd1\xe8\x4f\x0f', 'LLIL_SET_REG.d(r0,LLIL_ZX.d(LLIL_LOAD.b(LLIL_REG.d(r1))))'), # ldrexh r0, [r1] ('T', b'\xd1\xe8\x5f\x0f', 'LLIL_SET_REG.d(r0,LLIL_ZX.d(LLIL_LOAD.w(LLIL_REG.d(r1))))'), + # vmov.32 d16[0], r3 + ('T', b'\x00\xee\x90\x3b', 'LLIL_SET_REG.q(d16,LLIL_OR.q(LLIL_AND.q(LLIL_REG.q(d16),LLIL_CONST.q(0xFFFFFFFF00000000)),LLIL_ZX.q(LLIL_REG.d(r3))))'), + # vst1.8 {d16, d17}, [r11] + ('T', b'\x4b\xf9\x0f\x0a', 'LLIL_STORE.q(LLIL_REG.d(r11),LLIL_REG.q(d16)); LLIL_STORE.q(LLIL_ADD.d(LLIL_REG.d(r11),LLIL_CONST.d(0x8)),LLIL_REG.q(d17))'), + # vst1.64 {d16, d17}, [r1] + ('T', b'\x41\xf9\xcf\x0a', 'LLIL_STORE.q(LLIL_REG.d(r1),LLIL_REG.q(d16)); LLIL_STORE.q(LLIL_ADD.d(LLIL_REG.d(r1),LLIL_CONST.d(0x8)),LLIL_REG.q(d17))'), + # vst1.32 {d16, d17}, [r0] + ('T', b'\x40\xf9\x8f\x0a', 'LLIL_STORE.q(LLIL_REG.d(r0),LLIL_REG.q(d16)); LLIL_STORE.q(LLIL_ADD.d(LLIL_REG.d(r0),LLIL_CONST.d(0x8)),LLIL_REG.q(d17))'), + # vst1.16 {d10}, [r1] + ('T', b'\x01\xf9\x4f\xa7', 'LLIL_STORE.q(LLIL_REG.d(r1),LLIL_REG.q(d10))'), + # vst4.16 {d20, d21, d22, d23}, [r8:0x40], r1 + ('T', b'\x48\xf9\x51\x40', 'LLIL_INTRINSIC([],__vst4,[LLIL_REG.d(r8),LLIL_CONST.b(0x10),LLIL_CONST.b(0x40),LLIL_CONST.b(0xFF),LLIL_REG.q(d20),LLIL_REG.q(d21),LLIL_REG.q(d22),LLIL_REG.q(d23)]); LLIL_SET_REG.d(r8,LLIL_ADD.d(LLIL_REG.d(r8),LLIL_REG.d(r1)))'), + # vst2.8 {d8, d9, d10, d11}, [r0:0x40], r10 + ('T', b'\x00\xf9\x1a\x83', 'LLIL_INTRINSIC([],__vst2,[LLIL_REG.d(r0),LLIL_CONST.b(0x8),LLIL_CONST.b(0x40),LLIL_CONST.b(0xFF),LLIL_REG.q(d8),LLIL_REG.q(d9),LLIL_REG.q(d10),LLIL_REG.q(d11)]); LLIL_SET_REG.d(r0,LLIL_ADD.d(LLIL_REG.d(r0),LLIL_REG.d(r10)))'), + # vst4.16 {d22[3], d24[3], d26[3], d28[3]}, [r0:0x40], r7 + ('T', b'\xc0\xf9\xf7\x67', 'LLIL_INTRINSIC([],__vst4,[LLIL_REG.d(r0),LLIL_CONST.b(0x10),LLIL_CONST.b(0x40),LLIL_CONST.b(0x3),LLIL_REG.q(d22),LLIL_REG.q(d24),LLIL_REG.q(d26),LLIL_REG.q(d28)]); LLIL_SET_REG.d(r0,LLIL_ADD.d(LLIL_REG.d(r0),LLIL_REG.d(r7)))'), + # vld4.16 {d30, d0, d2, d4}, [r9:0x80], r10 + ('T', b'\x69\xf9\x6a\xe1', 'LLIL_INTRINSIC([d30,d0,d2,d4],__vld4,[LLIL_REG.d(r9),LLIL_CONST.b(0x10),LLIL_CONST.b(0x80),LLIL_CONST.b(0xFF)]); LLIL_SET_REG.d(r9,LLIL_ADD.d(LLIL_REG.d(r9),LLIL_REG.d(r10)))'), + # vld2.16 {d17, d18}, [r11:0x80], r10 + ('T', b'\x6b\xf9\x6a\x18', 'LLIL_INTRINSIC([d17,d18],__vld2,[LLIL_REG.d(r11),LLIL_CONST.b(0x10),LLIL_CONST.b(0x80),LLIL_CONST.b(0xFF)]); LLIL_SET_REG.d(r11,LLIL_ADD.d(LLIL_REG.d(r11),LLIL_REG.d(r10)))'), + # vld1.8 {d18, d19}, [r7] + ('T', b'\x67\xf9\x0f\x2a', 'LLIL_SET_REG.q(d18,LLIL_LOAD.q(LLIL_REG.d(r7))); LLIL_SET_REG.q(d19,LLIL_LOAD.q(LLIL_ADD.d(LLIL_REG.d(r7),LLIL_CONST.d(0x8))))'), + # vld1.64 {d16, d17}, [r6] + ('T', b'\x66\xf9\xcf\x0a', 'LLIL_SET_REG.q(d16,LLIL_LOAD.q(LLIL_REG.d(r6))); LLIL_SET_REG.q(d17,LLIL_LOAD.q(LLIL_ADD.d(LLIL_REG.d(r6),LLIL_CONST.d(0x8))))'), + # vld1.16 {d18}, [r7] + ('T', b'\x67\xf9\x4f\x27', 'LLIL_SET_REG.q(d18,LLIL_LOAD.q(LLIL_REG.d(r7)))'), + # vcmpe.f64 d8, d16 + ('T', b'\xb4\xee\xe0\x8b', 'LLIL_SET_FLAG(n,LLIL_FCMP_LT.q(LLIL_REG.q(d8),LLIL_REG.q(d16))); LLIL_SET_FLAG(z,LLIL_FCMP_E.q(LLIL_REG.q(d8),LLIL_REG.q(d16))); LLIL_SET_FLAG(c,LLIL_NOT.b(LLIL_FCMP_LT.q(LLIL_REG.q(d8),LLIL_REG.q(d16)))); LLIL_SET_FLAG(v,LLIL_FCMP_UO.q(LLIL_REG.q(d8),LLIL_REG.q(d16)))'), + # vcmpe.f32 s24, s22 + ('T', b'\xb4\xee\xcb\xca', 'LLIL_SET_FLAG(n,LLIL_FCMP_LT.d(LLIL_REG.d(s24),LLIL_REG.d(s22))); LLIL_SET_FLAG(z,LLIL_FCMP_E.d(LLIL_REG.d(s24),LLIL_REG.d(s22))); LLIL_SET_FLAG(c,LLIL_NOT.b(LLIL_FCMP_LT.d(LLIL_REG.d(s24),LLIL_REG.d(s22)))); LLIL_SET_FLAG(v,LLIL_FCMP_UO.d(LLIL_REG.d(s24),LLIL_REG.d(s22)))'), + # vmls.f32 s24, s0, s16 + ('T', b'\x00\xee\x48\xca', 'LLIL_SET_REG.d(s24,LLIL_FSUB.d(LLIL_REG.d(s24),LLIL_FMUL.d(LLIL_REG.d(s0),LLIL_REG.d(s16))))'), + # vmla.f64 d0, d1, d2 + ('A', b'\x02\x0b\x01\xee', 'LLIL_SET_REG.q(d0,LLIL_FADD.q(LLIL_REG.q(d0),LLIL_FMUL.q(LLIL_REG.q(d1),LLIL_REG.q(d2))))'), + # vfma.f32 s0, s1, s2 + ('A', b'\x81\x0a\xa0\xee', 'LLIL_SET_REG.d(s0,LLIL_FADD.d(LLIL_REG.d(s0),LLIL_FMUL.d(LLIL_REG.d(s1),LLIL_REG.d(s2))))'), + # vfms.f32 s0, s1, s2 + ('A', b'\xc1\x0a\xa0\xee', 'LLIL_SET_REG.d(s0,LLIL_FSUB.d(LLIL_REG.d(s0),LLIL_FMUL.d(LLIL_REG.d(s1),LLIL_REG.d(s2))))'), + # vmla.i32 d16, d28, d15[1] + ('T', b'\xec\xef\xef\x00', 'LLIL_INTRINSIC([d16],__vmla,[LLIL_CONST.b(0x20),LLIL_REG.q(d16),LLIL_REG.q(d28),LLIL_REG.q(d15),LLIL_CONST.b(0x1)])'), + # vmlsl.u32 q8, d9, d1[0] + ('T', b'\xe9\xff\x41\x06', 'LLIL_INTRINSIC([q8],__vmlsl,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x1),LLIL_REG.o(q8),LLIL_REG.q(d9),LLIL_REG.q(d1),LLIL_CONST.b(0x0)])'), + # vmul.p8 q12, q9, q10 + ('T', b'\x42\xff\xf4\x89', 'LLIL_INTRINSIC([q12],__vmul,[LLIL_CONST.b(0x8),LLIL_CONST.b(0x0),LLIL_REG.o(q9),LLIL_REG.o(q10)])'), + # vqdmull.s32 q8, d0, d1 + ('A', b'\x01\x0d\xe0\xf2', 'LLIL_INTRINSIC([q8],__vqdmull,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x0),LLIL_REG.q(d0),LLIL_REG.q(d1)])'), + # vqdmull.s32 q8, d0, d1 + ('T', b'\xe0\xef\x01\x0d', 'LLIL_INTRINSIC([q8],__vqdmull,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x0),LLIL_REG.q(d0),LLIL_REG.q(d1)])'), + # vmlal.s8 q8, d0, d1 + ('A', b'\x01\x08\xc0\xf2', vmlal_expected(8, 0)), + # vmlal.u8 q8, d0, d1 + ('A', b'\x01\x08\xc0\xf3', vmlal_expected(8, 1)), + # vmlal.s16 q8, d0, d1 + ('A', b'\x01\x08\xd0\xf2', vmlal_expected(16, 0)), + # vmlal.u16 q8, d0, d1 + ('A', b'\x01\x08\xd0\xf3', vmlal_expected(16, 1)), + # vmlal.s32 q8, d0, d1 + ('A', b'\x01\x08\xe0\xf2', vmlal_expected(32, 0)), + # vmlal.u32 q8, d0, d1 + ('A', b'\x01\x08\xe0\xf3', vmlal_expected(32, 1)), + # vmlal.s8 q8, d0, d1 + ('T', b'\xc0\xef\x01\x08', vmlal_expected(8, 0)), + # vmlal.u8 q8, d0, d1 + ('T', b'\xc0\xff\x01\x08', vmlal_expected(8, 1)), + # vmlal.s16 q8, d0, d1 + ('T', b'\xd0\xef\x01\x08', vmlal_expected(16, 0)), + # vmlal.u16 q8, d0, d1 + ('T', b'\xd0\xff\x01\x08', vmlal_expected(16, 1)), + # vmlal.s32 q8, d0, d1 + ('T', b'\xe0\xef\x01\x08', vmlal_expected(32, 0)), + # vmlal.u32 q8, d0, d1 + ('T', b'\xe0\xff\x01\x08', vmlal_expected(32, 1)), + # vabal.u16 q8, d10, d24 + ('T', b'\xda\xff\x28\x05', 'LLIL_INTRINSIC([q8],__vabal,[LLIL_CONST.b(0x10),LLIL_CONST.b(0x1),LLIL_REG.o(q8),LLIL_REG.q(d10),LLIL_REG.q(d24)])'), + # vaba.u8 q11, q9, q11 + ('T', b'\x42\xff\xf6\x67', 'LLIL_INTRINSIC([q11],__vaba,[LLIL_CONST.b(0x8),LLIL_CONST.b(0x1),LLIL_REG.o(q11),LLIL_REG.o(q9),LLIL_REG.o(q11)])'), + # vabdl.u16 q8, d15, d24 + ('T', b'\xdf\xff\x28\x07', 'LLIL_INTRINSIC([q8],__vabdl,[LLIL_CONST.b(0x10),LLIL_CONST.b(0x1),LLIL_REG.q(d15),LLIL_REG.q(d24)])'), + # vaddw.u16 q8, q6, d19 + ('T', b'\xdc\xff\x23\x01', 'LLIL_INTRINSIC([q8],__vaddw,[LLIL_CONST.b(0x10),LLIL_CONST.b(0x1),LLIL_REG.o(q6),LLIL_REG.q(d19)])'), + # vaddl.u16 q8, d14, d24 + ('T', b'\xde\xff\x28\x00', 'LLIL_INTRINSIC([q8],__vaddl,[LLIL_CONST.b(0x10),LLIL_CONST.b(0x1),LLIL_REG.q(d14),LLIL_REG.q(d24)])'), + # vraddhn.i64 d16, q0, q9 + ('T', b'\xe0\xff\x22\x04', 'LLIL_INTRINSIC([d16],__vraddhn,[LLIL_CONST.b(0x40),LLIL_REG.o(q0),LLIL_REG.o(q9)])'), + # vsub.i32 d0, d1, d8 + ('T', b'\x21\xff\x08\x08', 'LLIL_SET_REG.q(d0,LLIL_SUB.q(LLIL_REG.q(d1),LLIL_REG.q(d8)))'), + # vsub.i16 d0, d1, d8 + ('T', b'\x11\xff\x08\x08', 'LLIL_SET_REG.q(d0,LLIL_SUB.q(LLIL_REG.q(d1),LLIL_REG.q(d8)))'), + # vsub.i8 d0, d13, d8 + ('T', b'\x0d\xff\x08\x08', 'LLIL_SET_REG.q(d0,LLIL_SUB.q(LLIL_REG.q(d13),LLIL_REG.q(d8)))'), + # vhadd.u8 d0, d0, d0 + ('T', b'\x00\xff\x00\x00', vector_intrinsic_expected('d0', 'vhadd', 8, 1, 'd0', 'd0')), + # vceq.s16 d16, d0, d13 + ('T', b'\x50\xff\x1d\x08', vector_intrinsic_expected('d16', 'vceq', 16, 0, 'd0', 'd13')), + # vcgt.s32 d0, d19, #0 + ('T', b'\xb9\xff\x23\x00', 'LLIL_INTRINSIC([d0],__vcgt,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x0),LLIL_REG.q(d19),LLIL_CONST.q(0x0)])'), + # vcgt.u32 d10, d1, d18 + ('T', b'\x21\xff\x22\xa3', 'LLIL_INTRINSIC([d10],__vcgt,[LLIL_CONST.b(0x20),LLIL_CONST.b(0x1),LLIL_REG.q(d1),LLIL_REG.q(d18)])'), + # vtbl.8 d0, {d5}, d4 + ('T', b'\xb5\xff\x04\x08', 'LLIL_INTRINSIC([d0],__vtbl,[LLIL_CONST.b(0x1),LLIL_REG.q(d5),LLIL_CONST.q(0x0),LLIL_CONST.q(0x0),LLIL_CONST.q(0x0),LLIL_REG.q(d4)])'), + # vshl.u16 d0, d0, d1 + ('T', b'\x11\xff\x00\x04', 'LLIL_INTRINSIC([d0],__vshl,[LLIL_CONST.b(0x10),LLIL_CONST.b(0x1),LLIL_REG.q(d0),LLIL_REG.q(d1)])'), + # vnmul.f32 s15, s15, s0 + ('T', b'\x67\xee\xc0\x7a', 'LLIL_SET_REG.d(s15,LLIL_FNEG.d(LLIL_FMUL.d(LLIL_REG.d(s15),LLIL_REG.d(s0))))'), + # vnmls.f32 s0, s1, s2 + ('A', b'\x81\x0a\x10\xee', 'LLIL_SET_REG.d(s0,LLIL_FNEG.d(LLIL_FSUB.d(LLIL_REG.d(s0),LLIL_FMUL.d(LLIL_REG.d(s1),LLIL_REG.d(s2)))))'), + # vnmla.f32 s0, s1, s2 + ('A', b'\xc1\x0a\x10\xee', 'LLIL_SET_REG.d(s0,LLIL_FNEG.d(LLIL_FADD.d(LLIL_REG.d(s0),LLIL_FMUL.d(LLIL_REG.d(s1),LLIL_REG.d(s2)))))'), + # vnmls.f32 s0, s1, s2 + ('T', b'\x10\xee\x81\x0a', 'LLIL_SET_REG.d(s0,LLIL_FNEG.d(LLIL_FSUB.d(LLIL_REG.d(s0),LLIL_FMUL.d(LLIL_REG.d(s1),LLIL_REG.d(s2)))))'), + # vnmla.f32 s0, s1, s2 + ('T', b'\x10\xee\xc1\x0a', 'LLIL_SET_REG.d(s0,LLIL_FNEG.d(LLIL_FADD.d(LLIL_REG.d(s0),LLIL_FMUL.d(LLIL_REG.d(s1),LLIL_REG.d(s2)))))'), + # vsqrt.f32 s15, s0 + ('T', b'\xf1\xee\xc0\x7a', 'LLIL_SET_REG.d(s15,LLIL_FSQRT.d(LLIL_REG.d(s0)))'), + # vselgt.f32 s14, s15, s14 + ('T', b'\x37\xfe\x87\x7a', 'LLIL_IF(LLIL_FLAG_COND(LowLevelILFlagCondition.LLFC_SGT,None),1,3); LLIL_SET_REG.d(s14,LLIL_REG.d(s15)); LLIL_GOTO(5); LLIL_SET_REG.d(s14,LLIL_REG.d(s14)); LLIL_GOTO(5)'), + # vseleq.f32 s15, s13, s14 + ('T', b'\x46\xfe\x87\x7a', 'LLIL_IF(LLIL_FLAG_COND(LowLevelILFlagCondition.LLFC_E,None),1,3); LLIL_SET_REG.d(s15,LLIL_REG.d(s13)); LLIL_GOTO(5); LLIL_SET_REG.d(s15,LLIL_REG.d(s14)); LLIL_GOTO(5)'), + # vselge.f64 d6, d6, d7 + ('T', b'\x26\xfe\x07\x6b', 'LLIL_IF(LLIL_FLAG_COND(LowLevelILFlagCondition.LLFC_SGE,None),1,3); LLIL_SET_REG.q(d6,LLIL_REG.q(d6)); LLIL_GOTO(5); LLIL_SET_REG.q(d6,LLIL_REG.q(d7)); LLIL_GOTO(5)'), + # vfnma.f64 d2, d14, d11 + ('T', b'\x9e\xee\x4b\x2b', 'LLIL_SET_REG.q(d2,LLIL_FNEG.q(LLIL_FADD.q(LLIL_REG.q(d2),LLIL_FMUL.q(LLIL_REG.q(d14),LLIL_REG.q(d11)))))'), + # vfnms.f32 s8, s14, s11 + ('T', b'\x97\xee\x25\x4a', 'LLIL_SET_REG.d(s8,LLIL_FNEG.d(LLIL_FSUB.d(LLIL_REG.d(s8),LLIL_FMUL.d(LLIL_REG.d(s14),LLIL_REG.d(s11)))))'), + # vrinta.f32 s0, s0 + ('T', b'\xb8\xfe\x40\x0a', 'LLIL_INTRINSIC([s0],__vrinta,[LLIL_REG.d(s0)])'), + # vrintm.f32 s17, s14 + ('T', b'\xfb\xfe\x47\x8a', 'LLIL_SET_REG.d(s17,LLIL_FLOOR.d(LLIL_REG.d(s14)))'), + # vcvt.f32.s32 s14, s14, #1 + ('T', b'\xba\xee\xef\x7a', 'LLIL_SET_REG.d(s14,LLIL_FDIV.d(LLIL_INT_TO_FLOAT.d(LLIL_SX.d(LLIL_REG.d(s14))),LLIL_FLOAT_CONST.d(2.0)))'), + # vcvt.f64.u32 d7, d7, #1 + ('T', b'\xbb\xee\xef\x7b', 'LLIL_SET_REG.q(d7,LLIL_FDIV.q(LLIL_INT_TO_FLOAT.q(LLIL_ZX.q(LLIL_LOW_PART.d(LLIL_REG.q(d7)))),LLIL_FLOAT_CONST.q(2.0)))'), + # vmaxnm.f64 d11, d11, d7 + ('T', b'\x8b\xfe\x07\xbb', 'LLIL_INTRINSIC([d11],__vmaxnm,[LLIL_REG.q(d11),LLIL_REG.q(d7)])'), + # vminnm.f64 d8, d8, d9 + ('T', b'\x88\xfe\x49\x8b', 'LLIL_INTRINSIC([d8],__vminnm,[LLIL_REG.q(d8),LLIL_REG.q(d9)])'), # umlal r0, r1, r2, r3 ('T', b'\xe2\xfb\x03\x01', 'LLIL_SET_REG_SPLIT.d(r1,r0,LLIL_ADD.q(LLIL_MULU_DP.d(LLIL_REG.d(r3),LLIL_REG.d(r2)),LLIL_REG_SPLIT.d(r1,r0)))'), + # smlad r0, r1, r2, r3 + ('T', b'\x21\xfb\x02\x30', 'LLIL_SET_REG.d(r0,LLIL_ADD.d(LLIL_REG.d(r3),LLIL_ADD.d(LLIL_MUL.d(LLIL_SX.d(LLIL_LOW_PART.w(LLIL_REG.d(r1))),LLIL_SX.d(LLIL_LOW_PART.w(LLIL_REG.d(r2)))),LLIL_MUL.d(LLIL_ASR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_ASR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x10))))))'), + # smuad r0, r1, r2 + ('T', b'\x21\xfb\x02\xf0', 'LLIL_SET_REG.d(temp0,LLIL_MUL.d(LLIL_ASR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_ASR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(temp1,LLIL_MUL.d(LLIL_LOW_PART.w(LLIL_REG.d(r1)),LLIL_LOW_PART.w(LLIL_REG.d(r2)))); LLIL_SET_REG.d(r0,LLIL_ADD.d(LLIL_REG.d(temp1),LLIL_REG.d(temp0)))'), + # smuadx r0, r1, r2 + ('T', b'\x21\xfb\x12\xf0', 'LLIL_SET_REG.d(temp0,LLIL_MUL.d(LLIL_ASR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_LOW_PART.w(LLIL_REG.d(r2)))); LLIL_SET_REG.d(temp1,LLIL_MUL.d(LLIL_LOW_PART.w(LLIL_REG.d(r1)),LLIL_ASR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(r0,LLIL_ADD.d(LLIL_REG.d(temp1),LLIL_REG.d(temp0)))'), + # smusd r0, r1, r2 + ('T', b'\x41\xfb\x02\xf0', 'LLIL_SET_REG.d(temp0,LLIL_MUL.d(LLIL_ASR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_ASR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(temp1,LLIL_MUL.d(LLIL_LOW_PART.w(LLIL_REG.d(r1)),LLIL_LOW_PART.w(LLIL_REG.d(r2)))); LLIL_SET_REG.d(r0,LLIL_SUB.d(LLIL_REG.d(temp1),LLIL_REG.d(temp0)))'), + # smusdx r0, r1, r2 + ('T', b'\x41\xfb\x12\xf0', 'LLIL_SET_REG.d(temp0,LLIL_MUL.d(LLIL_ASR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_LOW_PART.w(LLIL_REG.d(r2)))); LLIL_SET_REG.d(temp1,LLIL_MUL.d(LLIL_LOW_PART.w(LLIL_REG.d(r1)),LLIL_ASR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(r0,LLIL_SUB.d(LLIL_REG.d(temp1),LLIL_REG.d(temp0)))'), + # smlsd r0, r1, r2, r3 + ('T', b'\x41\xfb\x02\x30', 'LLIL_SET_REG.d(temp0,LLIL_MUL.d(LLIL_ASR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_ASR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(temp1,LLIL_MUL.d(LLIL_LOW_PART.w(LLIL_REG.d(r1)),LLIL_LOW_PART.w(LLIL_REG.d(r2)))); LLIL_SET_REG.d(r0,LLIL_ADD.d(LLIL_SUB.d(LLIL_REG.d(temp1),LLIL_REG.d(temp0)),LLIL_REG.d(r3)))'), + # smlsdx r0, r1, r2, r3 + ('T', b'\x41\xfb\x12\x30', 'LLIL_SET_REG.d(temp0,LLIL_MUL.d(LLIL_ASR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x10)),LLIL_LOW_PART.w(LLIL_REG.d(r2)))); LLIL_SET_REG.d(temp1,LLIL_MUL.d(LLIL_LOW_PART.w(LLIL_REG.d(r1)),LLIL_ASR.d(LLIL_REG.d(r2),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(r0,LLIL_ADD.d(LLIL_SUB.d(LLIL_REG.d(temp1),LLIL_REG.d(temp0)),LLIL_REG.d(r3)))'), + # smlsld r0, r1, r2, r3 + ('T', b'\xd2\xfb\xc3\x01', 'LLIL_SET_REG.d(temp0,LLIL_MUL.d(LLIL_LOW_PART.w(LLIL_REG.d(r2)),LLIL_LOW_PART.w(LLIL_REG.d(r3)))); LLIL_SET_REG.d(temp1,LLIL_MUL.d(LLIL_ASR.w(LLIL_REG.d(r2),LLIL_CONST.b(0x10)),LLIL_ASR.w(LLIL_REG.d(r3),LLIL_CONST.b(0x10)))); LLIL_SET_REG.q(temp2,LLIL_ADD.q(LLIL_OR.q(LLIL_LSL.q(LLIL_REG.d(r1),LLIL_CONST.b(0x20)),LLIL_REG.d(r0)),LLIL_SUB.d(LLIL_REG.d(temp0),LLIL_REG.d(temp1)))); LLIL_SET_REG.d(r0,LLIL_LOW_PART.d(LLIL_REG.q(temp2))); LLIL_SET_REG.d(r1,LLIL_ASR.d(LLIL_REG.q(temp2),LLIL_CONST.b(0x20)))'), + # smlsldx r0, r1, r2, r3 + ('T', b'\xd2\xfb\xd3\x01', 'LLIL_SET_REG.d(temp0,LLIL_MUL.d(LLIL_LOW_PART.w(LLIL_REG.d(r2)),LLIL_ASR.w(LLIL_REG.d(r3),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(temp1,LLIL_MUL.d(LLIL_ASR.w(LLIL_REG.d(r2),LLIL_CONST.b(0x10)),LLIL_LOW_PART.w(LLIL_REG.d(r3)))); LLIL_SET_REG.q(temp2,LLIL_ADD.q(LLIL_OR.q(LLIL_LSL.q(LLIL_REG.d(r1),LLIL_CONST.b(0x20)),LLIL_REG.d(r0)),LLIL_SUB.d(LLIL_REG.d(temp0),LLIL_REG.d(temp1)))); LLIL_SET_REG.d(r0,LLIL_LOW_PART.d(LLIL_REG.q(temp2))); LLIL_SET_REG.d(r1,LLIL_ASR.d(LLIL_REG.q(temp2),LLIL_CONST.b(0x20)))'), + # smlalbb r0, r1, r2, r3 + ('T', b'\xc2\xfb\x83\x01', 'LLIL_SET_REG_SPLIT.d(r1,r0,LLIL_ADD.q(LLIL_SX.q(LLIL_MUL.d(LLIL_LOW_PART.w(LLIL_REG.d(r2)),LLIL_LOW_PART.w(LLIL_REG.d(r3)))),LLIL_REG_SPLIT.d(r1,r0)))'), + # smlalbt r0, r1, r2, r3 + ('T', b'\xc2\xfb\x93\x01', 'LLIL_SET_REG_SPLIT.d(r1,r0,LLIL_ADD.q(LLIL_SX.q(LLIL_MUL.d(LLIL_LOW_PART.w(LLIL_REG.d(r2)),LLIL_ASR.w(LLIL_REG.d(r3),LLIL_CONST.b(0x10)))),LLIL_REG_SPLIT.d(r1,r0)))'), + # smlaltb r0, r1, r2, r3 + ('T', b'\xc2\xfb\xa3\x01', 'LLIL_SET_REG_SPLIT.d(r1,r0,LLIL_ADD.q(LLIL_SX.q(LLIL_MUL.d(LLIL_ASR.w(LLIL_REG.d(r2),LLIL_CONST.b(0x10)),LLIL_LOW_PART.w(LLIL_REG.d(r3)))),LLIL_REG_SPLIT.d(r1,r0)))'), + # smlaltt r0, r1, r2, r3 + ('T', b'\xc2\xfb\xb3\x01', 'LLIL_SET_REG_SPLIT.d(r1,r0,LLIL_ADD.q(LLIL_SX.q(LLIL_MUL.d(LLIL_ASR.w(LLIL_REG.d(r2),LLIL_CONST.b(0x10)),LLIL_ASR.w(LLIL_REG.d(r3),LLIL_CONST.b(0x10)))),LLIL_REG_SPLIT.d(r1,r0)))'), + # smlawb r0, r1, r2, r3 + ('T', b'\x31\xfb\x02\x30', 'LLIL_SET_REG.q(temp0,LLIL_ADD.q(LLIL_MUL.q(LLIL_REG.d(r1),LLIL_LOW_PART.w(LLIL_REG.d(r2))),LLIL_LSL.q(LLIL_REG.d(r3),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(r0,LLIL_AND.d(LLIL_ASR.q(LLIL_REG.q(temp0),LLIL_CONST.b(0x10)),LLIL_CONST.d(0xFFFFFFFF)))'), + # smlawt r0, r1, r2, r3 + ('T', b'\x31\xfb\x12\x30', 'LLIL_SET_REG.q(temp0,LLIL_ADD.q(LLIL_MUL.q(LLIL_REG.d(r1),LLIL_ASR.w(LLIL_REG.d(r2),LLIL_CONST.b(0x10))),LLIL_LSL.q(LLIL_REG.d(r3),LLIL_CONST.b(0x10)))); LLIL_SET_REG.d(r0,LLIL_AND.d(LLIL_ASR.q(LLIL_REG.q(temp0),LLIL_CONST.b(0x10)),LLIL_CONST.d(0xFFFFFFFF)))'), + # smulwb r0, r1, r2 + ('T', b'\x31\xfb\x02\xf0', 'LLIL_SET_REG.d(r0,LLIL_MUL.d(LLIL_REG.d(r1),LLIL_LOW_PART.w(LLIL_REG.d(r2))))'), + # smulwt r0, r1, r2 + ('T', b'\x31\xfb\x12\xf0', 'LLIL_SET_REG.d(r0,LLIL_MUL.d(LLIL_REG.d(r1),LLIL_ASR.w(LLIL_REG.d(r2),LLIL_CONST.b(0x10))))'), + # smlal r4, r5, r2, r3 + ('T', b'\xc2\xfb\x03\x45', 'LLIL_SET_REG_SPLIT.d(r5,r4,LLIL_ADD.q(LLIL_MULS_DP.d(LLIL_REG.d(r2),LLIL_REG.d(r3)),LLIL_REG_SPLIT.d(r5,r4)))'), + # smlald r11, r5, pc, r0 + ('T', b'\xcf\xfb\xc0\xb5', 'LLIL_SET_REG_SPLIT.d(r5,r11,LLIL_ADD.q(LLIL_REG_SPLIT.d(r5,r11),LLIL_SX.q(LLIL_ADD.d(LLIL_MUL.d(LLIL_SX.d(LLIL_LOW_PART.w(LLIL_CONST.d(0x4))),LLIL_SX.d(LLIL_LOW_PART.w(LLIL_REG.d(r0)))),LLIL_MUL.d(LLIL_ASR.d(LLIL_CONST.d(0x4),LLIL_CONST.b(0x10)),LLIL_ASR.d(LLIL_REG.d(r0),LLIL_CONST.b(0x10)))))))'), + # usad8 r0, r1, r2 + ('T', b'\x71\xfb\x02\xf0', scalar_intrinsic_expected('r0', 'usad8', 'r1', 'r2')), + # usada8 r0, r1, r2, r3 + ('T', b'\x71\xfb\x02\x30', scalar_intrinsic_expected('r0', 'usada8', 'r1', 'r2', 'r3')), + # smmul r0, r0, r1 + ('T', b'\x50\xfb\x01\xf0', 'LLIL_SET_REG.d(r0,LLIL_LOW_PART.d(LLIL_ASR.q(LLIL_MULS_DP.d(LLIL_REG.d(r0),LLIL_REG.d(r1)),LLIL_CONST.b(0x20))))'), + # smmlar r8, sp, r6, r0 + ('T', b'\x5d\xfb\x16\x08', 'LLIL_SET_REG.d(r8,LLIL_ADD.d(LLIL_LOW_PART.d(LLIL_ASR.q(LLIL_ADD.q(LLIL_MULS_DP.d(LLIL_REG.d(sp),LLIL_REG.d(r6)),LLIL_CONST.q(0x80000000)),LLIL_CONST.b(0x20))),LLIL_REG.d(r0)))'), + # smmlsr r8, r5, r6, r0 + ('T', b'\x65\xfb\x16\x08', 'LLIL_SET_REG.d(r8,LLIL_LOW_PART.d(LLIL_ASR.q(LLIL_ADD.q(LLIL_SUB.q(LLIL_LSL.q(LLIL_REG.d(r0),LLIL_CONST.b(0x20)),LLIL_MULS_DP.d(LLIL_REG.d(r5),LLIL_REG.d(r6))),LLIL_CONST.q(0x80000000)),LLIL_CONST.b(0x20))))'), + # smlabb r6, r0, r1, r11 + ('T', b'\x10\xfb\x01\xb6', 'LLIL_SET_REG.d(r6,LLIL_ADD.d(LLIL_MUL.d(LLIL_SX.d(LLIL_LOW_PART.w(LLIL_REG.d(r0))),LLIL_SX.d(LLIL_LOW_PART.w(LLIL_REG.d(r1)))),LLIL_REG.d(r11)))'), + # sel r5, r3, r7 + ('T', b'\xa3\xfa\x87\xf5', 'LLIL_INTRINSIC([r5],__sel,[LLIL_REG.d(r3),LLIL_REG.d(r7)])'), # sbfx r0, r1, 0, 1 (starting at b0, width 1, so extract b0) ('T', b'\x41\xf3\x00\x00', 'LLIL_SET_REG.d(r0,LLIL_ASR.d(LLIL_LSL.d(LLIL_REG.d(r1),LLIL_CONST.b(0x1F)),LLIL_CONST.b(0x1F)))'), # sbfx r0, r1, 1, 2 (starting at b1, width 2, so extract b2b1) @@ -128,6 +726,10 @@ ('T', b'\x41\xf3\x1d\x50', 'LLIL_SET_REG.d(r0,LLIL_ASR.d(LLIL_REG.d(r1),LLIL_CONST.b(0x14)))'), # rev r1, r1 ('T', b'\x09\xba', 'LLIL_SET_REG.d(r1,LLIL_OR.d(LLIL_LSR.d(LLIL_REG.d(r1),LLIL_CONST.d(0x18)),LLIL_OR.d(LLIL_LSL.d(LLIL_AND.d(LLIL_LSR.d(LLIL_REG.d(r1),LLIL_CONST.d(0x10)),LLIL_CONST.d(0xFF)),LLIL_CONST.b(0x8)),LLIL_OR.d(LLIL_LSL.d(LLIL_AND.d(LLIL_LSR.d(LLIL_REG.d(r1),LLIL_CONST.d(0x8)),LLIL_CONST.d(0xFF)),LLIL_CONST.b(0x10)),LLIL_LSL.d(LLIL_AND.d(LLIL_REG.d(r1),LLIL_CONST.d(0xFF)),LLIL_CONST.b(0x18))))))'), + # revsh r3, r3 + ('T', b'\xdb\xba', 'LLIL_SET_REG.d(r3,LLIL_SX.d(LLIL_OR.w(LLIL_LSL.w(LLIL_AND.w(LLIL_LOW_PART.w(LLIL_REG.d(r3)),LLIL_CONST.w(0xFF)),LLIL_CONST.b(0x8)),LLIL_AND.w(LLIL_LSR.w(LLIL_LOW_PART.w(LLIL_REG.d(r3)),LLIL_CONST.b(0x8)),LLIL_CONST.w(0xFF)))))'), + # revsh.w r8, r8 + ('T', b'\x98\xfa\xb8\xf8', 'LLIL_SET_REG.d(r8,LLIL_SX.d(LLIL_OR.w(LLIL_LSL.w(LLIL_AND.w(LLIL_LOW_PART.w(LLIL_REG.d(r8)),LLIL_CONST.w(0xFF)),LLIL_CONST.b(0x8)),LLIL_AND.w(LLIL_LSR.w(LLIL_LOW_PART.w(LLIL_REG.d(r8)),LLIL_CONST.b(0x8)),LLIL_CONST.w(0xFF)))))'), ] import re @@ -212,10 +814,25 @@ def il_str_to_tree(ilstr): def test_all(): for (test_i, (arch_name, data, expected)) in enumerate(test_cases): platform = {'A':'linux-armv7', 'T':'linux-thumb2'}[arch_name] + + if '?' in expected: + print('INVALID EXPECTED LLIL AT TEST %d!' % test_i) + print('\t input: %s' % data.hex()) + print('\texpected: %s' % expected) + return False + actual = instr_to_il(data, platform) #print(f'{test_i:04d} {data.hex()} {actual}') + if '?' in actual: + print('INVALID ACTUAL LLIL AT TEST %d!' % test_i) + print('\t input: %s' % data.hex()) + print('\t actual: %s' % actual) + print('\t tree:') + print(il_str_to_tree(actual)) + return False + if actual != expected: print('MISMATCH AT TEST %d!' % test_i) print('\t input: %s' % data.hex()) diff --git a/arch/armv7/thumb2_disasm/arch_thumb2.cpp b/arch/armv7/thumb2_disasm/arch_thumb2.cpp index 73e6e1cdcc..600596f1c8 100644 --- a/arch/armv7/thumb2_disasm/arch_thumb2.cpp +++ b/arch/armv7/thumb2_disasm/arch_thumb2.cpp @@ -86,6 +86,21 @@ static Ref get_msr_op_enum() return _enum; } +static Ref GetVfpStatusRegisterEnum() +{ + EnumerationBuilder builder; + builder.AddMemberWithValue("fpsid", REGS_FPSID); + builder.AddMemberWithValue("fpscr", REGS_FPSCR); + builder.AddMemberWithValue("mvfr2", REGS_MVFR2); + builder.AddMemberWithValue("mvfr1", REGS_MVFR1); + builder.AddMemberWithValue("mvfr0", REGS_MVFR0); + builder.AddMemberWithValue("fpexc", REGS_FPEXC); + builder.AddMemberWithValue("fpinst", REGS_FPINST); + builder.AddMemberWithValue("fpinst2", REGS_FPINST2); + Ref _enum = builder.Finalize(); + return _enum; +} + /* class Architecture from binaryninjaapi.h */ class Thumb2Architecture: public ArmCommonArchitecture { @@ -1600,6 +1615,204 @@ class Thumb2Architecture: public ArmCommonArchitecture return "Coproc_SendOneWord"; case ARMV7_INTRIN_COPROC_SENDTWOWORDS: return "Coproc_SendTwoWords"; + case ARMV7_INTRIN_COPROC_STORE: + return "Coproc_Store"; + case ARMV7_INTRIN_COPROC_LOAD: + return "Coproc_Load"; + case ARMV7_INTRIN_COPROC_DATAPROCESSING: + return "Coproc_DataProcessing"; + case ARMV7_INTRIN_EXCLUSIVE_MONITORS_PASS: + return "ExclusiveMonitorsPass"; + case ARMV7_INTRIN_SET_EXCLUSIVE_MONITORS: + return "SetExclusiveMonitors"; + case ARMV7_INTRIN_SEL: + return "__sel"; + case ARMV7_INTRIN_VRINTA: + return "__vrinta"; + case ARMV7_INTRIN_VMAXNM: + return "__vmaxnm"; + case ARMV7_INTRIN_VMINNM: + return "__vminnm"; + case ARMV7_INTRIN_VMAX: + return "__vmax"; + case ARMV7_INTRIN_VMIN: + return "__vmin"; + case ARMV7_INTRIN_VPMAX: + return "__vpmax"; + case ARMV7_INTRIN_VPMIN: + return "__vpmin"; + case ARMV7_INTRIN_VREV16: + return "__vrev16"; + case ARMV7_INTRIN_VREV32: + return "__vrev32"; + case ARMV7_INTRIN_VREV64: + return "__vrev64"; + case ARMV7_INTRIN_VEXT: + return "__vext"; + case ARMV7_INTRIN_VCGT: + return "__vcgt"; + case ARMV7_INTRIN_VCEQ: + return "__vceq"; + case ARMV7_INTRIN_VTBL: + return "__vtbl"; + case ARMV7_INTRIN_VTBX: + return "__vtbx"; + case ARMV7_INTRIN_VDUP: + return "__vdup"; + case ARMV7_INTRIN_VABD: + return "__vabd"; + case ARMV7_INTRIN_VABDL: + return "__vabdl"; + case ARMV7_INTRIN_VABA: + return "__vaba"; + case ARMV7_INTRIN_VABAL: + return "__vabal"; + case ARMV7_INTRIN_VADDL: + return "__vaddl"; + case ARMV7_INTRIN_VADDW: + return "__vaddw"; + case ARMV7_INTRIN_VRADDHN: + return "__vraddhn"; + case ARMV7_INTRIN_VRSHR: + return "__vrshr"; + case ARMV7_INTRIN_VRSHL: + return "__vrshl"; + case ARMV7_INTRIN_VSRA: + return "__vsra"; + case ARMV7_INTRIN_VRSRA: + return "__vrsra"; + case ARMV7_INTRIN_VSRI: + return "__vsri"; + case ARMV7_INTRIN_VSLI: + return "__vsli"; + case ARMV7_INTRIN_VLD2: + return "__vld2"; + case ARMV7_INTRIN_VLD4: + return "__vld4"; + case ARMV7_INTRIN_VST2: + return "__vst2"; + case ARMV7_INTRIN_VST4: + return "__vst4"; + case ARMV7_INTRIN_VSHL: + return "__vshl"; + case ARMV7_INTRIN_VSHR: + return "__vshr"; + case ARMV7_INTRIN_VSHLL: + return "__vshll"; + case ARMV7_INTRIN_VBIF: + return "__vbif"; + case ARMV7_INTRIN_VBIT: + return "__vbit"; + case ARMV7_INTRIN_VBSL: + return "__vbsl"; + case ARMV7_INTRIN_VQADD: + return "__vqadd"; + case ARMV7_INTRIN_VHADD: + return "__vhadd"; + case ARMV7_INTRIN_VQSHL: + return "__vqshl"; + case ARMV7_INTRIN_VQRSHL: + return "__vqrshl"; + case ARMV7_INTRIN_VQSHRN: + return "__vqshrn"; + case ARMV7_INTRIN_VQSHRUN: + return "__vqshrun"; + case ARMV7_INTRIN_VQRSHRN: + return "__vqrshrn"; + case ARMV7_INTRIN_VQRSHRUN: + return "__vqrshrun"; + case ARMV7_INTRIN_VQMOVN: + return "__vqmovn"; + case ARMV7_INTRIN_VQMOVUN: + return "__vqmovun"; + case ARMV7_INTRIN_VMLA: + return "__vmla"; + case ARMV7_INTRIN_VMLS: + return "__vmls"; + case ARMV7_INTRIN_VMLAL: + return "__vmlal"; + case ARMV7_INTRIN_VMLSL: + return "__vmlsl"; + case ARMV7_INTRIN_VMUL: + return "__vmul"; + case ARMV7_INTRIN_VQDMULL: + return "__vqdmull"; + case ARMV7_INTRIN_SSAT: + return "__ssat"; + case ARMV7_INTRIN_SSAT16: + return "__ssat16"; + case ARMV7_INTRIN_USAT: + return "__usat"; + case ARMV7_INTRIN_USAT16: + return "__usat16"; + case ARMV7_INTRIN_SRS: + return "__srs"; + case ARMV7_INTRIN_RFE: + return "__rfe"; + case ARMV7_INTRIN_QADD: + return "__qadd"; + case ARMV7_INTRIN_QSUB: + return "__qsub"; + case ARMV7_INTRIN_QDADD: + return "__qdadd"; + case ARMV7_INTRIN_QDSUB: + return "__qdsub"; + case ARMV7_INTRIN_QADD16: + return "__qadd16"; + case ARMV7_INTRIN_QADD8: + return "__qadd8"; + case ARMV7_INTRIN_QSUB16: + return "__qsub16"; + case ARMV7_INTRIN_QSUB8: + return "__qsub8"; + case ARMV7_INTRIN_UQADD16: + return "__uqadd16"; + case ARMV7_INTRIN_UQADD8: + return "__uqadd8"; + case ARMV7_INTRIN_UQSUB16: + return "__uqsub16"; + case ARMV7_INTRIN_UQSUB8: + return "__uqsub8"; + case ARMV7_INTRIN_SXTAB16: + return "__sxtab16"; + case ARMV7_INTRIN_SXTB16: + return "__sxtb16"; + case ARMV7_INTRIN_UXTAB16: + return "__uxtab16"; + case ARMV7_INTRIN_UXTB16: + return "__uxtb16"; + case ARMV7_INTRIN_SADD16: + return "__sadd16"; + case ARMV7_INTRIN_SADD8: + return "__sadd8"; + case ARMV7_INTRIN_SHADD16: + return "__shadd16"; + case ARMV7_INTRIN_SHADD8: + return "__shadd8"; + case ARMV7_INTRIN_SSUB8: + return "__ssub8"; + case ARMV7_INTRIN_SHSUB8: + return "__shsub8"; + case ARMV7_INTRIN_SHSUB16: + return "__shsub16"; + case ARMV7_INTRIN_UHSUB8: + return "__uhsub8"; + case ARMV7_INTRIN_UHSUB16: + return "__uhsub16"; + case ARMV7_INTRIN_USUB8: + return "__usub8"; + case ARMV7_INTRIN_USUB16: + return "__usub16"; + case ARMV7_INTRIN_USAD8: + return "__usad8"; + case ARMV7_INTRIN_USADA8: + return "__usada8"; + case ARMV7_INTRIN_QSAX: + return "__qsax"; + case ARMV7_INTRIN_UQASX: + return "__uqasx"; + case ARMV7_INTRIN_UQSAX: + return "__uqsax"; case ARMV7_INTRIN_DBG: return "__dbg"; case ARMV7_INTRIN_DMB_SY: @@ -1640,18 +1853,56 @@ class Thumb2Architecture: public ArmCommonArchitecture return "__mrs"; case ARMV7_INTRIN_MSR: return "__msr"; + case ARMV7_INTRIN_VMRS: + return "__vmrs"; + case ARMV7_INTRIN_VMSR: + return "__vmsr"; + case ARMV7_INTRIN_YIELD: + return "__yield"; case ARMV7_INTRIN_SEV: return "__sev"; case ARMV7_INTRIN_WFE: return "__wfe"; case ARMV7_INTRIN_WFI: return "__wfi"; + case ARMV7_INTRIN_HINT: + return "__hint"; + case ARMV7_INTRIN_UNPREDICTABLE: + return "__unpredictable"; + case ARMV7_INTRIN_HVC: + return "__hvc"; + case ARMV7_INTRIN_SMC: + return "__smc"; case ARM_M_INTRIN_SET_BASEPRI: return "__set_BASEPRI"; case ARMV7_INTRIN_RBIT: return "__rbit"; case ARMV7_INTRIN_CLZ: return "__clz"; + case ARMV7_INTRIN_CPS: + return "__cps"; + case ARMV7_INTRIN_CPSID: + return "__cpsid"; + case ARMV7_INTRIN_CPSIE: + return "__cpsie"; + case ARMV7_INTRIN_SETEND: + return "__setend"; + case ARMV7_INTRIN_CLREX: + return "__clrex"; + case ARMV7_INTRIN_PLD: + return "__pld"; + case ARMV7_INTRIN_CRC32B: + return "__crc32b"; + case ARMV7_INTRIN_CRC32CB: + return "__crc32cb"; + case ARMV7_INTRIN_CRC32CH: + return "__crc32ch"; + case ARMV7_INTRIN_CRC32CW: + return "__crc32cw"; + case ARMV7_INTRIN_CRC32H: + return "__crc32h"; + case ARMV7_INTRIN_CRC32W: + return "__crc32w"; default: return ""; } @@ -1664,7 +1915,115 @@ class Thumb2Architecture: public ArmCommonArchitecture ARMV7_INTRIN_COPROC_GETTWOWORDS, ARMV7_INTRIN_COPROC_SENDONEWORD, ARMV7_INTRIN_COPROC_SENDTWOWORDS, + ARMV7_INTRIN_COPROC_STORE, + ARMV7_INTRIN_COPROC_LOAD, + ARMV7_INTRIN_COPROC_DATAPROCESSING, + ARMV7_INTRIN_EXCLUSIVE_MONITORS_PASS, + ARMV7_INTRIN_SET_EXCLUSIVE_MONITORS, + ARMV7_INTRIN_SETEND, + ARMV7_INTRIN_SEL, + ARMV7_INTRIN_VRINTA, + ARMV7_INTRIN_VMAXNM, + ARMV7_INTRIN_VMINNM, + ARMV7_INTRIN_VMAX, + ARMV7_INTRIN_VMIN, + ARMV7_INTRIN_VPMAX, + ARMV7_INTRIN_VPMIN, + ARMV7_INTRIN_VREV16, + ARMV7_INTRIN_VREV32, + ARMV7_INTRIN_VREV64, + ARMV7_INTRIN_VEXT, + ARMV7_INTRIN_VCGT, + ARMV7_INTRIN_VCEQ, + ARMV7_INTRIN_VTBL, + ARMV7_INTRIN_VTBX, + ARMV7_INTRIN_VDUP, + ARMV7_INTRIN_VABD, + ARMV7_INTRIN_VABDL, + ARMV7_INTRIN_VABA, + ARMV7_INTRIN_VABAL, + ARMV7_INTRIN_VADDL, + ARMV7_INTRIN_VADDW, + ARMV7_INTRIN_VRADDHN, + ARMV7_INTRIN_VRSHR, + ARMV7_INTRIN_VRSHL, + ARMV7_INTRIN_VSRA, + ARMV7_INTRIN_VRSRA, + ARMV7_INTRIN_VSRI, + ARMV7_INTRIN_VSLI, + ARMV7_INTRIN_VLD2, + ARMV7_INTRIN_VLD4, + ARMV7_INTRIN_VST2, + ARMV7_INTRIN_VST4, + ARMV7_INTRIN_VSHL, + ARMV7_INTRIN_VSHR, + ARMV7_INTRIN_VSHLL, + ARMV7_INTRIN_VBIF, + ARMV7_INTRIN_VBIT, + ARMV7_INTRIN_VBSL, + ARMV7_INTRIN_VQADD, + ARMV7_INTRIN_VHADD, + ARMV7_INTRIN_VQSHL, + ARMV7_INTRIN_VQRSHL, + ARMV7_INTRIN_VQSHRN, + ARMV7_INTRIN_VQSHRUN, + ARMV7_INTRIN_VQRSHRN, + ARMV7_INTRIN_VQRSHRUN, + ARMV7_INTRIN_VQMOVN, + ARMV7_INTRIN_VQMOVUN, + ARMV7_INTRIN_VMLA, + ARMV7_INTRIN_VMLS, + ARMV7_INTRIN_VMLAL, + ARMV7_INTRIN_VMLSL, + ARMV7_INTRIN_VMUL, + ARMV7_INTRIN_VQDMULL, + ARMV7_INTRIN_SSAT, + ARMV7_INTRIN_SSAT16, + ARMV7_INTRIN_USAT, + ARMV7_INTRIN_USAT16, + ARMV7_INTRIN_SRS, + ARMV7_INTRIN_RFE, + ARMV7_INTRIN_QADD, + ARMV7_INTRIN_QSUB, + ARMV7_INTRIN_QDADD, + ARMV7_INTRIN_QDSUB, + ARMV7_INTRIN_QADD16, + ARMV7_INTRIN_QADD8, + ARMV7_INTRIN_QSUB16, + ARMV7_INTRIN_QSUB8, + ARMV7_INTRIN_UQADD16, + ARMV7_INTRIN_UQADD8, + ARMV7_INTRIN_UQSUB16, + ARMV7_INTRIN_UQSUB8, + ARMV7_INTRIN_SXTAB16, + ARMV7_INTRIN_SXTB16, + ARMV7_INTRIN_UXTAB16, + ARMV7_INTRIN_UXTB16, + ARMV7_INTRIN_SADD16, + ARMV7_INTRIN_SADD8, + ARMV7_INTRIN_SHADD16, + ARMV7_INTRIN_SHADD8, + ARMV7_INTRIN_SSUB8, + ARMV7_INTRIN_SHSUB8, + ARMV7_INTRIN_SHSUB16, + ARMV7_INTRIN_UHSUB8, + ARMV7_INTRIN_UHSUB16, + ARMV7_INTRIN_USUB8, + ARMV7_INTRIN_USUB16, + ARMV7_INTRIN_USAD8, + ARMV7_INTRIN_USADA8, + ARMV7_INTRIN_QSAX, + ARMV7_INTRIN_UQASX, + ARMV7_INTRIN_UQSAX, ARMV7_INTRIN_DBG, + ARMV7_INTRIN_CLREX, + ARMV7_INTRIN_PLD, + ARMV7_INTRIN_CRC32B, + ARMV7_INTRIN_CRC32CB, + ARMV7_INTRIN_CRC32CH, + ARMV7_INTRIN_CRC32CW, + ARMV7_INTRIN_CRC32H, + ARMV7_INTRIN_CRC32W, ARMV7_INTRIN_DMB_SY, ARMV7_INTRIN_DMB_ST, ARMV7_INTRIN_DMB_ISH, @@ -1684,9 +2043,16 @@ class Thumb2Architecture: public ArmCommonArchitecture ARMV7_INTRIN_ISB, ARMV7_INTRIN_MRS, ARMV7_INTRIN_MSR, + ARMV7_INTRIN_VMRS, + ARMV7_INTRIN_VMSR, + ARMV7_INTRIN_YIELD, ARMV7_INTRIN_SEV, ARMV7_INTRIN_WFE, ARMV7_INTRIN_WFI, + ARMV7_INTRIN_HINT, + ARMV7_INTRIN_UNPREDICTABLE, + ARMV7_INTRIN_HVC, + ARMV7_INTRIN_SMC, }; } @@ -1725,6 +2091,347 @@ class Thumb2Architecture: public ArmCommonArchitecture NameAndType(Type::IntegerType(1, false)), NameAndType("m", Type::IntegerType(1, false)), }; + case ARMV7_INTRIN_COPROC_STORE: + case ARMV7_INTRIN_COPROC_LOAD: + return { + NameAndType("address", Type::PointerType(4, Confidence(Type::VoidType(), 0), Confidence(false), Confidence(false), PointerReferenceType)), + NameAndType("cp", Type::IntegerType(1, false)), + NameAndType("d", Type::IntegerType(1, false)), + NameAndType("long_transfer", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_COPROC_DATAPROCESSING: + return { + NameAndType("cp", Type::IntegerType(1, false)), + NameAndType("opc1", Type::IntegerType(1, false)), + NameAndType("d", Type::IntegerType(1, false)), + NameAndType("n", Type::IntegerType(1, false)), + NameAndType("m", Type::IntegerType(1, false)), + NameAndType("opc2", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_EXCLUSIVE_MONITORS_PASS: + case ARMV7_INTRIN_SET_EXCLUSIVE_MONITORS: + return { + NameAndType("address", Type::PointerType(4, Confidence(Type::VoidType(), 0), Confidence(false), Confidence(false), PointerReferenceType)), + NameAndType("size", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_SMC: + return { + NameAndType("imm", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_HVC: + return { + NameAndType("imm", Type::IntegerType(2, false)), + }; + case ARMV7_INTRIN_SEL: + return { + NameAndType("rn", Type::IntegerType(4, false)), + NameAndType("rm", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_QADD: + case ARMV7_INTRIN_QSUB: + case ARMV7_INTRIN_QDADD: + case ARMV7_INTRIN_QDSUB: + case ARMV7_INTRIN_QADD16: + case ARMV7_INTRIN_QADD8: + case ARMV7_INTRIN_QSUB16: + case ARMV7_INTRIN_QSUB8: + case ARMV7_INTRIN_UQADD16: + case ARMV7_INTRIN_UQADD8: + case ARMV7_INTRIN_UQSUB16: + case ARMV7_INTRIN_UQSUB8: + case ARMV7_INTRIN_QSAX: + case ARMV7_INTRIN_UQASX: + case ARMV7_INTRIN_UQSAX: + case ARMV7_INTRIN_SXTAB16: + case ARMV7_INTRIN_UXTAB16: + case ARMV7_INTRIN_SADD16: + case ARMV7_INTRIN_SADD8: + case ARMV7_INTRIN_SHADD16: + case ARMV7_INTRIN_SHADD8: + case ARMV7_INTRIN_SSUB8: + case ARMV7_INTRIN_SHSUB8: + case ARMV7_INTRIN_SHSUB16: + case ARMV7_INTRIN_UHSUB8: + case ARMV7_INTRIN_UHSUB16: + case ARMV7_INTRIN_USUB8: + case ARMV7_INTRIN_USUB16: + case ARMV7_INTRIN_USAD8: + return { + NameAndType("source1", Type::IntegerType(4, false)), + NameAndType("source2", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_SXTB16: + case ARMV7_INTRIN_UXTB16: + return { + NameAndType("source", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_USADA8: + return { + NameAndType("source1", Type::IntegerType(4, false)), + NameAndType("source2", Type::IntegerType(4, false)), + NameAndType("accumulator", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_VRINTA: + return { + NameAndType("source_register", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_VMAXNM: + case ARMV7_INTRIN_VMINNM: + return { + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VMAX: + case ARMV7_INTRIN_VMIN: + case ARMV7_INTRIN_VPMAX: + case ARMV7_INTRIN_VPMIN: + case ARMV7_INTRIN_VCGT: + case ARMV7_INTRIN_VHADD: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VCEQ: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_float", Type::BoolType()), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VREV16: + case ARMV7_INTRIN_VREV32: + case ARMV7_INTRIN_VREV64: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("source", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VEXT: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + NameAndType("index", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_SSAT: + case ARMV7_INTRIN_SSAT16: + case ARMV7_INTRIN_USAT16: + case ARMV7_INTRIN_USAT: + return { + NameAndType("saturate_to", Type::IntegerType(4, false)), + NameAndType("source", Type::IntegerType(4, false)), + }; + case ARMV7_INTRIN_VTBL: + return { + NameAndType("length", Type::IntegerType(1, false)), + NameAndType("table0", Type::IntegerType(8, false)), + NameAndType("table1", Type::IntegerType(8, false)), + NameAndType("table2", Type::IntegerType(8, false)), + NameAndType("table3", Type::IntegerType(8, false)), + NameAndType("indices", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VTBX: + return { + NameAndType("length", Type::IntegerType(1, false)), + NameAndType("table0", Type::IntegerType(8, false)), + NameAndType("table1", Type::IntegerType(8, false)), + NameAndType("table2", Type::IntegerType(8, false)), + NameAndType("table3", Type::IntegerType(8, false)), + NameAndType("indices", Type::IntegerType(8, false)), + NameAndType("destination", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VDUP: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("source", Type::IntegerType(8, false)), + NameAndType("index", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_VABD: + case ARMV7_INTRIN_VABDL: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VABA: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("accumulator", Type::IntegerType(16, false)), + NameAndType("source1", Type::IntegerType(16, false)), + NameAndType("source2", Type::IntegerType(16, false)), + }; + case ARMV7_INTRIN_VABAL: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("accumulator", Type::IntegerType(16, false)), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VADDL: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VADDW: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("source1", Type::IntegerType(16, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VRADDHN: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("source1", Type::IntegerType(16, false)), + NameAndType("source2", Type::IntegerType(16, false)), + }; + case ARMV7_INTRIN_VRSHR: + case ARMV7_INTRIN_VRSHL: + case ARMV7_INTRIN_VSHL: + case ARMV7_INTRIN_VSHR: + case ARMV7_INTRIN_VSHLL: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("source", Type::IntegerType(8, false)), + NameAndType("shift", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VBIF: + case ARMV7_INTRIN_VBIT: + case ARMV7_INTRIN_VBSL: + return { + NameAndType("destination", Type::IntegerType(8, false)), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VSRA: + case ARMV7_INTRIN_VRSRA: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("accumulator", Type::IntegerType(8, false)), + NameAndType("source", Type::IntegerType(8, false)), + NameAndType("shift", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VSRI: + case ARMV7_INTRIN_VSLI: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("destination", Type::IntegerType(8, false)), + NameAndType("source", Type::IntegerType(8, false)), + NameAndType("shift", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VLD2: + case ARMV7_INTRIN_VLD4: + return { + NameAndType("address", Type::PointerType(4, Confidence(Type::VoidType(), 0), Confidence(false), Confidence(false), PointerReferenceType)), + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("alignment", Type::IntegerType(1, false)), + NameAndType("index", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_VST2: + case ARMV7_INTRIN_VST4: + return { + NameAndType("address", Type::PointerType(4, Confidence(Type::VoidType(), 0), Confidence(false), Confidence(false), PointerReferenceType)), + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("alignment", Type::IntegerType(1, false)), + NameAndType("index", Type::IntegerType(1, false)), + NameAndType("source0", Type::IntegerType(8, false)), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + NameAndType("source3", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VQADD: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_VQSHL: + case ARMV7_INTRIN_VQRSHL: + case ARMV7_INTRIN_VQSHRN: + case ARMV7_INTRIN_VQSHRUN: + case ARMV7_INTRIN_VQRSHRN: + case ARMV7_INTRIN_VQRSHRUN: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("source_unsigned", Type::BoolType()), + NameAndType("destination_unsigned", Type::BoolType()), + NameAndType("source", Type::IntegerType( + (intrinsic == ARMV7_INTRIN_VQSHL || intrinsic == ARMV7_INTRIN_VQRSHL) ? 8 : 16, false)), + NameAndType("shift", Type::IntegerType( + (intrinsic == ARMV7_INTRIN_VQSHL || intrinsic == ARMV7_INTRIN_VQRSHL) ? 8 : 16, false)), + }; + case ARMV7_INTRIN_VQMOVN: + case ARMV7_INTRIN_VQMOVUN: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("source_unsigned", Type::BoolType()), + NameAndType("destination_unsigned", Type::BoolType()), + NameAndType("source", Type::IntegerType(16, false)), + }; + case ARMV7_INTRIN_VMLA: + case ARMV7_INTRIN_VMLS: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("accumulator", Type::IntegerType(8, false)), + NameAndType("source", Type::IntegerType(8, false)), + NameAndType("scalar", Type::IntegerType(8, false)), + NameAndType("index", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_VMLAL: + case ARMV7_INTRIN_VMLSL: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("accumulator", Type::IntegerType(16, false)), + NameAndType("source", Type::IntegerType(8, false)), + NameAndType("scalar", Type::IntegerType(8, false)), + NameAndType("index", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_VMUL: + case ARMV7_INTRIN_VQDMULL: + return { + NameAndType("size", Type::IntegerType(1, false)), + NameAndType("is_unsigned", Type::BoolType()), + NameAndType("source1", Type::IntegerType(8, false)), + NameAndType("source2", Type::IntegerType(8, false)), + }; + case ARMV7_INTRIN_SRS: + return { + NameAndType("mode", Type::IntegerType(1, false)), + NameAndType("increment", Type::BoolType()), + NameAndType("wordhigher", Type::BoolType()), + NameAndType("writeback", Type::BoolType()), + }; + case ARMV7_INTRIN_RFE: + return { + NameAndType("base_register", Type::IntegerType(4, false)), + NameAndType("increment", Type::BoolType()), + NameAndType("wordhigher", Type::BoolType()), + NameAndType("writeback", Type::BoolType()), + }; + case ARMV7_INTRIN_CPS: + return { + NameAndType("mode", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_SETEND: + return { + NameAndType("endian", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_CPSID: + case ARMV7_INTRIN_CPSIE: + return { + NameAndType("iflags", Type::IntegerType(1, false)), + NameAndType("mode", Type::IntegerType(1, false)), + }; case ARMV7_INTRIN_MRS: // return {NameAndType(Type::IntegerType(4, false))}; return { @@ -1736,8 +2443,41 @@ class Thumb2Architecture: public ArmCommonArchitecture NameAndType("msr", Confidence>(Type::EnumerationType(this, get_msr_op_enum(), 4, false), BN_FULL_CONFIDENCE)), NameAndType(Type::IntegerType(4, false)) }; + case ARMV7_INTRIN_VMRS: + return { + NameAndType("status_register", Confidence>(Type::EnumerationType(this, GetVfpStatusRegisterEnum(), 4, false), BN_FULL_CONFIDENCE)), + }; + case ARMV7_INTRIN_VMSR: + return { + NameAndType("status_register", Confidence>(Type::EnumerationType(this, GetVfpStatusRegisterEnum(), 4, false), BN_FULL_CONFIDENCE)), + NameAndType("source_register", Type::IntegerType(4, false)), + }; case ARMV7_INTRIN_DBG: return {NameAndType(Type::IntegerType(1, false))}; + case ARMV7_INTRIN_HINT: + return {NameAndType("imm", Type::IntegerType(1, false))}; + case ARMV7_INTRIN_PLD: + return { + NameAndType("address", Type::PointerType(4, Confidence(Type::VoidType(), 0), Confidence(false), Confidence(false), PointerReferenceType)), + }; + case ARMV7_INTRIN_CRC32B: + case ARMV7_INTRIN_CRC32CB: + return { + NameAndType("accumulator", Type::IntegerType(4, false)), + NameAndType("value", Type::IntegerType(1, false)), + }; + case ARMV7_INTRIN_CRC32H: + case ARMV7_INTRIN_CRC32CH: + return { + NameAndType("accumulator", Type::IntegerType(4, false)), + NameAndType("value", Type::IntegerType(2, false)), + }; + case ARMV7_INTRIN_CRC32W: + case ARMV7_INTRIN_CRC32CW: + return { + NameAndType("accumulator", Type::IntegerType(4, false)), + NameAndType("value", Type::IntegerType(4, false)), + }; default: return vector(); } @@ -1751,8 +2491,111 @@ class Thumb2Architecture: public ArmCommonArchitecture return { Type::IntegerType(4, false) }; case ARMV7_INTRIN_COPROC_GETTWOWORDS: return { Type::IntegerType(4, false), Type::IntegerType(4, false) }; + case ARMV7_INTRIN_EXCLUSIVE_MONITORS_PASS: + return { Type::BoolType() }; case ARMV7_INTRIN_MRS: + case ARMV7_INTRIN_VMRS: + case ARMV7_INTRIN_SEL: + case ARMV7_INTRIN_QADD: + case ARMV7_INTRIN_QSUB: + case ARMV7_INTRIN_QDADD: + case ARMV7_INTRIN_QDSUB: + case ARMV7_INTRIN_QADD16: + case ARMV7_INTRIN_QADD8: + case ARMV7_INTRIN_QSUB16: + case ARMV7_INTRIN_QSUB8: + case ARMV7_INTRIN_UQADD16: + case ARMV7_INTRIN_UQADD8: + case ARMV7_INTRIN_UQSUB16: + case ARMV7_INTRIN_UQSUB8: + case ARMV7_INTRIN_QSAX: + case ARMV7_INTRIN_UQASX: + case ARMV7_INTRIN_SXTAB16: + case ARMV7_INTRIN_SXTB16: + case ARMV7_INTRIN_UXTAB16: + case ARMV7_INTRIN_UXTB16: + case ARMV7_INTRIN_SADD16: + case ARMV7_INTRIN_SADD8: + case ARMV7_INTRIN_SHADD16: + case ARMV7_INTRIN_SHADD8: + case ARMV7_INTRIN_SSUB8: + case ARMV7_INTRIN_SHSUB8: + case ARMV7_INTRIN_SHSUB16: + case ARMV7_INTRIN_UHSUB8: + case ARMV7_INTRIN_UHSUB16: + case ARMV7_INTRIN_USUB8: + case ARMV7_INTRIN_USUB16: + case ARMV7_INTRIN_USAD8: + case ARMV7_INTRIN_USADA8: + case ARMV7_INTRIN_UQSAX: + case ARMV7_INTRIN_VRINTA: + case ARMV7_INTRIN_VMAXNM: + case ARMV7_INTRIN_VMINNM: + case ARMV7_INTRIN_SSAT: + case ARMV7_INTRIN_SSAT16: + case ARMV7_INTRIN_USAT: + case ARMV7_INTRIN_USAT16: + case ARMV7_INTRIN_CRC32B: + case ARMV7_INTRIN_CRC32CB: + case ARMV7_INTRIN_CRC32CH: + case ARMV7_INTRIN_CRC32CW: + case ARMV7_INTRIN_CRC32H: + case ARMV7_INTRIN_CRC32W: return {Type::IntegerType(4, false)}; + case ARMV7_INTRIN_VLD2: + return {Type::IntegerType(8, false), Type::IntegerType(8, false)}; + case ARMV7_INTRIN_VLD4: + return {Type::IntegerType(8, false), Type::IntegerType(8, false), Type::IntegerType(8, false), Type::IntegerType(8, false)}; + case ARMV7_INTRIN_VTBL: + case ARMV7_INTRIN_VTBX: + case ARMV7_INTRIN_VDUP: + case ARMV7_INTRIN_VABD: + case ARMV7_INTRIN_VABA: + case ARMV7_INTRIN_VRSHR: + case ARMV7_INTRIN_VRSHL: + case ARMV7_INTRIN_VSRA: + case ARMV7_INTRIN_VRSRA: + case ARMV7_INTRIN_VSRI: + case ARMV7_INTRIN_VSLI: + case ARMV7_INTRIN_VRADDHN: + case ARMV7_INTRIN_VSHL: + case ARMV7_INTRIN_VSHR: + case ARMV7_INTRIN_VMAX: + case ARMV7_INTRIN_VMIN: + case ARMV7_INTRIN_VPMAX: + case ARMV7_INTRIN_VPMIN: + case ARMV7_INTRIN_VREV16: + case ARMV7_INTRIN_VREV32: + case ARMV7_INTRIN_VREV64: + case ARMV7_INTRIN_VEXT: + case ARMV7_INTRIN_VCGT: + case ARMV7_INTRIN_VCEQ: + case ARMV7_INTRIN_VQADD: + case ARMV7_INTRIN_VHADD: + case ARMV7_INTRIN_VQSHL: + case ARMV7_INTRIN_VQRSHL: + case ARMV7_INTRIN_VQSHRN: + case ARMV7_INTRIN_VQSHRUN: + case ARMV7_INTRIN_VQRSHRN: + case ARMV7_INTRIN_VQRSHRUN: + case ARMV7_INTRIN_VQMOVN: + case ARMV7_INTRIN_VQMOVUN: + case ARMV7_INTRIN_VMLA: + case ARMV7_INTRIN_VMLS: + case ARMV7_INTRIN_VMUL: + case ARMV7_INTRIN_VBIF: + case ARMV7_INTRIN_VBIT: + case ARMV7_INTRIN_VBSL: + return {Type::IntegerType(8, false)}; + case ARMV7_INTRIN_VABAL: + case ARMV7_INTRIN_VABDL: + case ARMV7_INTRIN_VADDL: + case ARMV7_INTRIN_VADDW: + case ARMV7_INTRIN_VSHLL: + case ARMV7_INTRIN_VMLAL: + case ARMV7_INTRIN_VMLSL: + case ARMV7_INTRIN_VQDMULL: + return {Type::IntegerType(16, false)}; case ARMV7_INTRIN_MSR: // return {Type::IntegerType(4, false)}; return {}; diff --git a/arch/armv7/thumb2_disasm/disassembler.cpp b/arch/armv7/thumb2_disasm/disassembler.cpp index 6910307fc8..3161e951fa 100644 --- a/arch/armv7/thumb2_disasm/disassembler.cpp +++ b/arch/armv7/thumb2_disasm/disassembler.cpp @@ -15,6 +15,107 @@ using namespace std; /* helper prototypes */ int get_reg_name(int reg_idx, char *reg_name); +static bool thumb_decode_crc32(struct decomp_request *info, struct decomp_result *result) +{ + uint32_t instr = info->instr_word32; + if ((instr & 0xffe0f0c0) != 0xfac0f080) + return false; + + uint32_t size = (instr >> 4) & 3; + uint32_t castagnoli = (instr >> 20) & 1; + if (size == 3) + return false; + + static const instruction_format instrFormats[] = + { + { /* CRC32B ,, */ + "crc32b", + 0, + { + {OPERAND_FORMAT_REG,FIELD_Rd,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_REG,FIELD_Rn,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_REG,FIELD_Rm,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_END,FIELD_UNINIT,FIELD_UNINIT,"","",WRITEBACK_NO}, + }, + 3 + }, + { /* CRC32H ,, */ + "crc32h", + 0, + { + {OPERAND_FORMAT_REG,FIELD_Rd,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_REG,FIELD_Rn,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_REG,FIELD_Rm,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_END,FIELD_UNINIT,FIELD_UNINIT,"","",WRITEBACK_NO}, + }, + 3 + }, + { /* CRC32W ,, */ + "crc32w", + 0, + { + {OPERAND_FORMAT_REG,FIELD_Rd,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_REG,FIELD_Rn,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_REG,FIELD_Rm,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_END,FIELD_UNINIT,FIELD_UNINIT,"","",WRITEBACK_NO}, + }, + 3 + }, + { /* CRC32CB ,, */ + "crc32cb", + 0, + { + {OPERAND_FORMAT_REG,FIELD_Rd,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_REG,FIELD_Rn,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_REG,FIELD_Rm,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_END,FIELD_UNINIT,FIELD_UNINIT,"","",WRITEBACK_NO}, + }, + 3 + }, + { /* CRC32CH ,, */ + "crc32ch", + 0, + { + {OPERAND_FORMAT_REG,FIELD_Rd,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_REG,FIELD_Rn,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_REG,FIELD_Rm,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_END,FIELD_UNINIT,FIELD_UNINIT,"","",WRITEBACK_NO}, + }, + 3 + }, + { /* CRC32CW ,, */ + "crc32cw", + 0, + { + {OPERAND_FORMAT_REG,FIELD_Rd,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_REG,FIELD_Rn,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_REG,FIELD_Rm,FIELD_UNINIT,"","",WRITEBACK_NO}, + {OPERAND_FORMAT_END,FIELD_UNINIT,FIELD_UNINIT,"","",WRITEBACK_NO}, + }, + 3 + }, + }; + static const armv7::Operation operations[] = { + ARMV7_CRC32B, ARMV7_CRC32H, ARMV7_CRC32W, + ARMV7_CRC32CB, ARMV7_CRC32CH, ARMV7_CRC32CW, + }; + + uint32_t index = castagnoli ? size + 3 : size; + result->instrSize = 32; + result->group = INSN_GROUP_CRC; + result->fields[FIELD_Rn] = (instr >> 16) & 0xf; + result->fields_mask[FIELD_Rn >> 6] |= 1LL << (FIELD_Rn & 63); + result->fields[FIELD_Rd] = (instr >> 8) & 0xf; + result->fields_mask[FIELD_Rd >> 6] |= 1LL << (FIELD_Rd & 63); + result->fields[FIELD_Rm] = instr & 0xf; + result->fields_mask[FIELD_Rm >> 6] |= 1LL << (FIELD_Rm & 63); + result->formats = &instrFormats[index]; + result->formatCount = 1; + result->format = &instrFormats[index]; + result->mnem = operations[index]; + return true; +} + /* decompose an instruction stream into a decomposition result */ int thumb_decompose(struct decomp_request *info, struct decomp_result *result) { @@ -30,6 +131,9 @@ int thumb_decompose(struct decomp_request *info, struct decomp_result *result) result->formatCount = 0; result->pc = info->addr + 4; + if (thumb_decode_crc32(info, result)) + return STATUS_OK; + /* jump into generated code */ rc = thumb_root(info, result); @@ -521,4 +625,3 @@ get_reg_name(int reg_idx, char *reg_name) //printf("in response to %d, returned %s and rc=%d\n", reg_idx, reg_name, rc); return rc; } - diff --git a/arch/armv7/thumb2_disasm/il_thumb2.cpp b/arch/armv7/thumb2_disasm/il_thumb2.cpp index cc3856c985..c1032078c8 100644 --- a/arch/armv7/thumb2_disasm/il_thumb2.cpp +++ b/arch/armv7/thumb2_disasm/il_thumb2.cpp @@ -12,6 +12,10 @@ using namespace armv7; #define ALIGN4(a) ((a) & 0xFFFFFFFC) bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il, decomp_result* instr, bool ifThenBlock); +static void WriteAddCarryOperand(LowLevelILFunction& il, decomp_result* instr, bool writeFlags); +static void WriteAsrOperand(LowLevelILFunction& il, decomp_result* instr, bool writeFlags); +static ExprId GetMemoryAddress(LowLevelILFunction& il, decomp_result* instr, size_t operand, uint32_t size, + bool canWriteback = true, uint32_t align = 0); static uint32_t GetRegisterByIndex(uint32_t i, const char* prefix = "") { @@ -20,7 +24,7 @@ static uint32_t GetRegisterByIndex(uint32_t i, const char* prefix = "") if (strcmp(prefix, "d") == 0) return REG_D0 + i; if (strcmp(prefix, "q") == 0) - return REG_R0 + (i / 2) + (i % 2) + REG_Q0; // TODO: This might be the same as above. + return REG_Q0 + (i >> 1); return REG_R0 + i; } @@ -133,6 +137,34 @@ static int GetSpecialRegister(LowLevelILFunction& il, decomp_result* instr, size return REG_INVALID; } +static int GetVfpStatusRegister(decomp_result* instr, size_t operand) +{ + if (instr->format->operands[operand].type != OPERAND_FORMAT_FPSCR) + return REG_INVALID; + + switch (instr->fields[FIELD_FPSCR]) + { + case 0: + return REGS_FPSID; + case 1: + return REGS_FPSCR; + case 5: + return REGS_MVFR2; + case 6: + return REGS_MVFR1; + case 7: + return REGS_MVFR0; + case 8: + return REGS_FPEXC; + case 9: + return REGS_FPINST; + case 10: + return REGS_FPINST2; + default: + return REG_INVALID; + } +} + static ExprId ReadILOperand(LowLevelILFunction& il, decomp_result* instr, size_t operand, size_t size = 4) { uint32_t value; @@ -189,6 +221,129 @@ static uint32_t GetRegisterSize(decomp_result* instr, size_t operand) return RegisterSizeFromPrefix(instr->format->operands[operand].prefix); } +static ExprId ReadFloatOperand(LowLevelILFunction& il, decomp_result* instr, size_t operand, size_t size) +{ + const instruction_operand_format& op = instr->format->operands[operand]; + switch (op.type) + { + case OPERAND_FORMAT_REG_FP: + return il.Register(size, GetRegisterByIndex(instr->fields[op.field0], op.prefix)); + case OPERAND_FORMAT_ZERO: + return il.FloatConstRaw(size, 0); + default: + return ReadILOperand(il, instr, operand, size); + } +} + +static void FloatCompare(LowLevelILFunction& il, decomp_result* instr) +{ + size_t size = GetRegisterSize(instr, 0); + ExprId lhs = ReadFloatOperand(il, instr, 0, size); + ExprId rhs = ReadFloatOperand(il, instr, 1, size); + + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.FloatCompareLessThan(size, lhs, rhs))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.FloatCompareEqual(size, lhs, rhs))); + il.AddInstruction(il.SetFlag(IL_FLAG_C, il.Not(1, il.FloatCompareLessThan(size, lhs, rhs)))); + il.AddInstruction(il.SetFlag(IL_FLAG_V, il.FloatCompareUnordered(size, lhs, rhs))); +} + +static ExprId RoundFloatOperand(LowLevelILFunction& il, decomp_result* instr) +{ + size_t size = GetRegisterSize(instr, 0); + ExprId src = ReadILOperand(il, instr, 1, size); + if (strncmp(instr->format->operation, "vrintn", 6) == 0) + return il.RoundToInt(size, src); + if (strncmp(instr->format->operation, "vrintp", 6) == 0) + return il.Ceil(size, src); + if (strncmp(instr->format->operation, "vrintm", 6) == 0) + return il.Floor(size, src); + if (strncmp(instr->format->operation, "vrintz", 6) == 0) + return il.FloatTrunc(size, src); + return il.Unimplemented(); +} + +static ExprId FixedPointScale(LowLevelILFunction& il, size_t size, uint64_t fractionalBits) +{ + double scale = static_cast(UINT64_C(1) << fractionalBits); + if (size == 8) + return il.FloatConstDouble(scale); + return il.FloatConstSingle(static_cast(scale)); +} + +static bool IsSignedVectorElement(decomp_result* instr) +{ + return IS_FIELD_PRESENT(instr, FIELD_unsigned) && (instr->fields[FIELD_unsigned] == 0); +} + +static ExprId ReadVectorElement(LowLevelILFunction& il, decomp_result* instr, size_t operand, size_t outputSize) +{ + const instruction_operand_format& op = instr->format->operands[operand]; + size_t elementSize = instr->fields[FIELD_esize] / 8; + size_t regSize = RegisterSizeFromPrefix(op.prefix); + size_t shift = instr->fields[op.field1] * elementSize * 8; + uint32_t reg = GetRegisterByIndex(instr->fields[op.field0], op.prefix); + + ExprId value = il.Register(regSize, reg); + if (shift != 0) + value = il.LogicalShiftRight(regSize, value, il.Const(1, shift)); + if (elementSize < regSize) + value = il.LowPart(elementSize, value); + if (outputSize > elementSize) + return IsSignedVectorElement(instr) ? il.SignExtend(outputSize, value) : il.ZeroExtend(outputSize, value); + return value; +} + +static ExprId InsertVectorElement(LowLevelILFunction& il, decomp_result* instr, size_t operand, ExprId src, size_t srcSize) +{ + const instruction_operand_format& op = instr->format->operands[operand]; + size_t elementSize = instr->fields[FIELD_esize] / 8; + size_t regSize = RegisterSizeFromPrefix(op.prefix); + size_t shift = instr->fields[op.field1] * elementSize * 8; + size_t elementBits = elementSize * 8; + uint64_t elementMask = (elementBits == 64) ? UINT64_MAX : ((1ULL << elementBits) - 1); + uint64_t shiftedMask = elementMask << shift; + uint32_t reg = GetRegisterByIndex(instr->fields[op.field0], op.prefix); + + ExprId value = src; + if (srcSize > elementSize) + value = il.LowPart(elementSize, value); + if (regSize > elementSize) + value = il.ZeroExtend(regSize, value); + if (shift != 0) + value = il.ShiftLeft(regSize, value, il.Const(1, shift)); + + return il.Or(regSize, + il.And(regSize, il.Register(regSize, reg), il.Const(regSize, ~shiftedMask)), + value); +} + +static ExprId ReadVst1Element(LowLevelILFunction& il, uint32_t reg, size_t elementSize, size_t index) +{ + size_t shift = index * elementSize * 8; + ExprId value = il.Register(8, reg); + if (shift != 0) + value = il.LogicalShiftRight(8, value, il.Const(1, shift)); + return il.LowPart(elementSize, value); +} + +static ExprId InsertVld1Element(LowLevelILFunction& il, uint32_t reg, ExprId src, size_t elementSize, size_t index) +{ + size_t shift = index * elementSize * 8; + size_t elementBits = elementSize * 8; + uint64_t elementMask = (elementBits == 64) ? UINT64_MAX : ((1ULL << elementBits) - 1); + uint64_t shiftedMask = elementMask << shift; + + ExprId value = src; + if (elementSize < 8) + value = il.ZeroExtend(8, value); + if (shift != 0) + value = il.ShiftLeft(8, value, il.Const(1, shift)); + + return il.Or(8, + il.And(8, il.Register(8, reg), il.Const(8, ~shiftedMask)), + value); +} + static ExprId ReadShiftedOperand(LowLevelILFunction& il, decomp_result* instr, size_t operand, size_t size = 4) { uint32_t shift_t = instr->fields[FIELD_shift_t]; @@ -215,6 +370,56 @@ static ExprId ReadShiftedOperand(LowLevelILFunction& il, decomp_result* instr, s } } +static bool GetShiftCarryOut(LowLevelILFunction& il, decomp_result* instr, size_t operand, ExprId& carry) +{ + if (IS_FIELD_PRESENT(instr, FIELD_carry)) + { + carry = il.Const(0, instr->fields[FIELD_carry] ? 1 : 0); + return true; + } + + if (!IS_FIELD_PRESENT(instr, FIELD_shift_t) || !IS_FIELD_PRESENT(instr, FIELD_shift_n)) + return false; + + uint32_t shift_t = instr->fields[FIELD_shift_t]; + uint32_t shift_n = instr->fields[FIELD_shift_n]; + if (shift_n == 0) + return false; + + ExprId value = ReadILOperand(il, instr, operand, 4); + switch (shift_t) + { + case SRType_LSL: + carry = il.TestBit(4, value, il.Const(1, 32 - shift_n)); + return true; + case SRType_LSR: + case SRType_ASR: + carry = il.TestBit(4, value, il.Const(1, shift_n - 1)); + return true; + case SRType_ROR: + carry = il.TestBit(4, value, il.Const(1, (shift_n - 1) & 31)); + return true; + case SRType_RRX: + carry = il.TestBit(4, value, il.Const(1, 0)); + return true; + default: + return false; + } +} + +static size_t GetShiftCarryOperand(decomp_result* instr) +{ + if (instr->format->operandCount == 2) + return 1; + if (instr->format->operandCount == 3) + { + if (instr->format->operands[2].type == OPERAND_FORMAT_SHIFT) + return 1; + return 2; + } + return 2; +} + static ExprId ReadRotatedOperand(LowLevelILFunction& il, decomp_result* instr, size_t operand, size_t size = 4) { uint32_t rot_n = instr->fields[FIELD_rotation]; @@ -272,6 +477,45 @@ static uint32_t GetRegisterOperand(decomp_result* instr, size_t operand) } } +static uint32_t GetCrc32Intrinsic(armv7::Operation operation) +{ + switch (operation) + { + case armv7::ARMV7_CRC32B: + return ARMV7_INTRIN_CRC32B; + case armv7::ARMV7_CRC32CB: + return ARMV7_INTRIN_CRC32CB; + case armv7::ARMV7_CRC32CH: + return ARMV7_INTRIN_CRC32CH; + case armv7::ARMV7_CRC32CW: + return ARMV7_INTRIN_CRC32CW; + case armv7::ARMV7_CRC32H: + return ARMV7_INTRIN_CRC32H; + case armv7::ARMV7_CRC32W: + return ARMV7_INTRIN_CRC32W; + default: + return 0; + } +} + +static size_t GetCrc32ValueSize(armv7::Operation operation) +{ + switch (operation) + { + case armv7::ARMV7_CRC32B: + case armv7::ARMV7_CRC32CB: + return 1; + case armv7::ARMV7_CRC32H: + case armv7::ARMV7_CRC32CH: + return 2; + case armv7::ARMV7_CRC32W: + case armv7::ARMV7_CRC32CW: + return 4; + default: + return 0; + } +} + static ExprId WriteILOperand(LowLevelILFunction& il, decomp_result* instr, size_t operand, ExprId value, size_t size = 4, uint32_t flags = 0) { @@ -298,34 +542,1868 @@ static ExprId WriteILOperand(LowLevelILFunction& il, decomp_result* instr, size_ } } - -static ExprId WriteArithOperand(LowLevelILFunction& il, decomp_result* instr, ExprId value, size_t size = 4, - uint32_t flags = 0) + +static ExprId WriteArithOperand(LowLevelILFunction& il, decomp_result* instr, ExprId value, size_t size = 4, + uint32_t flags = 0) +{ + return WriteILOperand(il, instr, 0, value, size, flags); +} + +static void WriteLogicalOperand(LowLevelILFunction& il, decomp_result* instr, bool writeFlags, bool exclusiveOr) +{ + ExprId value = exclusiveOr + ? il.Xor(4, ReadArithOperand(il, instr, 0), ReadArithOperand(il, instr, 1)) + : il.And(4, ReadArithOperand(il, instr, 0), ReadArithOperand(il, instr, 1)); + if (!writeFlags) + { + il.AddInstruction(WriteArithOperand(il, instr, value)); + return; + } + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), value)); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(4, il.Register(4, LLIL_TEMP(0)), il.Const(4, 0)))); + + ExprId carry; + if (GetShiftCarryOut(il, instr, GetShiftCarryOperand(instr), carry)) + il.AddInstruction(il.SetFlag(IL_FLAG_C, carry)); + + il.AddInstruction(WriteILOperand(il, instr, 0, il.Register(4, LLIL_TEMP(0)))); +} + +static void WriteTestOperand(LowLevelILFunction& il, decomp_result* instr) +{ + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.And(4, ReadILOperand(il, instr, 0), ReadArithOperand(il, instr, 1)))); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(4, il.Register(4, LLIL_TEMP(0)), il.Const(4, 0)))); + + ExprId carry; + if (GetShiftCarryOut(il, instr, GetShiftCarryOperand(instr), carry)) + il.AddInstruction(il.SetFlag(IL_FLAG_C, carry)); +} + +static void WriteTestEquivalenceOperand(LowLevelILFunction& il, decomp_result* instr) +{ + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Xor(4, ReadILOperand(il, instr, 0), ReadArithOperand(il, instr, 1)))); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(4, il.Register(4, LLIL_TEMP(0)), il.Const(4, 0)))); + + ExprId carry; + if (GetShiftCarryOut(il, instr, GetShiftCarryOperand(instr), carry)) + il.AddInstruction(il.SetFlag(IL_FLAG_C, carry)); +} + +static void WriteBitClearOperand(LowLevelILFunction& il, decomp_result* instr, bool writeFlags) +{ + ExprId value = il.And(4, ReadArithOperand(il, instr, 0), + il.Not(4, ReadArithOperand(il, instr, 1))); + if (!writeFlags) + { + il.AddInstruction(WriteArithOperand(il, instr, value)); + return; + } + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), value)); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(4, il.Register(4, LLIL_TEMP(0)), il.Const(4, 0)))); + + ExprId carry; + if (GetShiftCarryOut(il, instr, GetShiftCarryOperand(instr), carry)) + il.AddInstruction(il.SetFlag(IL_FLAG_C, carry)); + + il.AddInstruction(WriteILOperand(il, instr, 0, il.Register(4, LLIL_TEMP(0)))); +} + +static void WriteMoveNotOperand(LowLevelILFunction& il, decomp_result* instr, bool writeFlags) +{ + ExprId value = il.Not(4, ReadArithOperand(il, instr, 1)); + if (!writeFlags) + { + il.AddInstruction(WriteILOperand(il, instr, 0, value)); + return; + } + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), value)); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(4, il.Register(4, LLIL_TEMP(0)), il.Const(4, 0)))); + + ExprId carry; + if (GetShiftCarryOut(il, instr, GetShiftCarryOperand(instr), carry)) + il.AddInstruction(il.SetFlag(IL_FLAG_C, carry)); + + il.AddInstruction(WriteILOperand(il, instr, 0, il.Register(4, LLIL_TEMP(0)))); +} + +static void WriteOrOperand(LowLevelILFunction& il, decomp_result* instr, bool writeFlags) +{ + ExprId value = il.Or(4, ReadArithOperand(il, instr, 0), ReadArithOperand(il, instr, 1)); + if (!writeFlags) + { + il.AddInstruction(WriteArithOperand(il, instr, value)); + return; + } + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), value)); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(4, il.Register(4, LLIL_TEMP(0)), il.Const(4, 0)))); + + ExprId carry; + if (GetShiftCarryOut(il, instr, GetShiftCarryOperand(instr), carry)) + il.AddInstruction(il.SetFlag(IL_FLAG_C, carry)); + + il.AddInstruction(WriteILOperand(il, instr, 0, il.Register(4, LLIL_TEMP(0)))); +} + +static void WritePackHalfwordOperand(LowLevelILFunction& il, decomp_result* instr, bool top) +{ + ExprId rn = ReadILOperand(il, instr, 1); + ExprId shiftedRm = ReadShiftedOperand(il, instr, 2); + ExprId result = top + ? il.Or(4, + il.And(4, shiftedRm, il.Const(4, 0xffff0000)), + il.And(4, rn, il.Const(4, 0xffff))) + : il.Or(4, + il.And(4, rn, il.Const(4, 0xffff0000)), + il.And(4, shiftedRm, il.Const(4, 0xffff))); + il.AddInstruction(WriteILOperand(il, instr, 0, result)); +} + +static void WriteSaturatingAddSubOperand(LowLevelILFunction& il, decomp_result* instr, bool subtract) +{ + uint32_t dest = GetRegisterOperand(instr, 0); + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + subtract ? ARMV7_INTRIN_QSUB : ARMV7_INTRIN_QADD, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); +} + +static void WriteSaturatingDoubleAddSubOperand(LowLevelILFunction& il, decomp_result* instr, bool subtract) +{ + uint32_t dest = GetRegisterOperand(instr, 0); + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + subtract ? ARMV7_INTRIN_QDSUB : ARMV7_INTRIN_QDADD, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); +} + +static void WriteSignedSaturatingParallelAddSubOperand(LowLevelILFunction& il, decomp_result* instr, size_t elementSize, bool subtract) +{ + uint32_t dest = GetRegisterOperand(instr, 0); + uint32_t intrinsic = 0; + if (elementSize == 2) + intrinsic = subtract ? ARMV7_INTRIN_QSUB16 : ARMV7_INTRIN_QADD16; + else + intrinsic = subtract ? ARMV7_INTRIN_QSUB8 : ARMV7_INTRIN_QADD8; + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); +} + +static void WriteUnsignedSaturatingParallelAddSubOperand(LowLevelILFunction& il, decomp_result* instr, size_t elementSize, bool subtract) +{ + uint32_t dest = GetRegisterOperand(instr, 0); + uint32_t intrinsic = 0; + if (elementSize == 2) + intrinsic = subtract ? ARMV7_INTRIN_UQSUB16 : ARMV7_INTRIN_UQADD16; + else + intrinsic = subtract ? ARMV7_INTRIN_UQSUB8 : ARMV7_INTRIN_UQADD8; + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); +} + +static void WriteSignedParallelAddSubOperand(LowLevelILFunction& il, decomp_result* instr, size_t elementSize, bool subtract) +{ + uint32_t dest = GetRegisterOperand(instr, 0); + ExprId source1 = ReadILOperand(il, instr, 1); + ExprId source2 = ReadILOperand(il, instr, 2); + + if (elementSize == 2) + { + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.And(2, + subtract ? il.Sub(2, source1, source2) : il.Add(2, source1, source2), + il.Const(2, 0xffff)))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.And(2, + subtract + ? il.Sub(2, + il.ArithShiftRight(4, source1, il.Const(1, 16)), + il.ArithShiftRight(4, source2, il.Const(1, 16))) + : il.Add(2, + il.ArithShiftRight(4, source1, il.Const(1, 16)), + il.ArithShiftRight(4, source2, il.Const(1, 16))), + il.Const(2, 0xffff)))); + il.AddInstruction(il.SetRegister(4, dest, + il.Or(4, + il.ShiftLeft(4, + il.And(2, il.Register(4, LLIL_TEMP(1)), il.Const(2, 0xffff)), + il.Const(1, 16)), + il.And(2, il.Register(4, LLIL_TEMP(0)), il.Const(2, 0xffff))))); + return; + } + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.And(1, + subtract ? il.Sub(1, source1, source2) : il.Add(1, source1, source2), + il.Const(1, 0xff)))); + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(1), + il.And(1, + subtract + ? il.Sub(1, + il.ArithShiftRight(4, source1, il.Const(1, 8)), + il.ArithShiftRight(4, source2, il.Const(1, 8))) + : il.Add(1, + il.ArithShiftRight(4, source1, il.Const(1, 8)), + il.ArithShiftRight(4, source2, il.Const(1, 8))), + il.Const(1, 0xff)))); + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(2), + il.And(1, + subtract + ? il.Sub(1, + il.ArithShiftRight(4, source1, il.Const(1, 16)), + il.ArithShiftRight(4, source2, il.Const(1, 16))) + : il.Add(1, + il.ArithShiftRight(4, source1, il.Const(1, 16)), + il.ArithShiftRight(4, source2, il.Const(1, 16))), + il.Const(1, 0xff)))); + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(3), + il.And(1, + subtract + ? il.Sub(1, + il.ArithShiftRight(4, source1, il.Const(1, 24)), + il.ArithShiftRight(4, source2, il.Const(1, 24))) + : il.Add(1, + il.ArithShiftRight(4, source1, il.Const(1, 24)), + il.ArithShiftRight(4, source2, il.Const(1, 24))), + il.Const(1, 0xff)))); + il.AddInstruction(il.SetRegister(4, dest, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, il.ZeroExtend(4, il.Register(1, LLIL_TEMP(3))), il.Const(1, 24)), + il.ShiftLeft(4, il.ZeroExtend(4, il.Register(1, LLIL_TEMP(2))), il.Const(1, 16))), + il.Or(4, + il.ShiftLeft(4, il.ZeroExtend(4, il.Register(1, LLIL_TEMP(1))), il.Const(1, 8)), + il.Register(1, LLIL_TEMP(0)))))); +} + +static void WriteUnsignedHalvingParallelAddOperand(LowLevelILFunction& il, decomp_result* instr, size_t elementSize) +{ + uint32_t dest = GetRegisterOperand(instr, 0); + ExprId source1 = ReadILOperand(il, instr, 1); + ExprId source2 = ReadILOperand(il, instr, 2); + + if (elementSize == 2) + { + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.And(2, + il.LogicalShiftRight(4, + il.Add(4, il.LowPart(2, source1), il.LowPart(2, source2)), + il.Const(1, 1)), + il.Const(2, 0xffff)))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.And(2, + il.LogicalShiftRight(4, + il.Add(4, + il.LogicalShiftRight(4, source1, il.Const(1, 16)), + il.LogicalShiftRight(4, source2, il.Const(1, 16))), + il.Const(1, 1)), + il.Const(2, 0xffff)))); + il.AddInstruction(il.SetRegister(4, dest, + il.Or(4, + il.ShiftLeft(4, + il.And(2, il.Register(4, LLIL_TEMP(1)), il.Const(2, 0xffff)), + il.Const(1, 16)), + il.And(2, il.Register(4, LLIL_TEMP(0)), il.Const(2, 0xffff))))); + return; + } + + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), + il.And(1, + il.LogicalShiftRight(4, + il.Add(4, il.LowPart(1, source1), il.LowPart(1, source2)), + il.Const(1, 1)), + il.Const(1, 0xff)))); + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(1), + il.And(1, + il.LogicalShiftRight(4, + il.Add(4, + il.LowPart(1, il.LogicalShiftRight(4, source1, il.Const(1, 8))), + il.LowPart(1, il.LogicalShiftRight(4, source2, il.Const(1, 8)))), + il.Const(1, 1)), + il.Const(1, 0xff)))); + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(2), + il.And(1, + il.LogicalShiftRight(4, + il.Add(4, + il.LowPart(1, il.LogicalShiftRight(4, source1, il.Const(1, 16))), + il.LowPart(1, il.LogicalShiftRight(4, source2, il.Const(1, 16)))), + il.Const(1, 1)), + il.Const(1, 0xff)))); + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(3), + il.And(1, + il.LogicalShiftRight(4, + il.Add(4, + il.LogicalShiftRight(4, source1, il.Const(1, 24)), + il.LogicalShiftRight(4, source2, il.Const(1, 24))), + il.Const(1, 1)), + il.Const(1, 0xff)))); + il.AddInstruction(il.SetRegister(4, dest, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, il.ZeroExtend(4, il.Register(1, LLIL_TEMP(3))), il.Const(1, 24)), + il.ShiftLeft(4, il.ZeroExtend(4, il.Register(1, LLIL_TEMP(2))), il.Const(1, 16))), + il.Or(4, + il.ShiftLeft(4, il.ZeroExtend(4, il.Register(1, LLIL_TEMP(1))), il.Const(1, 8)), + il.Register(1, LLIL_TEMP(0)))))); +} + +static void WriteSignedHalvingParallelExchangeOperand(LowLevelILFunction& il, decomp_result* instr, bool addLow) +{ + uint32_t dest = GetRegisterOperand(instr, 0); + ExprId source1 = ReadILOperand(il, instr, 1); + ExprId source2 = ReadILOperand(il, instr, 2); + + ExprId low = addLow + ? il.Add(4, + il.LowPart(2, source1), + il.ArithShiftRight(2, source2, il.Const(1, 16))) + : il.Sub(4, + il.LowPart(2, source1), + il.ArithShiftRight(2, source2, il.Const(1, 16))); + ExprId high = addLow + ? il.Sub(4, + il.ArithShiftRight(2, source1, il.Const(1, 16)), + il.LowPart(2, source2)) + : il.Add(4, + il.ArithShiftRight(2, source1, il.Const(1, 16)), + il.LowPart(2, source2)); + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), low)); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), high)); + il.AddInstruction(il.SetRegister(4, dest, + il.Or(4, + il.ShiftLeft(4, + il.LowPart(2, + il.ArithShiftRight(2, + il.Register(4, LLIL_TEMP(1)), + il.Const(1, 1))), + il.Const(1, 16)), + il.LowPart(2, + il.ArithShiftRight(2, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 1)))))); +} + +static void WriteUnsignedHalvingParallelExchangeOperand(LowLevelILFunction& il, decomp_result* instr, bool addLow) +{ + uint32_t dest = GetRegisterOperand(instr, 0); + ExprId source1 = ReadILOperand(il, instr, 1); + ExprId source2 = ReadILOperand(il, instr, 2); + + ExprId low = addLow + ? il.Add(4, + il.LowPart(2, source1), + il.LogicalShiftRight(2, source2, il.Const(1, 16))) + : il.Sub(4, + il.LowPart(2, source1), + il.LogicalShiftRight(2, source2, il.Const(1, 16))); + ExprId high = addLow + ? il.Sub(4, + il.LogicalShiftRight(2, source1, il.Const(1, 16)), + il.LowPart(2, source2)) + : il.Add(4, + il.LogicalShiftRight(2, source1, il.Const(1, 16)), + il.LowPart(2, source2)); + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), low)); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), high)); + il.AddInstruction(il.SetRegister(4, dest, + il.Or(4, + il.ShiftLeft(4, + il.LowPart(2, + il.LogicalShiftRight(2, + il.Register(4, LLIL_TEMP(1)), + il.Const(1, 1))), + il.Const(1, 16)), + il.LowPart(2, + il.LogicalShiftRight(2, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 1)))))); +} + +static void WriteSignedParallelExchangeOperand(LowLevelILFunction& il, decomp_result* instr, bool addLow) +{ + uint32_t dest = GetRegisterOperand(instr, 0); + ExprId source1 = ReadILOperand(il, instr, 1); + ExprId source2 = ReadILOperand(il, instr, 2); + ExprId source1Low = il.LowPart(2, source1); + ExprId source1High = il.ArithShiftRight(2, source1, il.Const(1, 16)); + ExprId source2Low = il.LowPart(2, source2); + ExprId source2High = il.ArithShiftRight(2, source2, il.Const(1, 16)); + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + addLow ? il.Add(4, source1Low, source2High) : il.Sub(4, source1Low, source2High))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + addLow ? il.Sub(4, source1High, source2Low) : il.Add(4, source1High, source2Low))); + il.AddInstruction(il.SetRegister(4, dest, + il.Or(4, + il.ShiftLeft(4, il.Register(2, LLIL_TEMP(1)), il.Const(1, 16)), + il.Register(2, LLIL_TEMP(0))))); +} + +static void WriteUnsignedParallelExchangeOperand(LowLevelILFunction& il, decomp_result* instr, bool addLow) +{ + uint32_t dest = GetRegisterOperand(instr, 0); + ExprId source1 = ReadILOperand(il, instr, 1); + ExprId source2 = ReadILOperand(il, instr, 2); + ExprId source1Low = il.LowPart(2, source1); + ExprId source1High = il.LogicalShiftRight(2, source1, il.Const(1, 16)); + ExprId source2Low = il.LowPart(2, source2); + ExprId source2High = il.LogicalShiftRight(2, source2, il.Const(1, 16)); + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + addLow ? il.Add(4, source1Low, source2High) : il.Sub(4, source1Low, source2High))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + addLow ? il.Sub(4, source1High, source2Low) : il.Add(4, source1High, source2Low))); + il.AddInstruction(il.SetRegister(4, dest, + il.Or(4, + il.ShiftLeft(4, il.Register(2, LLIL_TEMP(1)), il.Const(1, 16)), + il.Register(2, LLIL_TEMP(0))))); +} + +static void WriteAddCarryOperand(LowLevelILFunction& il, decomp_result* instr, bool writeFlags) +{ + ExprId lhs = ReadArithOperand(il, instr, 0); + ExprId rhs = ReadArithOperand(il, instr, 1); + ExprId carry = il.Flag(IL_FLAG_C); + ExprId value = il.AddCarry(4, lhs, rhs, carry); + if (!writeFlags) + { + il.AddInstruction(WriteArithOperand(il, instr, value)); + return; + } + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), value)); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(4, il.Register(4, LLIL_TEMP(0)), il.Const(4, 0)))); + il.AddInstruction(il.SetFlag(IL_FLAG_C, + il.Or(1, + il.CompareUnsignedLessThan(4, il.Register(4, LLIL_TEMP(0)), lhs), + il.And(1, carry, il.CompareEqual(4, il.Register(4, LLIL_TEMP(0)), lhs))))); + il.AddInstruction(il.SetFlag(IL_FLAG_V, + il.And(1, + il.TestBit(4, il.Xor(4, lhs, il.Register(4, LLIL_TEMP(0))), il.Const(1, 31)), + il.TestBit(4, il.Xor(4, rhs, il.Register(4, LLIL_TEMP(0))), il.Const(1, 31))))); + il.AddInstruction(WriteILOperand(il, instr, 0, il.Register(4, LLIL_TEMP(0)))); +} + +static void WriteAsrOperand(LowLevelILFunction& il, decomp_result* instr, bool writeFlags) +{ + ExprId source = ReadArithOperand(il, instr, 0); + ExprId shift = ReadArithOperand(il, instr, 1); + ExprId value = il.ArithShiftRight(4, source, shift); + if (!writeFlags) + { + il.AddInstruction(WriteArithOperand(il, instr, value)); + return; + } + + if ((instr->format->operandCount != 3) || (instr->format->operands[2].type != OPERAND_FORMAT_IMM)) + { + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), value)); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(4, il.Register(4, LLIL_TEMP(0)), il.Const(4, 0)))); + + ExprId shiftAmount = il.ZeroExtend(4, il.LowPart(1, shift)); + LowLevelILLabel zeroShift, nonZeroShift, wideShift, normalShift, done; + il.AddInstruction(il.If(il.CompareEqual(4, shiftAmount, il.Const(4, 0)), zeroShift, nonZeroShift)); + il.MarkLabel(zeroShift); + il.AddInstruction(il.Goto(done)); + il.MarkLabel(nonZeroShift); + il.AddInstruction(il.If(il.CompareUnsignedGreaterEqual(4, shiftAmount, il.Const(4, 32)), wideShift, normalShift)); + il.MarkLabel(wideShift); + il.AddInstruction(il.SetFlag(IL_FLAG_C, il.TestBit(4, source, il.Const(1, 31)))); + il.AddInstruction(il.Goto(done)); + il.MarkLabel(normalShift); + il.AddInstruction(il.SetFlag(IL_FLAG_C, il.TestBit(4, source, il.Sub(1, il.LowPart(1, shift), il.Const(1, 1))))); + il.MarkLabel(done); + il.AddInstruction(WriteILOperand(il, instr, 0, il.Register(4, LLIL_TEMP(0)))); + return; + } + + uint32_t shiftAmount = instr->fields[instr->format->operands[2].field0]; + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), value)); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(4, il.Register(4, LLIL_TEMP(0)), il.Const(4, 0)))); + il.AddInstruction(il.SetFlag(IL_FLAG_C, il.TestBit(4, source, il.Const(1, shiftAmount - 1)))); + il.AddInstruction(WriteILOperand(il, instr, 0, il.Register(4, LLIL_TEMP(0)))); +} + +static void WriteRorOperand(LowLevelILFunction& il, decomp_result* instr, bool writeFlags) +{ + ExprId source = ReadArithOperand(il, instr, 0); + ExprId shift = ReadArithOperand(il, instr, 1); + ExprId shiftAmount = il.And(4, shift, il.Const(4, 0xff)); + ExprId value = il.RotateRight(4, source, shiftAmount); + if (!writeFlags) + { + il.AddInstruction(WriteArithOperand(il, instr, value)); + return; + } + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), value)); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.CompareEqual(4, il.Register(4, LLIL_TEMP(0)), il.Const(4, 0)))); + + LowLevelILLabel zeroShift, setCarry, done; + il.AddInstruction(il.If(il.CompareEqual(4, shiftAmount, il.Const(4, 0)), zeroShift, setCarry)); + il.MarkLabel(zeroShift); + il.AddInstruction(il.Goto(done)); + il.MarkLabel(setCarry); + il.AddInstruction(il.SetFlag(IL_FLAG_C, + il.TestBit(4, source, + il.And(1, il.Sub(1, il.LowPart(1, shiftAmount), il.Const(1, 1)), il.Const(1, 0x1f))))); + il.MarkLabel(done); + il.AddInstruction(WriteILOperand(il, instr, 0, il.Register(4, LLIL_TEMP(0)))); +} + +static bool VectorMultiplyAccumulateIntrinsic(LowLevelILFunction& il, decomp_result* instr, uint32_t intrinsic) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize)) + return false; + if (IS_FIELD_PRESENT(instr, FIELD_floating_point) && instr->fields[FIELD_floating_point]) + return false; + if (instr->format->operandCount < 3) + return false; + + size_t destSize = GetRegisterSize(instr, 0); + size_t sourceSize = GetRegisterSize(instr, 1); + if (destSize == 0 || sourceSize == 0) + return false; + + uint32_t dest = GetRegisterOperand(instr, 0); + uint32_t source = GetRegisterOperand(instr, 1); + if (dest == armv7::REG_INVALID || source == armv7::REG_INVALID) + return false; + + const instruction_operand_format& source2Op = instr->format->operands[2]; + if (!IS_FIELD_PRESENT(instr, source2Op.field0)) + return false; + + uint32_t source2Reg = GetRegisterByIndex(instr->fields[source2Op.field0], source2Op.prefix); + uint32_t source2Size = RegisterSizeFromPrefix(source2Op.prefix); + uint32_t source2Index = 0xff; + if (source2Op.type == OPERAND_FORMAT_REG_INDEX) + { + if (!IS_FIELD_PRESENT(instr, source2Op.field1)) + return false; + source2Index = instr->fields[source2Op.field1]; + } + + std::vector inputs; + inputs.push_back(il.Const(1, instr->fields[FIELD_esize])); + if ((intrinsic == ARMV7_INTRIN_VMLAL) || (intrinsic == ARMV7_INTRIN_VMLSL)) + inputs.push_back(il.Const(1, + IS_FIELD_PRESENT(instr, FIELD_unsigned) && instr->fields[FIELD_unsigned] ? 1 : 0)); + inputs.push_back(il.Register(destSize, dest)); + inputs.push_back(il.Register(sourceSize, source)); + inputs.push_back(il.Register(source2Size, source2Reg)); + inputs.push_back(il.Const(1, source2Index)); + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + inputs)); + return true; +} + +static bool VectorMultiplyIntrinsic(LowLevelILFunction& il, decomp_result* instr) +{ + if (instr->format->operandCount < 3) + return false; + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + return false; + + size_t source1Size = GetRegisterSize(instr, 1); + size_t source2Size = GetRegisterSize(instr, 2); + if (source1Size == 0 || source2Size == 0) + return false; + + uint32_t elementSize = 0; + if (IS_FIELD_PRESENT(instr, FIELD_esize)) + elementSize = instr->fields[FIELD_esize]; + else if (IS_FIELD_PRESENT(instr, FIELD_size)) + elementSize = 8 << instr->fields[FIELD_size]; + else + return false; + + bool isUnsigned = IS_FIELD_PRESENT(instr, FIELD_unsigned) && instr->fields[FIELD_unsigned] != 0; + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + ARMV7_INTRIN_VMUL, + { + il.Const(1, elementSize), + il.Const(1, isUnsigned ? 1 : 0), + ReadILOperand(il, instr, 1, source1Size), + ReadILOperand(il, instr, 2, source2Size), + })); + return true; +} + +static bool VectorSaturatingDoublingMultiplyLongIntrinsic(LowLevelILFunction& il, decomp_result* instr) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize) || instr->format->operandCount < 3) + return false; + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + return false; + + size_t source1Size = GetRegisterSize(instr, 1); + size_t source2Size = GetRegisterSize(instr, 2); + if (source1Size == 0 || source2Size == 0) + return false; + + bool isUnsigned = IS_FIELD_PRESENT(instr, FIELD_unsigned) && instr->fields[FIELD_unsigned] != 0; + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + ARMV7_INTRIN_VQDMULL, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Const(1, isUnsigned ? 1 : 0), + ReadILOperand(il, instr, 1, source1Size), + ReadILOperand(il, instr, 2, source2Size), + })); + return true; +} + +static void VectorTableLookup(LowLevelILFunction& il, decomp_result* instr) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_length) || !IS_FIELD_PRESENT(instr, FIELD_n) + || !IS_FIELD_PRESENT(instr, FIELD_is_vtbl)) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + uint32_t indices = GetRegisterOperand(instr, 2); + if (dest == armv7::REG_INVALID || indices == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t length = instr->fields[FIELD_length]; + uint32_t tableStart = instr->fields[FIELD_n]; + std::vector inputs; + inputs.push_back(il.Const(1, length)); + for (uint32_t i = 0; i < 4; i++) + { + if (i < length) + inputs.push_back(il.Register(8, GetRegisterByIndex(tableStart + i, "d"))); + else + inputs.push_back(il.Const(8, 0)); + } + inputs.push_back(il.Register(8, indices)); + + bool isVtbl = instr->fields[FIELD_is_vtbl] != 0; + if (!isVtbl) + inputs.push_back(il.Register(8, dest)); + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + isVtbl ? ARMV7_INTRIN_VTBL : ARMV7_INTRIN_VTBX, + inputs)); +} + +static void VectorShiftLeft(LowLevelILFunction& il, decomp_result* instr) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize)) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + uint32_t source = GetRegisterOperand(instr, 1); + if (dest == armv7::REG_INVALID || source == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t regSize = GetRegisterSize(instr, 0); + size_t elementSize = instr->fields[FIELD_esize] / 8; + if (regSize == 0 || elementSize == 0 || elementSize > regSize || instr->format->operandCount < 3) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + if (instr->format->operands[2].type == OPERAND_FORMAT_IMM) + { + uint64_t shift = instr->fields[instr->format->operands[2].field0]; + if (elementSize == regSize) + { + il.AddInstruction(WriteILOperand(il, instr, 0, + il.ShiftLeft(regSize, il.Register(regSize, source), il.Const(1, shift)), regSize)); + return; + } + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + ARMV7_INTRIN_VSHL, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Const(1, (IS_FIELD_PRESENT(instr, FIELD_unsigned) && instr->fields[FIELD_unsigned]) ? 1 : 0), + ReadILOperand(il, instr, 1, regSize), + il.Const(regSize, shift), + })); + return; + } + + if (!IS_FIELD_PRESENT(instr, FIELD_unsigned)) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + ARMV7_INTRIN_VSHL, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Const(1, instr->fields[FIELD_unsigned] ? 1 : 0), + ReadILOperand(il, instr, 1, regSize), + ReadILOperand(il, instr, 2, regSize), + })); +} + +static void VectorShiftRight(LowLevelILFunction& il, decomp_result* instr) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize) || (!IS_FIELD_PRESENT(instr, FIELD_unsigned) && !IS_FIELD_PRESENT(instr, FIELD_type))) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID || GetRegisterOperand(instr, 1) == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t regSize = GetRegisterSize(instr, 0); + size_t elementSize = instr->fields[FIELD_esize] / 8; + if (regSize == 0 || elementSize == 0 || elementSize > regSize || instr->format->operandCount < 3) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint64_t shift = instr->fields[instr->format->operands[2].field0]; + bool isUnsigned = IS_FIELD_PRESENT(instr, FIELD_unsigned) + ? instr->fields[FIELD_unsigned] != 0 + : instr->fields[FIELD_type] != 2; + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + ARMV7_INTRIN_VSHR, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Const(1, isUnsigned ? 1 : 0), + ReadILOperand(il, instr, 1, regSize), + il.Const(regSize, shift), + })); +} + +static void VectorBitSelect(LowLevelILFunction& il, decomp_result* instr, uint32_t intrinsic) +{ + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID || instr->format->operandCount < 3) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t regSize = GetRegisterSize(instr, 0); + if (regSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + { + il.Register(regSize, dest), + ReadILOperand(il, instr, 1, regSize), + ReadILOperand(il, instr, 2, regSize), + })); +} + +static void RoundedVectorShift(LowLevelILFunction& il, decomp_result* instr, uint32_t intrinsic) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize) || instr->format->operandCount < 3) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t regSize = GetRegisterSize(instr, 0); + if (regSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + bool isUnsigned = IS_FIELD_PRESENT(instr, FIELD_unsigned) + ? instr->fields[FIELD_unsigned] != 0 + : IS_FIELD_PRESENT(instr, FIELD_type) && instr->fields[FIELD_type] != 2; + ExprId shift = instr->format->operands[2].type == OPERAND_FORMAT_IMM + ? il.Const(regSize, instr->fields[instr->format->operands[2].field0]) + : ReadILOperand(il, instr, 2, regSize); + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Const(1, isUnsigned ? 1 : 0), + ReadILOperand(il, instr, 1, regSize), + shift, + })); +} + +static void ShiftRightAccumulateOrInsert(LowLevelILFunction& il, decomp_result* instr, uint32_t intrinsic) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize) || instr->format->operandCount < 3) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t regSize = GetRegisterSize(instr, 0); + if (regSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + ExprId shift = instr->format->operands[2].type == OPERAND_FORMAT_IMM + ? il.Const(regSize, instr->fields[instr->format->operands[2].field0]) + : ReadILOperand(il, instr, 2, regSize); + + if (intrinsic == ARMV7_INTRIN_VSRA || intrinsic == ARMV7_INTRIN_VRSRA) + { + bool isUnsigned = IS_FIELD_PRESENT(instr, FIELD_unsigned) + ? instr->fields[FIELD_unsigned] != 0 + : IS_FIELD_PRESENT(instr, FIELD_type) && instr->fields[FIELD_type] != 2; + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Const(1, isUnsigned ? 1 : 0), + il.Register(regSize, dest), + ReadILOperand(il, instr, 1, regSize), + shift, + })); + return; + } + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Register(regSize, dest), + ReadILOperand(il, instr, 1, regSize), + shift, + })); +} + +static void VectorDuplicate(LowLevelILFunction& il, decomp_result* instr) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize) || instr->format->operandCount < 2) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + const instruction_operand_format& sourceOp = instr->format->operands[1]; + uint32_t source = armv7::REG_INVALID; + size_t sourceSize = 0; + uint32_t index = 0; + if (sourceOp.type == OPERAND_FORMAT_REG) + { + source = GetRegisterByIndex(instr->fields[sourceOp.field0]); + sourceSize = GetRegisterSize(instr, 1); + } + else if (sourceOp.type == OPERAND_FORMAT_REG_INDEX) + { + source = GetRegisterByIndex(instr->fields[sourceOp.field0], sourceOp.prefix); + sourceSize = RegisterSizeFromPrefix(sourceOp.prefix); + index = instr->fields[sourceOp.field1]; + } + + if (source == armv7::REG_INVALID || sourceSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + ARMV7_INTRIN_VDUP, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Register(sourceSize, source), + il.Const(1, index), + })); +} + +static void SaturatingVectorAdd(LowLevelILFunction& il, decomp_result* instr) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize) || instr->format->operandCount < 3) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t regSize = GetRegisterSize(instr, 0); + if (regSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + bool isUnsigned = IS_FIELD_PRESENT(instr, FIELD_unsigned) && instr->fields[FIELD_unsigned] != 0; + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + ARMV7_INTRIN_VQADD, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Const(1, isUnsigned ? 1 : 0), + ReadILOperand(il, instr, 1, regSize), + ReadILOperand(il, instr, 2, regSize), + })); +} + +static void VectorMaximumMinimum(LowLevelILFunction& il, decomp_result* instr, uint32_t intrinsic) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize) || instr->format->operandCount < 3) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t regSize = GetRegisterSize(instr, 0); + if (regSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + bool isUnsigned = IS_FIELD_PRESENT(instr, FIELD_unsigned) && instr->fields[FIELD_unsigned] != 0; + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Const(1, isUnsigned ? 1 : 0), + ReadILOperand(il, instr, 1, regSize), + ReadILOperand(il, instr, 2, regSize), + })); +} + +static void VectorReverse(LowLevelILFunction& il, decomp_result* instr, uint32_t intrinsic) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize) || instr->format->operandCount < 2) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t sourceSize = GetRegisterSize(instr, 1); + if (sourceSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + { + il.Const(1, instr->fields[FIELD_esize]), + ReadILOperand(il, instr, 1, sourceSize), + })); +} + +static void VectorExtract(LowLevelILFunction& il, decomp_result* instr) +{ + if (instr->format->operandCount < 4) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t source1Size = GetRegisterSize(instr, 1); + size_t source2Size = GetRegisterSize(instr, 2); + if (source1Size == 0 || source2Size == 0 || !IS_FIELD_PRESENT(instr, FIELD_imm)) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + ARMV7_INTRIN_VEXT, + { + il.Const(1, 8), + ReadILOperand(il, instr, 1, source1Size), + ReadILOperand(il, instr, 2, source2Size), + il.Const(1, instr->fields[FIELD_imm]), + })); +} + +static void VectorAbsoluteDifferenceAccumulate(LowLevelILFunction& il, decomp_result* instr, uint32_t intrinsic) +{ + if (instr->format->operandCount < 3) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t destSize = GetRegisterSize(instr, 0); + size_t source1Size = GetRegisterSize(instr, 1); + size_t source2Size = GetRegisterSize(instr, 2); + if (destSize == 0 || source1Size == 0 || source2Size == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t elementSize = 0; + if (IS_FIELD_PRESENT(instr, FIELD_size)) + elementSize = 8 << instr->fields[FIELD_size]; + else if (IS_FIELD_PRESENT(instr, FIELD_esize)) + elementSize = instr->fields[FIELD_esize]; + else + { + il.AddInstruction(il.Unimplemented()); + return; + } + + bool isUnsigned = IS_FIELD_PRESENT(instr, FIELD_unsigned) && instr->fields[FIELD_unsigned] != 0; + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + { + il.Const(1, elementSize), + il.Const(1, isUnsigned ? 1 : 0), + il.Register(destSize, dest), + ReadILOperand(il, instr, 1, source1Size), + ReadILOperand(il, instr, 2, source2Size), + })); +} + +static void VectorAbsoluteDifference(LowLevelILFunction& il, decomp_result* instr, uint32_t intrinsic) +{ + if (instr->format->operandCount < 3) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t source1Size = GetRegisterSize(instr, 1); + size_t source2Size = GetRegisterSize(instr, 2); + if (source1Size == 0 || source2Size == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t elementSize = 0; + if (IS_FIELD_PRESENT(instr, FIELD_size)) + elementSize = 8 << instr->fields[FIELD_size]; + else if (IS_FIELD_PRESENT(instr, FIELD_esize)) + elementSize = instr->fields[FIELD_esize]; + else + { + il.AddInstruction(il.Unimplemented()); + return; + } + + bool isUnsigned = IS_FIELD_PRESENT(instr, FIELD_unsigned) && instr->fields[FIELD_unsigned] != 0; + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + { + il.Const(1, elementSize), + il.Const(1, isUnsigned ? 1 : 0), + ReadILOperand(il, instr, 1, source1Size), + ReadILOperand(il, instr, 2, source2Size), + })); +} + +static void VectorWideningAdd(LowLevelILFunction& il, decomp_result* instr, uint32_t intrinsic) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize) || instr->format->operandCount < 3) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t source1Size = GetRegisterSize(instr, 1); + size_t source2Size = GetRegisterSize(instr, 2); + if (source1Size == 0 || source2Size == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + if (instr->format->operands[1].type == OPERAND_FORMAT_REG_FP && + strcmp(instr->format->operands[1].prefix, "q") == 0) + intrinsic = ARMV7_INTRIN_VADDW; + + bool isUnsigned = IS_FIELD_PRESENT(instr, FIELD_unsigned) && instr->fields[FIELD_unsigned] != 0; + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Const(1, isUnsigned ? 1 : 0), + ReadILOperand(il, instr, 1, source1Size), + ReadILOperand(il, instr, 2, source2Size), + })); +} + +static void VectorRoundingAddNarrow(LowLevelILFunction& il, decomp_result* instr) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize) || instr->format->operandCount < 3) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t source1Size = GetRegisterSize(instr, 1); + size_t source2Size = GetRegisterSize(instr, 2); + if (source1Size == 0 || source2Size == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + ARMV7_INTRIN_VRADDHN, + { + il.Const(1, instr->fields[FIELD_esize] * 2), + ReadILOperand(il, instr, 1, source1Size), + ReadILOperand(il, instr, 2, source2Size), + })); +} + +static void SaturatingVectorShiftLeft(LowLevelILFunction& il, decomp_result* instr, uint32_t intrinsic) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize)) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID || instr->format->operandCount < 3) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t regSize = GetRegisterSize(instr, 0); + bool sourceUnsigned = IS_FIELD_PRESENT(instr, FIELD_src_unsigned) + ? instr->fields[FIELD_src_unsigned] != 0 + : IS_FIELD_PRESENT(instr, FIELD_unsigned) && instr->fields[FIELD_unsigned] != 0; + bool destinationUnsigned = IS_FIELD_PRESENT(instr, FIELD_dest_unsigned) + ? instr->fields[FIELD_dest_unsigned] != 0 + : IS_FIELD_PRESENT(instr, FIELD_unsigned) && instr->fields[FIELD_unsigned] != 0; + ExprId shift = instr->format->operands[2].type == OPERAND_FORMAT_IMM + ? il.Const(regSize, instr->fields[instr->format->operands[2].field0]) + : ReadILOperand(il, instr, 2, regSize); + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Const(1, sourceUnsigned ? 1 : 0), + il.Const(1, destinationUnsigned ? 1 : 0), + ReadILOperand(il, instr, 1, regSize), + shift, + })); +} + +static void VectorShiftLeftLong(LowLevelILFunction& il, decomp_result* instr) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize) || instr->format->operandCount < 3) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t sourceSize = GetRegisterSize(instr, 1); + if (sourceSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + bool isUnsigned = IS_FIELD_PRESENT(instr, FIELD_unsigned) && instr->fields[FIELD_unsigned] != 0; + ExprId shift = instr->format->operands[2].type == OPERAND_FORMAT_IMM + ? il.Const(sourceSize, instr->fields[instr->format->operands[2].field0]) + : ReadILOperand(il, instr, 2, sourceSize); + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + ARMV7_INTRIN_VSHLL, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Const(1, isUnsigned ? 1 : 0), + ReadILOperand(il, instr, 1, sourceSize), + shift, + })); +} + +static void SaturatingVectorShiftRightNarrow(LowLevelILFunction& il, decomp_result* instr, uint32_t intrinsic) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize) || !IS_FIELD_PRESENT(instr, FIELD_src_unsigned) + || !IS_FIELD_PRESENT(instr, FIELD_dest_unsigned) || instr->format->operandCount < 3) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t sourceSize = GetRegisterSize(instr, 1); + if (sourceSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + ExprId shift = instr->format->operands[2].type == OPERAND_FORMAT_IMM + ? il.Const(sourceSize, instr->fields[instr->format->operands[2].field0]) + : ReadILOperand(il, instr, 2, sourceSize); + if (intrinsic == 0) + { + intrinsic = (instr->fields[FIELD_dest_unsigned] && !instr->fields[FIELD_src_unsigned]) + ? ARMV7_INTRIN_VQSHRUN + : ARMV7_INTRIN_VQSHRN; + } + if (intrinsic == static_cast(-1)) + { + intrinsic = (instr->fields[FIELD_dest_unsigned] && !instr->fields[FIELD_src_unsigned]) + ? ARMV7_INTRIN_VQRSHRUN + : ARMV7_INTRIN_VQRSHRN; + } + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + { + il.Const(1, instr->fields[FIELD_esize] * 2), + il.Const(1, instr->fields[FIELD_src_unsigned] ? 1 : 0), + il.Const(1, instr->fields[FIELD_dest_unsigned] ? 1 : 0), + ReadILOperand(il, instr, 1, sourceSize), + shift, + })); +} + +static void SaturatingVectorMoveNarrow(LowLevelILFunction& il, decomp_result* instr) +{ + if (!IS_FIELD_PRESENT(instr, FIELD_esize) || !IS_FIELD_PRESENT(instr, FIELD_src_unsigned) + || !IS_FIELD_PRESENT(instr, FIELD_dest_unsigned) || instr->format->operandCount < 2) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t dest = GetRegisterOperand(instr, 0); + if (dest == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t sourceSize = GetRegisterSize(instr, 1); + if (sourceSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t intrinsic = (instr->fields[FIELD_dest_unsigned] && !instr->fields[FIELD_src_unsigned]) + ? ARMV7_INTRIN_VQMOVUN + : ARMV7_INTRIN_VQMOVN; + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest) }, + intrinsic, + { + il.Const(1, instr->fields[FIELD_esize] * 2), + il.Const(1, instr->fields[FIELD_src_unsigned] ? 1 : 0), + il.Const(1, instr->fields[FIELD_dest_unsigned] ? 1 : 0), + ReadILOperand(il, instr, 1, sourceSize), + })); +} + +static void HalvingVectorAdd(LowLevelILFunction& il, decomp_result* instr) +{ + if (instr->format->operandCount < 3 || !IS_FIELD_PRESENT(instr, FIELD_esize)) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t regSize = GetRegisterSize(instr, 0); + size_t elementSize = instr->fields[FIELD_esize] / 8; + if (regSize == 0 || elementSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + uint32_t source1 = GetRegisterOperand(instr, 1); + uint32_t source2 = GetRegisterOperand(instr, 2); + if (source1 == armv7::REG_INVALID || source2 == armv7::REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_VHADD, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Const(1, IsSignedVectorElement(instr) ? 0 : 1), + il.Register(GetRegisterSize(instr, 1), source1), + il.Register(GetRegisterSize(instr, 2), source2), + })); +} + +static void VectorCompareEqual(LowLevelILFunction& il, decomp_result* instr) +{ + if (instr->format->operandCount < 3 || !IS_FIELD_PRESENT(instr, FIELD_esize)) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t regSize = GetRegisterSize(instr, 0); + size_t elementSize = instr->fields[FIELD_esize] / 8; + if (regSize == 0 || elementSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + ExprId rhs; + if (instr->format->operands[2].type == OPERAND_FORMAT_ZERO) + { + rhs = il.Const(regSize, 0); + } + else + { + size_t rhsSize = GetRegisterSize(instr, 2); + if (rhsSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + rhs = il.Register(rhsSize, GetRegisterOperand(instr, 2)); + } + + bool isFloat = instr->format->operationFlags & INSTR_FORMAT_FLAG_F32; + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_VCEQ, + { + il.Const(1, instr->fields[FIELD_esize]), + il.Const(1, isFloat ? 1 : 0), + il.Register(GetRegisterSize(instr, 1), GetRegisterOperand(instr, 1)), + rhs, + })); +} + +static void VectorCompareGreaterThan(LowLevelILFunction& il, decomp_result* instr) +{ + if (instr->format->operandCount < 3 || !IS_FIELD_PRESENT(instr, FIELD_esize)) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + size_t regSize = GetRegisterSize(instr, 0); + size_t elementSize = instr->fields[FIELD_esize] / 8; + if (regSize == 0 || elementSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + ExprId rhs; + if (instr->format->operands[2].type == OPERAND_FORMAT_ZERO) + { + rhs = il.Const(regSize, 0); + } + else + { + size_t rhsSize = GetRegisterSize(instr, 2); + if (rhsSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + rhs = il.Register(rhsSize, GetRegisterOperand(instr, 2)); + } + + bool isUnsigned = IS_FIELD_PRESENT(instr, FIELD_unsigned) && instr->fields[FIELD_unsigned] != 0; + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_VCGT, + { + il.Const(1, elementSize * 8), + il.Const(1, isUnsigned ? 1 : 0), + il.Register(GetRegisterSize(instr, 1), GetRegisterOperand(instr, 1)), + rhs, + })); +} + +static ExprId ReadSignedHalfwordOperand(LowLevelILFunction& il, decomp_result* instr, size_t operand, bool top) +{ + if (top) + return il.ArithShiftRight(4, ReadILOperand(il, instr, operand), il.Const(1, 16)); + return il.SignExtend(4, il.LowPart(2, ReadILOperand(il, instr, operand))); +} + +static void WriteSignedDualMultiplyOperand(LowLevelILFunction& il, decomp_result* instr, bool exchange, bool subtract) +{ + ExprId source1 = ReadILOperand(il, instr, 1); + ExprId source2 = ReadILOperand(il, instr, 2); + ExprId source2Top = il.ArithShiftRight(4, source2, il.Const(1, 16)); + ExprId source2Bottom = il.LowPart(2, source2); + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.ArithShiftRight(4, source1, il.Const(1, 16)), + exchange ? source2Bottom : source2Top))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.LowPart(2, source1), + exchange ? source2Top : source2Bottom))); + il.AddInstruction(WriteILOperand(il, instr, 0, + subtract + ? il.Sub(4, il.Register(4, LLIL_TEMP(1)), il.Register(4, LLIL_TEMP(0))) + : il.Add(4, il.Register(4, LLIL_TEMP(1)), il.Register(4, LLIL_TEMP(0))))); +} + +static void WriteSignedDualMultiplySubtractAccumulateOperand(LowLevelILFunction& il, decomp_result* instr, bool exchange) +{ + ExprId source1 = ReadILOperand(il, instr, 1); + ExprId source2 = ReadILOperand(il, instr, 2); + ExprId source2Top = il.ArithShiftRight(4, source2, il.Const(1, 16)); + ExprId source2Bottom = il.LowPart(2, source2); + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.ArithShiftRight(4, source1, il.Const(1, 16)), + exchange ? source2Bottom : source2Top))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.LowPart(2, source1), + exchange ? source2Top : source2Bottom))); + il.AddInstruction(WriteILOperand(il, instr, 0, + il.Add(4, + il.Sub(4, il.Register(4, LLIL_TEMP(1)), il.Register(4, LLIL_TEMP(0))), + ReadILOperand(il, instr, 3)))); +} + +static void WriteSignedDualMultiplySubtractLongOperand(LowLevelILFunction& il, decomp_result* instr, bool exchange) +{ + ExprId source1 = ReadILOperand(il, instr, 2); + ExprId source2 = ReadILOperand(il, instr, 3); + ExprId source2Top = il.ArithShiftRight(2, source2, il.Const(1, 16)); + ExprId source2Bottom = il.LowPart(2, source2); + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.LowPart(2, source1), + exchange ? source2Top : source2Bottom))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.ArithShiftRight(2, source1, il.Const(1, 16)), + exchange ? source2Bottom : source2Top))); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(2), + il.Add(8, + il.Or(8, + il.ShiftLeft(8, + ReadILOperand(il, instr, 1), + il.Const(1, 32)), + ReadILOperand(il, instr, 0)), + il.Sub(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(4, LLIL_TEMP(1)))))); + il.AddInstruction(WriteILOperand(il, instr, 0, + il.LowPart(4, + il.Register(8, LLIL_TEMP(2))))); + il.AddInstruction(WriteILOperand(il, instr, 1, + il.ArithShiftRight(4, + il.Register(8, LLIL_TEMP(2)), + il.Const(1, 32)))); +} + +static void WriteSignedLongHalfwordMultiplyAccumulateOperand(LowLevelILFunction& il, decomp_result* instr, bool nTop, bool mTop) +{ + ExprId source1 = nTop + ? il.ArithShiftRight(2, ReadILOperand(il, instr, 2), il.Const(1, 16)) + : il.LowPart(2, ReadILOperand(il, instr, 2)); + ExprId source2 = mTop + ? il.ArithShiftRight(2, ReadILOperand(il, instr, 3), il.Const(1, 16)) + : il.LowPart(2, ReadILOperand(il, instr, 3)); + + il.AddInstruction(il.SetRegisterSplit(4, GetRegisterOperand(instr, 1), GetRegisterOperand(instr, 0), + il.Add(8, + il.SignExtend(8, + il.Mult(4, source1, source2)), + il.RegisterSplit(4, + GetRegisterOperand(instr, 1), + GetRegisterOperand(instr, 0))))); +} + +static void WriteSignedWordHalfwordMultiplyOperand(LowLevelILFunction& il, decomp_result* instr, bool mTop, bool accumulate) +{ + ExprId product = il.Mult(accumulate ? 8 : 4, + ReadILOperand(il, instr, 1), + mTop + ? il.ArithShiftRight(2, ReadILOperand(il, instr, 2), il.Const(1, 16)) + : il.LowPart(2, ReadILOperand(il, instr, 2))); + + if (!accumulate) + { + il.AddInstruction(WriteILOperand(il, instr, 0, product)); + return; + } + + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + il.Add(8, + product, + il.ShiftLeft(8, + ReadILOperand(il, instr, 3), + il.Const(1, 16))))); + il.AddInstruction(WriteILOperand(il, instr, 0, + il.And(4, + il.ArithShiftRight(8, + il.Register(8, LLIL_TEMP(0)), + il.Const(1, 16)), + il.Const(4, 0xffffffff)))); +} + +static ExprId WriteSplitOperands(LowLevelILFunction& il, decomp_result *instr, size_t operandHi, size_t operandLo, ExprId value, + size_t size = 4, uint32_t flags = 0) +{ + uint32_t regHi = instr->fields[instr->format->operands[operandHi].field0]; + uint32_t regLo = instr->fields[instr->format->operands[operandLo].field0]; + + return il.SetRegisterSplit(size, GetRegisterByIndex(regHi), GetRegisterByIndex(regLo), value, flags); +} + +static void VfpLoadStoreMultiple(LowLevelILFunction& il, decomp_result* instr, bool load) +{ + const char* prefix = (IS_FIELD_PRESENT(instr, FIELD_single_regs) && instr->fields[FIELD_single_regs]) ? "s" : "d"; + size_t regSize = RegisterSizeFromPrefix(prefix); + uint32_t baseReg = GetRegisterOperand(instr, 0); + uint32_t d = instr->fields[FIELD_d]; + uint32_t inc = IS_FIELD_PRESENT(instr, FIELD_inc) ? instr->fields[FIELD_inc] : 1; + uint32_t regs = instr->fields[FIELD_regs]; + bool increment = IS_FIELD_PRESENT(instr, FIELD_add) ? instr->fields[FIELD_add] != 0 + : ((instr->mnem == armv7::ARMV7_VLDMIA) || (instr->mnem == armv7::ARMV7_VSTMIA)); + size_t totalSize = regs * regSize; + + ExprId base = il.Register(4, baseReg); + ExprId start = increment ? base : il.Sub(4, base, il.Const(4, totalSize)); + for (uint32_t i = 0; i < regs; ++i) + { + if (d + (i * inc) >= 32 && strcmp(prefix, "s") == 0) + break; + if (i >= 16 && strcmp(prefix, "d") == 0) + break; + + uint32_t reg = GetRegisterByIndex((d + i * inc) % 32, prefix); + ExprId address = i == 0 ? start : il.Add(4, start, il.Const(4, i * regSize)); + if (load) + il.AddInstruction(il.SetRegister(regSize, reg, il.Load(regSize, address))); + else + il.AddInstruction(il.Store(regSize, address, il.Register(regSize, reg))); + } + + if (IS_FIELD_PRESENT(instr, FIELD_wback) && instr->fields[FIELD_wback]) + { + ExprId value = increment ? il.Add(4, base, il.Const(4, totalSize)) : il.Sub(4, base, il.Const(4, totalSize)); + il.AddInstruction(il.SetRegister(4, baseReg, value)); + } +} + + +static bool HasWriteback(decomp_result* instr, size_t operand) +{ + switch (instr->format->operands[operand].writeback) + { + case WRITEBACK_YES: + return true; + case WRITEBACK_OPTIONAL: + return thumb_has_writeback(instr); + default: + return false; + } +} + +static bool HasNeonLoadStoreWriteback(decomp_result* instr, size_t operand) +{ + return HasWriteback(instr, operand) || (IS_FIELD_PRESENT(instr, FIELD_wback) && instr->fields[FIELD_wback]); +} + +static void StructuredVectorStoreIntrinsic(LowLevelILFunction& il, decomp_result* instr, uint32_t intrinsic, + size_t structureCount) +{ + ExprId base = GetMemoryAddress(il, instr, 1, 4, false); + ExprId sources[4] = {il.Const(8, 0), il.Const(8, 0), il.Const(8, 0), il.Const(8, 0)}; + size_t elementSize = instr->fields[FIELD_ebytes]; + unsigned int d = instr->fields[FIELD_d]; + unsigned int inc = IS_FIELD_PRESENT(instr, FIELD_inc) ? instr->fields[FIELD_inc] : 1; + bool indexed = instr->format->operands[0].type == OPERAND_FORMAT_REGISTERS_INDEXED; + size_t sourceRegCount = structureCount; + + if (instr->format->operands[0].type == OPERAND_FORMAT_REGISTERS) + { + if (IS_FIELD_PRESENT(instr, FIELD_regs)) + sourceRegCount = instr->fields[FIELD_regs]; + } + else if (!indexed) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + if ((structureCount == 4 && sourceRegCount != 4) || + (structureCount == 2 && sourceRegCount != 2 && sourceRegCount != 4) || elementSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } + + for (size_t i = 0; i < sourceRegCount && i < 4; ++i) + { + int regIdx = (d + i * inc) % 32; + sources[i] = il.Register(8, GetRegisterByIndex(regIdx, "d")); + } + + il.AddInstruction(il.Intrinsic({}, intrinsic, { + base, + il.Const(1, elementSize * 8), + il.Const(1, IS_FIELD_PRESENT(instr, FIELD_alignment) ? instr->fields[FIELD_alignment] : 0), + il.Const(1, indexed ? instr->fields[FIELD_index] : 0xff), + sources[0], + sources[1], + sources[2], + sources[3], + })); + + if (HasNeonLoadStoreWriteback(instr, 1)) + { + size_t totalSize = indexed ? structureCount * elementSize : sourceRegCount * 8; + uint32_t baseReg = GetRegisterByIndex(instr->fields[instr->format->operands[1].field0]); + if (IS_FIELD_PRESENT(instr, FIELD_register_index) && instr->fields[FIELD_register_index]) + { + uint32_t indexReg = GetRegisterByIndex(instr->fields[FIELD_m]); + il.AddInstruction(il.SetRegister(4, baseReg, + il.Add(4, il.Register(4, baseReg), il.Register(4, indexReg)))); + } + else + { + il.AddInstruction(il.SetRegister(4, baseReg, + il.Add(4, il.Register(4, baseReg), il.Const(4, totalSize)))); + } + } +} + +static void StructuredVectorLoadIntrinsic(LowLevelILFunction& il, decomp_result* instr, uint32_t intrinsic, + size_t structureCount) { - return WriteILOperand(il, instr, 0, value, size, flags); -} + ExprId base = GetMemoryAddress(il, instr, 1, 4, false); + std::vector outputs; + size_t elementSize = 0; + if (IS_FIELD_PRESENT(instr, FIELD_ebytes)) + elementSize = instr->fields[FIELD_ebytes]; + else if (IS_FIELD_PRESENT(instr, FIELD_size)) + elementSize = 1 << instr->fields[FIELD_size]; + unsigned int d = instr->fields[FIELD_d]; + unsigned int inc = IS_FIELD_PRESENT(instr, FIELD_inc) ? instr->fields[FIELD_inc] : 1; + bool indexed = instr->format->operands[0].type == OPERAND_FORMAT_REGISTERS_INDEXED; + size_t outputRegCount = structureCount; + if (instr->format->operands[0].type == OPERAND_FORMAT_REGISTERS) + { + if (IS_FIELD_PRESENT(instr, FIELD_regs_n)) + outputRegCount = instr->fields[FIELD_regs_n]; + else if (IS_FIELD_PRESENT(instr, FIELD_regs)) + outputRegCount = instr->fields[FIELD_regs]; + } + else if (!indexed) + { + il.AddInstruction(il.Unimplemented()); + return; + } -static ExprId WriteSplitOperands(LowLevelILFunction& il, decomp_result *instr, size_t operandHi, size_t operandLo, ExprId value, - size_t size = 4, uint32_t flags = 0) -{ - uint32_t regHi = instr->fields[instr->format->operands[operandHi].field0]; - uint32_t regLo = instr->fields[instr->format->operands[operandLo].field0]; + if ((structureCount == 4 && outputRegCount != 4) || + (structureCount == 2 && outputRegCount != 2 && outputRegCount != 4) || elementSize == 0) + { + il.AddInstruction(il.Unimplemented()); + return; + } - return il.SetRegisterSplit(size, GetRegisterByIndex(regHi), GetRegisterByIndex(regLo), value, flags); -} + for (size_t i = 0; i < outputRegCount && i < 4; ++i) + { + int regIdx = (d + i * inc) % 32; + outputs.push_back(RegisterOrFlag::Register(GetRegisterByIndex(regIdx, "d"))); + } + il.AddInstruction(il.Intrinsic(outputs, intrinsic, { + base, + il.Const(1, elementSize * 8), + il.Const(1, IS_FIELD_PRESENT(instr, FIELD_alignment) ? instr->fields[FIELD_alignment] : 0), + il.Const(1, indexed ? instr->fields[FIELD_index] : 0xff), + })); -static bool HasWriteback(decomp_result* instr, size_t operand) -{ - switch (instr->format->operands[operand].writeback) + if (HasNeonLoadStoreWriteback(instr, 1)) { - case WRITEBACK_YES: - return true; - case WRITEBACK_OPTIONAL: - return thumb_has_writeback(instr); - default: - return false; + size_t totalSize = indexed ? structureCount * elementSize : outputRegCount * 8; + uint32_t baseReg = GetRegisterByIndex(instr->fields[instr->format->operands[1].field0]); + bool registerIndex = IS_FIELD_PRESENT(instr, FIELD_register_index) && instr->fields[FIELD_register_index]; + if (!IS_FIELD_PRESENT(instr, FIELD_register_index) && IS_FIELD_PRESENT(instr, FIELD_Rm)) + registerIndex = instr->fields[FIELD_Rm] != 15 && instr->fields[FIELD_Rm] != 13; + if (registerIndex) + { + uint32_t indexReg = GetRegisterByIndex(IS_FIELD_PRESENT(instr, FIELD_m) + ? instr->fields[FIELD_m] : instr->fields[FIELD_Rm]); + il.AddInstruction(il.SetRegister(4, baseReg, + il.Add(4, il.Register(4, baseReg), il.Register(4, indexReg)))); + } + else + { + il.AddInstruction(il.SetRegister(4, baseReg, + il.Add(4, il.Register(4, baseReg), il.Const(4, totalSize)))); + } } } @@ -353,11 +2431,12 @@ static ExprId ShiftedRegister(LowLevelILFunction& il, decomp_result* instr, uint #define ReadRegisterA(il, instr, reg, align) ReadRegister(il, instr, reg, 4, "", align) static ExprId GetMemoryAddress(LowLevelILFunction& il, decomp_result* instr, size_t operand, uint32_t size, - bool canWriteback = true, uint32_t align=0) + bool canWriteback, uint32_t align) { uint32_t reg, second, t, n; switch (instr->format->operands[operand].type) { + case OPERAND_FORMAT_MEMORY_ONE_REG_ALIGNED: case OPERAND_FORMAT_MEMORY_ONE_REG: reg = GetRegisterByIndex(instr->fields[instr->format->operands[operand].field0]); return il.Register(4, reg); @@ -446,6 +2525,94 @@ static ExprId GetMemoryAddress(LowLevelILFunction& il, decomp_result* instr, siz } } +static void AddCoprocStoreIL(LowLevelILFunction& il, decomp_result* instr) +{ + const size_t memOperand = 2; + bool longTransfer = (instr->mnem == armv7::ARMV7_STCL) || (instr->mnem == armv7::ARMV7_STC2L); + ExprId address = GetMemoryAddress(il, instr, memOperand, 4, false); + + il.AddInstruction(il.Intrinsic({ }, + ARMV7_INTRIN_COPROC_STORE, + { + address, + il.Const(1, instr->fields[instr->format->operands[0].field0]), + il.Const(1, instr->fields[instr->format->operands[1].field0]), + il.Const(1, longTransfer ? 1 : 0), + })); + + if (HasWriteback(instr, memOperand)) + { + GetMemoryAddress(il, instr, memOperand, 4, true); + return; + } + + if ((instr->format->operandCount > 3) + && ((instr->format->operands[3].type == OPERAND_FORMAT_ADD_IMM) + || (instr->format->operands[3].type == OPERAND_FORMAT_OPTIONAL_ADD_IMM))) + { + uint32_t baseReg = GetRegisterByIndex(instr->fields[instr->format->operands[memOperand].field0]); + il.AddInstruction(il.SetRegister(4, baseReg, + il.Add(4, il.Register(4, baseReg), ReadILOperand(il, instr, 3)))); + return; + } + + if ((instr->format->operandCount > 3) + && (instr->format->operands[3].type == OPERAND_FORMAT_IMM) + && (strcmp(instr->format->operands[3].prefix, "#") == 0) + && IS_FIELD_PRESENT(instr, FIELD_imm32)) + { + uint32_t baseReg = GetRegisterByIndex(instr->fields[instr->format->operands[memOperand].field0]); + ExprId offset = il.Const(4, instr->fields[FIELD_imm32]); + ExprId value = instr->fields[FIELD_add] ? il.Add(4, il.Register(4, baseReg), offset) + : il.Sub(4, il.Register(4, baseReg), offset); + il.AddInstruction(il.SetRegister(4, baseReg, value)); + } +} + +static void AddCoprocLoadIL(LowLevelILFunction& il, decomp_result* instr) +{ + const size_t memOperand = 2; + bool longTransfer = (instr->mnem == armv7::ARMV7_LDCL) || (instr->mnem == armv7::ARMV7_LDC2L); + ExprId address = GetMemoryAddress(il, instr, memOperand, 4, false); + + il.AddInstruction(il.Intrinsic({ }, + ARMV7_INTRIN_COPROC_LOAD, + { + address, + il.Const(1, instr->fields[instr->format->operands[0].field0]), + il.Const(1, instr->fields[instr->format->operands[1].field0]), + il.Const(1, longTransfer ? 1 : 0), + })); + + if (HasWriteback(instr, memOperand)) + { + GetMemoryAddress(il, instr, memOperand, 4, true); + return; + } + + if ((instr->format->operandCount > 3) + && ((instr->format->operands[3].type == OPERAND_FORMAT_ADD_IMM) + || (instr->format->operands[3].type == OPERAND_FORMAT_OPTIONAL_ADD_IMM))) + { + uint32_t baseReg = GetRegisterByIndex(instr->fields[instr->format->operands[memOperand].field0]); + il.AddInstruction(il.SetRegister(4, baseReg, + il.Add(4, il.Register(4, baseReg), ReadILOperand(il, instr, 3)))); + return; + } + + if ((instr->format->operandCount > 3) + && (instr->format->operands[3].type == OPERAND_FORMAT_IMM) + && (strcmp(instr->format->operands[3].prefix, "#") == 0)) + { + uint32_t baseReg = GetRegisterByIndex(instr->fields[instr->format->operands[memOperand].field0]); + uint32_t offset = instr->fields[instr->format->operands[3].field0] << 2; + ExprId value = instr->fields[FIELD_add] + ? il.Add(4, il.Register(4, baseReg), il.Const(4, offset)) + : il.Sub(4, il.Register(4, baseReg), il.Const(4, offset)); + il.AddInstruction(il.SetRegister(4, baseReg, value)); + } +} + ExprId GetCondition(LowLevelILFunction& il, uint32_t cond) { @@ -615,14 +2782,10 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il switch (instr->mnem) { case armv7::ARMV7_ADC: - il.AddInstruction(WriteArithOperand(il, instr, - il.AddCarry(4, ReadArithOperand(il, instr, 0), ReadArithOperand(il, instr, 1), il.Flag(IL_FLAG_C), - WritesToStatus(instr, ifThenBlock) ? IL_FLAGWRITE_ALL : 0))); + WriteAddCarryOperand(il, instr, WritesToStatus(instr, ifThenBlock)); break; case armv7::ARMV7_ADCS: - il.AddInstruction(WriteArithOperand(il, instr, - il.AddCarry(4, ReadArithOperand(il, instr, 0), ReadArithOperand(il, instr, 1), il.Flag(IL_FLAG_C), - ifThenBlock ? 0 : IL_FLAGWRITE_ALL))); + WriteAddCarryOperand(il, instr, !ifThenBlock); break; case armv7::ARMV7_ADD: case armv7::ARMV7_ADDW: @@ -642,20 +2805,16 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il instr->format->operands[1].field0]) & (~3)))); break; case armv7::ARMV7_AND: - il.AddInstruction(WriteArithOperand(il, instr, il.And(4, ReadArithOperand(il, instr, 0), - ReadArithOperand(il, instr, 1), WritesToStatus(instr, ifThenBlock) ? IL_FLAGWRITE_ALL : 0))); + WriteLogicalOperand(il, instr, WritesToStatus(instr, ifThenBlock), false); break; case armv7::ARMV7_ANDS: - il.AddInstruction(WriteArithOperand(il, instr, il.And(4, ReadArithOperand(il, instr, 0), - ReadArithOperand(il, instr, 1), ifThenBlock ? 0 : IL_FLAGWRITE_ALL))); + WriteLogicalOperand(il, instr, !ifThenBlock, false); break; case armv7::ARMV7_ASR: - il.AddInstruction(WriteArithOperand(il, instr, il.ArithShiftRight(4, ReadArithOperand(il, instr, 0), - ReadArithOperand(il, instr, 1), WritesToStatus(instr, ifThenBlock) ? IL_FLAGWRITE_CNZ : 0))); + WriteAsrOperand(il, instr, WritesToStatus(instr, ifThenBlock)); break; case armv7::ARMV7_ASRS: - il.AddInstruction(WriteArithOperand(il, instr, il.ArithShiftRight(4, ReadArithOperand(il, instr, 0), - ReadArithOperand(il, instr, 1), ifThenBlock ? 0 : IL_FLAGWRITE_CNZ))); + WriteAsrOperand(il, instr, !ifThenBlock); break; case armv7::ARMV7_B: if ((!(instr->format->operationFlags & INSTR_FORMAT_FLAG_CONDITIONAL)) || @@ -707,12 +2866,10 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il break; } case armv7::ARMV7_BIC: - il.AddInstruction(WriteArithOperand(il, instr, il.And(4, ReadArithOperand(il, instr, 0), - il.Not(4, ReadArithOperand(il, instr, 1)), WritesToStatus(instr, ifThenBlock) ? IL_FLAGWRITE_ALL : 0))); + WriteBitClearOperand(il, instr, WritesToStatus(instr, ifThenBlock)); break; case armv7::ARMV7_BICS: - il.AddInstruction(WriteArithOperand(il, instr, il.And(4, ReadArithOperand(il, instr, 0), - il.Not(4, ReadArithOperand(il, instr, 1)), ifThenBlock ? 0 : IL_FLAGWRITE_ALL))); + WriteBitClearOperand(il, instr, !ifThenBlock); break; case armv7::ARMV7_BKPT: il.AddInstruction(il.Breakpoint()); @@ -721,6 +2878,7 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il case armv7::ARMV7_BLX: il.AddInstruction(il.Call(ReadILOperand(il, instr, 0))); break; + case armv7::ARMV7_BXJ: case armv7::ARMV7_BX: if ((instr->format->operands[0].type == OPERAND_FORMAT_LR) || (instr->fields[instr->format->operands[0].field0] == 14)) @@ -776,15 +2934,81 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il il.AddInstruction(WriteILOperand(il, instr, 0, il.Sub(4, il.Const(4, 32), il.Register(4, LLIL_TEMP(0))))); break; } + case armv7::ARMV7_CRC32B: + case armv7::ARMV7_CRC32CB: + case armv7::ARMV7_CRC32CH: + case armv7::ARMV7_CRC32CW: + case armv7::ARMV7_CRC32H: + case armv7::ARMV7_CRC32W: + { + size_t valueSize = GetCrc32ValueSize(instr->mnem); + ExprId value = ReadILOperand(il, instr, 2); + if (valueSize < 4) + value = il.LowPart(valueSize, value); + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + GetCrc32Intrinsic(instr->mnem), + { + ReadILOperand(il, instr, 1), + value, + })); + break; + } case armv7::ARMV7_CMP: il.AddInstruction(il.Sub(4, ReadILOperand(il, instr, 0), ReadArithOperand(il, instr, 1), IL_FLAGWRITE_ALL)); break; case armv7::ARMV7_CMN: il.AddInstruction(il.Add(4, ReadILOperand(il, instr, 0), ReadArithOperand(il, instr, 1), IL_FLAGWRITE_ALL)); break; + case armv7::ARMV7_CPS: + { + uint8_t iflags = 0; + if (IS_FIELD_PRESENT(instr, FIELD_affectA) && instr->fields[FIELD_affectA]) + iflags |= IFL_A; + if (IS_FIELD_PRESENT(instr, FIELD_affectI) && instr->fields[FIELD_affectI]) + iflags |= IFL_I; + if (IS_FIELD_PRESENT(instr, FIELD_affectF) && instr->fields[FIELD_affectF]) + iflags |= IFL_F; + + uint8_t mode = 0; + if (IS_FIELD_PRESENT(instr, FIELD_changemode) && instr->fields[FIELD_changemode] && IS_FIELD_PRESENT(instr, FIELD_mode)) + mode = instr->fields[FIELD_mode]; + + if (IS_FIELD_PRESENT(instr, FIELD_enable) && instr->fields[FIELD_enable]) + { + il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_CPSIE, {il.Const(1, iflags), il.Const(1, mode)})); + } + else if (IS_FIELD_PRESENT(instr, FIELD_disable) && instr->fields[FIELD_disable]) + { + il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_CPSID, {il.Const(1, iflags), il.Const(1, mode)})); + } + else + { + il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_CPS, {il.Const(1, mode)})); + } + break; + } + case armv7::ARMV7_SETEND: + if (IS_FIELD_PRESENT(instr, FIELD_E)) + il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_SETEND, {il.Const(1, instr->fields[FIELD_E])})); + else + il.AddInstruction(il.Unimplemented()); + break; + case armv7::ARMV7_CLREX: + il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_CLREX, {})); + break; + case armv7::ARMV7_PLD: + il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_PLD, {GetMemoryAddress(il, instr, 0, 4)})); + break; case armv7::ARMV7_DBG: il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_DBG, {il.Const(1, instr->fields[FIELD_option])})); break; + case armv7::ARMV7_HINT: + il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_HINT, {ReadILOperand(il, instr, 0, 1)})); + break; + case armv7::ARMV7_UNPREDICTABLE: + il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_UNPREDICTABLE, {})); + break; case armv7::ARMV7_DMB: switch (instr->fields[FIELD_barrier_option]) { @@ -850,12 +3074,10 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il } break; case armv7::ARMV7_EOR: - il.AddInstruction(WriteArithOperand(il, instr, il.Xor(4, ReadArithOperand(il, instr, 0), - ReadArithOperand(il, instr, 1), WritesToStatus(instr, ifThenBlock) ? IL_FLAGWRITE_ALL : 0))); + WriteLogicalOperand(il, instr, WritesToStatus(instr, ifThenBlock), true); break; case armv7::ARMV7_EORS: - il.AddInstruction(WriteArithOperand(il, instr, il.Xor(4, ReadArithOperand(il, instr, 0), - ReadArithOperand(il, instr, 1), ifThenBlock ? 0 : IL_FLAGWRITE_ALL))); + WriteLogicalOperand(il, instr, !ifThenBlock, true); break; case ARMV7_ISB: il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_ISB, {})); @@ -933,7 +3155,11 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il } case armv7::ARMV7_LDA: case armv7::ARMV7_LDR: + case armv7::ARMV7_LDAEX: case armv7::ARMV7_LDREX: + if (instr->mnem == armv7::ARMV7_LDAEX) + il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_SET_EXCLUSIVE_MONITORS, + { GetMemoryAddress(il, instr, 1, 4, false), il.Const(1, 4) })); if (instr->format->operandCount == 3) { uint32_t reg = GetRegisterByIndex(instr->fields[instr->format->operands[1].field0]); @@ -947,7 +3173,11 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il break; case armv7::ARMV7_LDAB: case armv7::ARMV7_LDRB: + case armv7::ARMV7_LDAEXB: case armv7::ARMV7_LDREXB: + if (instr->mnem == armv7::ARMV7_LDAEXB) + il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_SET_EXCLUSIVE_MONITORS, + { GetMemoryAddress(il, instr, 1, 4, false), il.Const(1, 4) })); if (instr->format->operandCount == 3) { uint32_t reg = GetRegisterByIndex(instr->fields[instr->format->operands[1].field0]); @@ -963,7 +3193,11 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il break; case armv7::ARMV7_LDAH: case armv7::ARMV7_LDRH: + case armv7::ARMV7_LDAEXH: case armv7::ARMV7_LDREXH: + if (instr->mnem == armv7::ARMV7_LDAEXH) + il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_SET_EXCLUSIVE_MONITORS, + { GetMemoryAddress(il, instr, 1, 4, false), il.Const(1, 4) })); if (instr->format->operandCount == 3) { uint32_t reg = GetRegisterByIndex(instr->fields[instr->format->operands[1].field0]); @@ -1048,6 +3282,32 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il il.AddInstruction(WriteArithOperand(il, instr, il.LogicalShiftRight(4, ReadArithOperand(il, instr, 0), ReadArithOperand(il, instr, 1), ifThenBlock ? 0 : IL_FLAGWRITE_CNZ))); break; + case armv7::ARMV7_STC: + case armv7::ARMV7_STC2: + case armv7::ARMV7_STCL: + case armv7::ARMV7_STC2L: + AddCoprocStoreIL(il, instr); + break; + case armv7::ARMV7_LDC: + case armv7::ARMV7_LDC2: + case armv7::ARMV7_LDCL: + case armv7::ARMV7_LDC2L: + AddCoprocLoadIL(il, instr); + break; + case armv7::ARMV7_CDP: + case armv7::ARMV7_CDP2: + il.AddInstruction(il.Intrinsic( + {}, + ARMV7_INTRIN_COPROC_DATAPROCESSING, + { + il.Const(1, instr->fields[instr->format->operands[0].field0]), + il.Const(1, instr->fields[instr->format->operands[1].field0]), + il.Const(1, instr->fields[instr->format->operands[2].field0]), + il.Const(1, instr->fields[instr->format->operands[3].field0]), + il.Const(1, instr->fields[instr->format->operands[4].field0]), + il.Const(1, instr->fields[instr->format->operands[5].field0]), + })); + break; case armv7::ARMV7_MCR: case armv7::ARMV7_MCR2: { @@ -1247,11 +3507,10 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il ReadArithOperand(il, instr, 1), ifThenBlock ? 0 : IL_FLAGWRITE_NZ))); break; case armv7::ARMV7_MVN: - il.AddInstruction(WriteILOperand(il, instr, 0, il.Not(4, ReadArithOperand(il, instr, 1), - WritesToStatus(instr, ifThenBlock) ? IL_FLAGWRITE_ALL : 0))); + WriteMoveNotOperand(il, instr, WritesToStatus(instr, ifThenBlock)); break; case armv7::ARMV7_MVNS: - il.AddInstruction(WriteILOperand(il, instr, 0, il.Not(4, ReadArithOperand(il, instr, 1), ifThenBlock ? 0 : IL_FLAGWRITE_ALL))); + WriteMoveNotOperand(il, instr, !ifThenBlock); break; case armv7::ARMV7_NOP: il.AddInstruction(il.Nop()); @@ -1261,12 +3520,46 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il il.Not(4, ReadArithOperand(il, instr, 1)), WritesToStatus(instr, ifThenBlock) ? IL_FLAGWRITE_ALL : 0))); break; case armv7::ARMV7_ORR: - il.AddInstruction(WriteArithOperand(il, instr, il.Or(4, ReadArithOperand(il, instr, 0), - ReadArithOperand(il, instr, 1), WritesToStatus(instr, ifThenBlock) ? IL_FLAGWRITE_ALL : 0))); + WriteOrOperand(il, instr, WritesToStatus(instr, ifThenBlock)); break; case armv7::ARMV7_ORRS: - il.AddInstruction(WriteArithOperand(il, instr, il.Or(4, ReadArithOperand(il, instr, 0), - ReadArithOperand(il, instr, 1), ifThenBlock ? 0 : IL_FLAGWRITE_ALL))); + WriteOrOperand(il, instr, !ifThenBlock); + break; + case armv7::ARMV7_PKHBT: + WritePackHalfwordOperand(il, instr, false); + break; + case armv7::ARMV7_PKHTB: + WritePackHalfwordOperand(il, instr, true); + break; + case armv7::ARMV7_QADD: + WriteSaturatingAddSubOperand(il, instr, false); + break; + case armv7::ARMV7_QADD16: + WriteSignedSaturatingParallelAddSubOperand(il, instr, 2, false); + break; + case armv7::ARMV7_QADD8: + WriteSignedSaturatingParallelAddSubOperand(il, instr, 1, false); + break; + case armv7::ARMV7_QDADD: + WriteSaturatingDoubleAddSubOperand(il, instr, false); + break; + case armv7::ARMV7_QDSUB: + WriteSaturatingDoubleAddSubOperand(il, instr, true); + break; + case armv7::ARMV7_QSAX: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_QSAX, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; + case armv7::ARMV7_QSUB: + WriteSaturatingAddSubOperand(il, instr, true); + break; + case armv7::ARMV7_QSUB16: + WriteSignedSaturatingParallelAddSubOperand(il, instr, 2, true); + break; + case armv7::ARMV7_QSUB8: + WriteSignedSaturatingParallelAddSubOperand(il, instr, 1, true); break; case armv7::ARMV7_POP: Pop(il, instr->fields[FIELD_registers]); @@ -1289,18 +3582,30 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il il.ShiftLeft(4, il.And(4, ReadILOperand(il, instr, 1), il.Const(4, 0xff)), il.Const(1, 24))))))); break; case armv7::ARMV7_REV16: - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), il.RotateRight(2, il.LowPart(2, ReadILOperand(il, instr, 1)), il.Const(1, 16)))); - il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), il.RotateRight(2, il.LogicalShiftRight(2, ReadILOperand(il, instr, 1), il.Const(1, 16)), il.Const(1, 16)))); - il.AddInstruction(WriteILOperand(il, instr, 0, il.Or(4, il.ShiftLeft(4, il.Register(2, LLIL_TEMP(1)), il.Const(1, 16)), il.Register(2, LLIL_TEMP(0))))); + { + auto value = [&]() { return ReadILOperand(il, instr, 1); }; + il.AddInstruction(WriteILOperand(il, instr, 0, + il.Or(4, + il.LogicalShiftRight(4, il.And(4, value(), il.Const(4, 0xff00ff00)), il.Const(1, 8)), + il.ShiftLeft(4, il.And(4, value(), il.Const(4, 0x00ff00ff)), il.Const(1, 8))))); + break; + } + case armv7::ARMV7_REVSH: + { + auto lowHalf = [&]() { return il.LowPart(2, ReadILOperand(il, instr, 1)); }; + il.AddInstruction(WriteILOperand(il, instr, 0, + il.SignExtend(4, + il.Or(2, + il.ShiftLeft(2, il.And(2, lowHalf(), il.Const(2, 0xff)), il.Const(1, 8)), + il.And(2, il.LogicalShiftRight(2, lowHalf(), il.Const(1, 8)), il.Const(2, 0xff)))))); + break; + } + case armv7::ARMV7_ROR: + WriteRorOperand(il, instr, WritesToStatus(instr, ifThenBlock)); + break; + case armv7::ARMV7_RORS: + WriteRorOperand(il, instr, !ifThenBlock); break; - case armv7::ARMV7_ROR: - il.AddInstruction(WriteArithOperand(il, instr, il.RotateRight(4, ReadArithOperand(il, instr, 0), - ReadArithOperand(il, instr, 1), WritesToStatus(instr, ifThenBlock) ? IL_FLAGWRITE_ALL : 0))); - break; - case armv7::ARMV7_RORS: - il.AddInstruction(WriteArithOperand(il, instr, il.RotateRight(4, ReadArithOperand(il, instr, 0), - ReadArithOperand(il, instr, 1), ifThenBlock ? 0 : IL_FLAGWRITE_ALL))); - break; case armv7::ARMV7_RSB: il.AddInstruction(WriteArithOperand(il, instr, il.Sub(4, ReadArithOperand(il, instr, 1), ReadArithOperand(il, instr, 0), WritesToStatus(instr, ifThenBlock) ? IL_FLAGWRITE_ALL : 0))); @@ -1309,6 +3614,96 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il il.AddInstruction(WriteArithOperand(il, instr, il.Sub(4, ReadArithOperand(il, instr, 1), ReadArithOperand(il, instr, 0), ifThenBlock ? 0 : IL_FLAGWRITE_ALL))); break; + case armv7::ARMV7_SASX: + WriteSignedParallelExchangeOperand(il, instr, false); + break; + case armv7::ARMV7_SADD16: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_SADD16, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; + case armv7::ARMV7_SADD8: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_SADD8, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; + case armv7::ARMV7_SHADD16: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_SHADD16, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; + case armv7::ARMV7_SHADD8: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_SHADD8, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; + case armv7::ARMV7_SHASX: + WriteSignedHalvingParallelExchangeOperand(il, instr, false); + break; + case armv7::ARMV7_SSAX: + WriteSignedParallelExchangeOperand(il, instr, true); + break; + case armv7::ARMV7_SSUB16: + WriteSignedParallelAddSubOperand(il, instr, 2, true); + break; + case armv7::ARMV7_SSUB8: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_SSUB8, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; + case armv7::ARMV7_SHSUB16: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_SHSUB16, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; + case armv7::ARMV7_SHSUB8: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_SHSUB8, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; + case armv7::ARMV7_UASX: + WriteUnsignedParallelExchangeOperand(il, instr, false); + break; + case armv7::ARMV7_UHASX: + WriteUnsignedHalvingParallelExchangeOperand(il, instr, false); + break; + case armv7::ARMV7_UQADD16: + WriteUnsignedSaturatingParallelAddSubOperand(il, instr, 2, false); + break; + case armv7::ARMV7_UQADD8: + WriteUnsignedSaturatingParallelAddSubOperand(il, instr, 1, false); + break; + case armv7::ARMV7_UQASX: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_UQASX, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; + case armv7::ARMV7_UHADD16: + WriteUnsignedHalvingParallelAddOperand(il, instr, 2); + break; + case armv7::ARMV7_UHADD8: + WriteUnsignedHalvingParallelAddOperand(il, instr, 1); + break; + case armv7::ARMV7_UHSUB16: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_UHSUB16, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; + case armv7::ARMV7_UHSUB8: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_UHSUB8, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; case armv7::ARMV7_UADD8: { uint32_t c = GetRegisterByIndex(instr->fields[instr->format->operands[0].field0]); @@ -1333,17 +3728,17 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il il.Or(4, il.Or(4, il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(3)), + il.ZeroExtend(4, il.Register(1, LLIL_TEMP(3))), il.Const(1, 24) ), il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(2)), + il.ZeroExtend(4, il.Register(1, LLIL_TEMP(2))), il.Const(1, 16) ) ), il.Or(4, il.ShiftLeft(4, - il.Register(1, LLIL_TEMP(1)), + il.ZeroExtend(4, il.Register(1, LLIL_TEMP(1))), il.Const(1, 8) ), il.Register(1, LLIL_TEMP(0)) @@ -1379,6 +3774,45 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il ); break; } + case armv7::ARMV7_USAX: + WriteUnsignedParallelExchangeOperand(il, instr, true); + break; + case armv7::ARMV7_UQSUB16: + WriteUnsignedSaturatingParallelAddSubOperand(il, instr, 2, true); + break; + case armv7::ARMV7_UQSUB8: + WriteUnsignedSaturatingParallelAddSubOperand(il, instr, 1, true); + break; + case armv7::ARMV7_UQSAX: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_UQSAX, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; + case armv7::ARMV7_USAD8: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_USAD8, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; + case armv7::ARMV7_USADA8: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_USADA8, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2), ReadILOperand(il, instr, 3) })); + break; + case armv7::ARMV7_USUB16: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_USUB16, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; + case armv7::ARMV7_USUB8: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_USUB8, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; case armv7::ARMV7_UDIV: il.AddInstruction(WriteArithOperand(il, instr, il.DivUnsigned(4, ReadArithOperand(il, instr, 0), ReadArithOperand(il, instr, 1)))); break; @@ -1425,6 +3859,9 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il case ARMV7_SEV: il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_SEV, {})); break; + case ARMV7_YIELD: + il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_YIELD, {})); + break; case ARMV7_STM: case ARMV7_STMIA: case ARMV7_STMDB: @@ -1498,8 +3935,57 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il il.AddInstruction(il.Jump(ReadRegister(il, instr, armv7::REG_PC, 4))); break; } + case armv7::ARMV7_STLEX: + case armv7::ARMV7_STLEXB: + case armv7::ARMV7_STLEXH: + case armv7::ARMV7_STREX: + case armv7::ARMV7_STREXB: + case armv7::ARMV7_STREXH: + { + size_t storeSize = 4; + if (instr->mnem == armv7::ARMV7_STLEXB || instr->mnem == armv7::ARMV7_STREXB) + storeSize = 1; + else if (instr->mnem == armv7::ARMV7_STLEXH || instr->mnem == armv7::ARMV7_STREXH) + storeSize = 2; + + ExprId address = GetMemoryAddress(il, instr, 2, 4); + LowLevelILLabel trueCode, falseCode; + uint32_t statusReg = GetRegisterOperand(instr, 0); + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(statusReg) }, + ARMV7_INTRIN_EXCLUSIVE_MONITORS_PASS, + { address, il.Const(1, 4) })); + il.AddInstruction(il.If(il.CompareEqual(4, il.Register(4, statusReg), il.Const(4, 1)), trueCode, falseCode)); + il.MarkLabel(trueCode); + ExprId value = ReadILOperand(il, instr, 1); + if (storeSize < 4) + value = il.LowPart(storeSize, value); + il.AddInstruction(il.Store(storeSize, address, value)); + il.MarkLabel(falseCode); + break; + } + case armv7::ARMV7_STLEXD: + case armv7::ARMV7_STREXD: + { + ExprId address = GetMemoryAddress(il, instr, 3, 4); + LowLevelILLabel trueCode, falseCode; + uint32_t statusReg = GetRegisterOperand(instr, 0); + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(statusReg) }, + ARMV7_INTRIN_EXCLUSIVE_MONITORS_PASS, + { address, il.Const(1, 8) })); + il.AddInstruction(il.If(il.CompareEqual(4, il.Register(4, statusReg), il.Const(4, 1)), trueCode, falseCode)); + il.MarkLabel(trueCode); + + ExprId value = arch->GetEndianness() == LittleEndian + ? il.RegisterSplit(4, GetRegisterOperand(instr, 2), GetRegisterOperand(instr, 1)) + : il.RegisterSplit(4, GetRegisterOperand(instr, 1), GetRegisterOperand(instr, 2)); + il.AddInstruction(il.Store(8, address, value)); + + il.MarkLabel(falseCode); + break; + } case armv7::ARMV7_STL: case armv7::ARMV7_STR: + case armv7::ARMV7_STRT: // case armv7::ARMV7_STREX: if (instr->format->operandCount == 3) { @@ -1512,8 +3998,71 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il il.AddInstruction(il.Store(4, GetMemoryAddress(il, instr, 1, 4), ReadILOperand(il, instr, 0))); } break; + case armv7::ARMV7_SRS: + case armv7::ARMV7_SRSDA: + case armv7::ARMV7_SRSDB: + case armv7::ARMV7_SRSIA: + case armv7::ARMV7_SRSIB: + { + bool increment = false; + bool wordhigher = false; + if (IS_FIELD_PRESENT(instr, FIELD_increment)) + increment = instr->fields[FIELD_increment] != 0; + else if (IS_FIELD_PRESENT(instr, FIELD_inc)) + increment = instr->fields[FIELD_inc] != 0; + else + increment = (instr->mnem == armv7::ARMV7_SRSIA) || (instr->mnem == armv7::ARMV7_SRSIB); + + if (IS_FIELD_PRESENT(instr, FIELD_wordhigher)) + wordhigher = instr->fields[FIELD_wordhigher] != 0; + else + wordhigher = (instr->mnem == armv7::ARMV7_SRSDA) || (instr->mnem == armv7::ARMV7_SRSIB); + + il.AddInstruction(il.Intrinsic( + {}, + ARMV7_INTRIN_SRS, + { + il.Const(1, instr->fields[FIELD_mode]), + il.Const(1, increment ? 1 : 0), + il.Const(1, wordhigher ? 1 : 0), + il.Const(1, (IS_FIELD_PRESENT(instr, FIELD_wback) && instr->fields[FIELD_wback]) ? 1 : 0), + })); + break; + } + case armv7::ARMV7_RFE: + case armv7::ARMV7_RFEDA: + case armv7::ARMV7_RFEDB: + case armv7::ARMV7_RFEIA: + case armv7::ARMV7_RFEIB: + { + bool increment = false; + bool wordhigher = false; + if (IS_FIELD_PRESENT(instr, FIELD_increment)) + increment = instr->fields[FIELD_increment] != 0; + else if (IS_FIELD_PRESENT(instr, FIELD_inc)) + increment = instr->fields[FIELD_inc] != 0; + else + increment = (instr->mnem == armv7::ARMV7_RFEIA) || (instr->mnem == armv7::ARMV7_RFEIB); + + if (IS_FIELD_PRESENT(instr, FIELD_wordhigher)) + wordhigher = instr->fields[FIELD_wordhigher] != 0; + else + wordhigher = (instr->mnem == armv7::ARMV7_RFEDA) || (instr->mnem == armv7::ARMV7_RFEIB); + + il.AddInstruction(il.Intrinsic( + {}, + ARMV7_INTRIN_RFE, + { + ReadILOperand(il, instr, 0), + il.Const(1, increment ? 1 : 0), + il.Const(1, wordhigher ? 1 : 0), + il.Const(1, (IS_FIELD_PRESENT(instr, FIELD_wback) && instr->fields[FIELD_wback]) ? 1 : 0), + })); + break; + } case armv7::ARMV7_STLB: case armv7::ARMV7_STRB: + case armv7::ARMV7_STRBT: // case armv7::ARMV7_STREXB: if (instr->format->operandCount == 3) { @@ -1528,6 +4077,7 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il break; case armv7::ARMV7_STLH: case armv7::ARMV7_STRH: + case armv7::ARMV7_STRHT: // case armv7::ARMV7_STREXH: if (instr->format->operandCount == 3) { @@ -1581,15 +4131,31 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il il.AddInstruction(il.SetRegister(4, FAKEREG_SYSCALL_INFO, il.Const(4, instr->fields[instr->format->operands[0].field0]))); il.AddInstruction(il.SystemCall()); break; + case armv7::ARMV7_SMC: + il.AddInstruction(il.Intrinsic({}, ARMV7_INTRIN_SMC, + {il.Const(1, instr->fields[instr->format->operands[0].field0])})); + break; case armv7::ARMV7_SXTAB: il.AddInstruction(WriteArithOperand(il, instr, il.Add(4, ReadILOperand(il, instr, 1), il.SignExtend(4, il.LowPart(1, ReadRotatedOperand(il, instr, 2)))))); break; + case armv7::ARMV7_SXTAB16: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_SXTAB16, + { ReadILOperand(il, instr, 1), ReadRotatedOperand(il, instr, 2) })); + break; case armv7::ARMV7_SXTAH: il.AddInstruction(WriteArithOperand(il, instr, il.Add(4, ReadILOperand(il, instr, 1), il.SignExtend(4, il.LowPart(2, ReadRotatedOperand(il, instr, 2)))))); break; case armv7::ARMV7_SXTB: il.AddInstruction(WriteArithOperand(il, instr, il.SignExtend(4, il.LowPart(1, ReadRotatedOperand(il, instr, 1))))); break; + case armv7::ARMV7_SXTB16: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_SXTB16, + { ReadRotatedOperand(il, instr, 1) })); + break; case armv7::ARMV7_SXTH: il.AddInstruction(WriteArithOperand(il, instr, il.SignExtend(4, il.LowPart(2, ReadRotatedOperand(il, instr, 1))))); break; @@ -1602,10 +4168,34 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il il.ZeroExtend(4, il.Load(2, GetMemoryAddress(il, instr, 0, 4, false))))))); break; case armv7::ARMV7_TEQ: - il.AddInstruction(il.Xor(4, ReadILOperand(il, instr, 0), ReadArithOperand(il, instr, 1), IL_FLAGWRITE_CNZ)); + WriteTestEquivalenceOperand(il, instr); break; case armv7::ARMV7_TST: - il.AddInstruction(il.And(4, ReadILOperand(il, instr, 0), ReadArithOperand(il, instr, 1), IL_FLAGWRITE_CNZ)); + WriteTestOperand(il, instr); + break; + case armv7::ARMV7_SSAT: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_SSAT, + { ReadILOperand(il, instr, 1), ReadShiftedOperand(il, instr, 2) })); + break; + case armv7::ARMV7_SSAT16: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_SSAT16, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; + case armv7::ARMV7_USAT: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_USAT, + { ReadILOperand(il, instr, 1), ReadShiftedOperand(il, instr, 2) })); + break; + case armv7::ARMV7_USAT16: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_USAT16, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); break; case armv7::ARMV7_UBFX: il.AddInstruction(WriteILOperand(il, instr, 0, il.And(4, il.LogicalShiftRight(4, ReadILOperand(il, instr, 1), @@ -1615,6 +4205,27 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il case armv7::ARMV7_UDF: il.AddInstruction(il.Trap(instr->fields[instr->format->operands[0].field0])); break; + case armv7::ARMV7_UMAAL: + { + uint32_t RdLo = GetRegisterByIndex(instr->fields[instr->format->operands[0].field0]); + uint32_t RdHi = GetRegisterByIndex(instr->fields[instr->format->operands[1].field0]); + uint32_t Rm = GetRegisterByIndex(instr->fields[instr->format->operands[2].field0]); + uint32_t Rn = GetRegisterByIndex(instr->fields[instr->format->operands[3].field0]); + + il.AddInstruction( + il.SetRegisterSplit(4, + RdHi, /* hi result */ + RdLo, /* lo result */ + il.Add(8, + il.MultDoublePrecUnsigned(4, il.Register(4, Rn), il.Register(4, Rm)), + il.Add(8, + il.ZeroExtend(8, il.Register(4, RdHi)), + il.ZeroExtend(8, il.Register(4, RdLo))) + ) + ) + ); + break; + } case armv7::ARMV7_UMLAL: { uint32_t RdLo = GetRegisterByIndex(instr->fields[instr->format->operands[0].field0]); @@ -1641,6 +4252,111 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il case armv7::ARMV7_SMULL: il.AddInstruction(WriteSplitOperands(il, instr, 1, 0, il.MultDoublePrecSigned(4, ReadILOperand(il, instr, 2), ReadILOperand(il, instr, 3)))); break; + case armv7::ARMV7_SMLAD: + case armv7::ARMV7_SMLADX: + { + bool exchange = instr->mnem == armv7::ARMV7_SMLADX; + ExprId productLo = il.Mult(4, + ReadSignedHalfwordOperand(il, instr, 1, false), + ReadSignedHalfwordOperand(il, instr, 2, exchange)); + ExprId productHi = il.Mult(4, + ReadSignedHalfwordOperand(il, instr, 1, true), + ReadSignedHalfwordOperand(il, instr, 2, !exchange)); + il.AddInstruction(WriteILOperand(il, instr, 0, + il.Add(4, + ReadILOperand(il, instr, 3), + il.Add(4, productLo, productHi)))); + break; + } + case armv7::ARMV7_SMUAD: + WriteSignedDualMultiplyOperand(il, instr, false, false); + break; + case armv7::ARMV7_SMUADX: + WriteSignedDualMultiplyOperand(il, instr, true, false); + break; + case armv7::ARMV7_SMUSD: + WriteSignedDualMultiplyOperand(il, instr, false, true); + break; + case armv7::ARMV7_SMUSDX: + WriteSignedDualMultiplyOperand(il, instr, true, true); + break; + case armv7::ARMV7_SMLSD: + WriteSignedDualMultiplySubtractAccumulateOperand(il, instr, false); + break; + case armv7::ARMV7_SMLSDX: + WriteSignedDualMultiplySubtractAccumulateOperand(il, instr, true); + break; + case armv7::ARMV7_SMLSLD: + WriteSignedDualMultiplySubtractLongOperand(il, instr, false); + break; + case armv7::ARMV7_SMLSLDX: + WriteSignedDualMultiplySubtractLongOperand(il, instr, true); + break; + case armv7::ARMV7_SMLALBB: + WriteSignedLongHalfwordMultiplyAccumulateOperand(il, instr, false, false); + break; + case armv7::ARMV7_SMLALBT: + WriteSignedLongHalfwordMultiplyAccumulateOperand(il, instr, false, true); + break; + case armv7::ARMV7_SMLALTB: + WriteSignedLongHalfwordMultiplyAccumulateOperand(il, instr, true, false); + break; + case armv7::ARMV7_SMLALTT: + WriteSignedLongHalfwordMultiplyAccumulateOperand(il, instr, true, true); + break; + case armv7::ARMV7_SMLAWB: + WriteSignedWordHalfwordMultiplyOperand(il, instr, false, true); + break; + case armv7::ARMV7_SMLAWT: + WriteSignedWordHalfwordMultiplyOperand(il, instr, true, true); + break; + case armv7::ARMV7_SMULWB: + WriteSignedWordHalfwordMultiplyOperand(il, instr, false, false); + break; + case armv7::ARMV7_SMULWT: + WriteSignedWordHalfwordMultiplyOperand(il, instr, true, false); + break; + case armv7::ARMV7_SMLAL: + il.AddInstruction(WriteSplitOperands(il, instr, 1, 0, + il.Add(8, + il.MultDoublePrecSigned(4, ReadILOperand(il, instr, 2), ReadILOperand(il, instr, 3)), + il.RegisterSplit(4, + GetRegisterOperand(instr, 1), + GetRegisterOperand(instr, 0))))); + break; + case armv7::ARMV7_SMLALD: + case armv7::ARMV7_SMLALDX: + { + bool exchange = instr->mnem == armv7::ARMV7_SMLALDX; + ExprId productLo = il.Mult(4, + ReadSignedHalfwordOperand(il, instr, 2, false), + ReadSignedHalfwordOperand(il, instr, 3, exchange)); + ExprId productHi = il.Mult(4, + ReadSignedHalfwordOperand(il, instr, 2, true), + ReadSignedHalfwordOperand(il, instr, 3, !exchange)); + il.AddInstruction(WriteSplitOperands(il, instr, 1, 0, + il.Add(8, + il.RegisterSplit(4, + GetRegisterOperand(instr, 1), + GetRegisterOperand(instr, 0)), + il.SignExtend(8, il.Add(4, productLo, productHi))))); + break; + } + case armv7::ARMV7_SMLABB: + case armv7::ARMV7_SMLABT: + case armv7::ARMV7_SMLATB: + case armv7::ARMV7_SMLATT: + { + bool nTop = (instr->mnem == armv7::ARMV7_SMLATB) || (instr->mnem == armv7::ARMV7_SMLATT); + bool mTop = (instr->mnem == armv7::ARMV7_SMLABT) || (instr->mnem == armv7::ARMV7_SMLATT); + il.AddInstruction(WriteArithOperand(il, instr, + il.Add(4, + il.Mult(4, + ReadSignedHalfwordOperand(il, instr, 1, nTop), + ReadSignedHalfwordOperand(il, instr, 2, mTop)), + ReadILOperand(il, instr, 3)))); + break; + } case armv7::ARMV7_SMULBB: il.AddInstruction(WriteArithOperand(il, instr, il.Mult(4, il.LowPart(2, ReadILOperand(il, instr, 1)), il.LowPart(2, ReadILOperand(il, instr, 2)), IL_FLAGWRITE_NONE))); @@ -1657,12 +4373,47 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il il.AddInstruction(WriteArithOperand(il, instr, il.Mult(4, il.LowPart(2, il.LogicalShiftRight(4, ReadILOperand(il, instr, 1), il.Const(1, 16))), il.LowPart(2, il.LogicalShiftRight(4, ReadILOperand(il, instr, 2), il.Const(1, 16))), IL_FLAGWRITE_NONE))); break; + case armv7::ARMV7_SMMUL: + il.AddInstruction(WriteILOperand(il, instr, 0, + il.LowPart(4, + il.ArithShiftRight(8, + il.MultDoublePrecSigned(4, ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2)), + il.Const(1, 32))))); + break; + case armv7::ARMV7_SMMLA: + case armv7::ARMV7_SMMLAR: + { + ExprId product = il.MultDoublePrecSigned(4, ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2)); + if (instr->mnem == armv7::ARMV7_SMMLAR) + product = il.Add(8, product, il.Const(8, 0x80000000)); + ExprId high = il.LowPart(4, il.ArithShiftRight(8, product, il.Const(1, 32))); + il.AddInstruction(WriteILOperand(il, instr, 0, il.Add(4, high, ReadILOperand(il, instr, 3)))); + break; + } + case armv7::ARMV7_SMMLS: + case armv7::ARMV7_SMMLSR: + { + ExprId difference = il.Sub(8, + il.ShiftLeft(8, ReadILOperand(il, instr, 3), il.Const(1, 32)), + il.MultDoublePrecSigned(4, ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2))); + if (instr->mnem == armv7::ARMV7_SMMLSR) + difference = il.Add(8, difference, il.Const(8, 0x80000000)); + il.AddInstruction(WriteILOperand(il, instr, 0, + il.LowPart(4, il.ArithShiftRight(8, difference, il.Const(1, 32))))); + break; + } case armv7::ARMV7_UXTAB: il.AddInstruction(WriteArithOperand(il, instr, il.Add(4, ReadILOperand(il, instr, 1), il.ZeroExtend(4, il.LowPart(1, ReadRotatedOperand(il, instr, 2)))))); break; + case armv7::ARMV7_UXTAB16: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_UXTAB16, + { ReadILOperand(il, instr, 1), ReadRotatedOperand(il, instr, 2) })); + break; case armv7::ARMV7_UXTAH: il.AddInstruction(WriteArithOperand(il, instr, il.Add(4, @@ -1672,6 +4423,12 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il case armv7::ARMV7_UXTB: il.AddInstruction(WriteArithOperand(il, instr, il.ZeroExtend(4, il.LowPart(1, ReadRotatedOperand(il, instr, 1))))); break; + case armv7::ARMV7_UXTB16: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_UXTB16, + { ReadRotatedOperand(il, instr, 1) })); + break; case armv7::ARMV7_UXTH: il.AddInstruction(WriteArithOperand(il, instr, il.ZeroExtend(4, il.LowPart(2, ReadRotatedOperand(il, instr, 1))))); break; @@ -1684,6 +4441,12 @@ bool GetLowLevelILForThumbInstruction(Architecture* arch, LowLevelILFunction& il case ARMV7_RRX: il.AddInstruction(WriteILOperand(il, instr, 0, ReadShiftedOperand(il, instr, 1))); break; + case ARMV7_SEL: + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_SEL, + { ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2) })); + break; default: GetLowLevelILForNEONInstruction(arch, il, instr, ifThenBlock); break; @@ -1705,7 +4468,6 @@ bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il, } else { - // Non scalar unsupported. il.AddInstruction(il.Unimplemented()); } break; @@ -1717,35 +4479,118 @@ bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il, } else { - // Non scalar unsupported. - il.AddInstruction(il.Unimplemented()); + size_t size = GetRegisterSize(instr, 0); + il.AddInstruction(WriteArithOperand(il, instr, + il.Add(size, ReadILOperand(il, instr, 1, size), ReadILOperand(il, instr, 2, size)), size)); } break; case armv7::ARMV7_VBIF: - il.AddInstruction(WriteArithOperand(il, instr, - il.Or(GetRegisterSize(instr, 0), - il.And(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 0), ReadILOperand(il, instr, 2)), - il.And(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 1), - il.Not(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 2)))))); + VectorBitSelect(il, instr, ARMV7_INTRIN_VBIF); break; case armv7::ARMV7_VBIT: - il.AddInstruction(WriteArithOperand(il, instr, - il.Or(GetRegisterSize(instr, 0), - il.And(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2)), - il.And(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 0), - il.Not(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 2)))))); + VectorBitSelect(il, instr, ARMV7_INTRIN_VBIT); break; case armv7::ARMV7_VBSL: - il.AddInstruction(WriteArithOperand(il, instr, - il.Or(GetRegisterSize(instr, 0), - il.And(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 0)), - il.And(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 2), - il.Not(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 0)))))); + VectorBitSelect(il, instr, ARMV7_INTRIN_VBSL); + break; + case armv7::ARMV7_VCEQ: + VectorCompareEqual(il, instr); + break; + case armv7::ARMV7_VCGT: + VectorCompareGreaterThan(il, instr); + break; + case armv7::ARMV7_VDUP: + VectorDuplicate(il, instr); + break; + case armv7::ARMV7_VAND: + il.AddInstruction(WriteArithOperand( + il, instr, il.And(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2)))); break; case armv7::ARMV7_VEOR: il.AddInstruction(WriteArithOperand( il, instr, il.Xor(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2)))); break; + case armv7::ARMV7_VORR: + il.AddInstruction(WriteArithOperand( + il, instr, il.Or(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2)))); + break; + case armv7::ARMV7_VQADD: + SaturatingVectorAdd(il, instr); + break; + case armv7::ARMV7_VABD: + VectorAbsoluteDifference(il, instr, ARMV7_INTRIN_VABD); + break; + case armv7::ARMV7_VABDL: + VectorAbsoluteDifference(il, instr, ARMV7_INTRIN_VABDL); + break; + case armv7::ARMV7_VABA: + VectorAbsoluteDifferenceAccumulate(il, instr, ARMV7_INTRIN_VABA); + break; + case armv7::ARMV7_VABAL: + VectorAbsoluteDifferenceAccumulate(il, instr, ARMV7_INTRIN_VABAL); + break; + case armv7::ARMV7_VADDL: + VectorWideningAdd(il, instr, ARMV7_INTRIN_VADDL); + break; + case armv7::ARMV7_VADDW: + VectorWideningAdd(il, instr, ARMV7_INTRIN_VADDW); + break; + case armv7::ARMV7_VRADDHN: + VectorRoundingAddNarrow(il, instr); + break; + case armv7::ARMV7_VQSHL: + SaturatingVectorShiftLeft(il, instr, ARMV7_INTRIN_VQSHL); + break; + case armv7::ARMV7_VQRSHL: + SaturatingVectorShiftLeft(il, instr, ARMV7_INTRIN_VQRSHL); + break; + case armv7::ARMV7_VQSHRN: + SaturatingVectorShiftRightNarrow(il, instr, 0); + break; + case armv7::ARMV7_VQSHRUN: + SaturatingVectorShiftRightNarrow(il, instr, ARMV7_INTRIN_VQSHRUN); + break; + case armv7::ARMV7_VQRSHRN: + SaturatingVectorShiftRightNarrow(il, instr, static_cast(-1)); + break; + case armv7::ARMV7_VQRSHRUN: + SaturatingVectorShiftRightNarrow(il, instr, ARMV7_INTRIN_VQRSHRUN); + break; + case armv7::ARMV7_VQMOVN: + case armv7::ARMV7_VQMOVUN: + SaturatingVectorMoveNarrow(il, instr); + break; + case armv7::ARMV7_VRSHR: + RoundedVectorShift(il, instr, ARMV7_INTRIN_VRSHR); + break; + case armv7::ARMV7_VRSHL: + RoundedVectorShift(il, instr, ARMV7_INTRIN_VRSHL); + break; + case armv7::ARMV7_VSRA: + ShiftRightAccumulateOrInsert(il, instr, ARMV7_INTRIN_VSRA); + break; + case armv7::ARMV7_VRSRA: + ShiftRightAccumulateOrInsert(il, instr, ARMV7_INTRIN_VRSRA); + break; + case armv7::ARMV7_VSRI: + ShiftRightAccumulateOrInsert(il, instr, ARMV7_INTRIN_VSRI); + break; + case armv7::ARMV7_VSLI: + ShiftRightAccumulateOrInsert(il, instr, ARMV7_INTRIN_VSLI); + break; + case armv7::ARMV7_VSHL: + VectorShiftLeft(il, instr); + break; + case armv7::ARMV7_VSHLL: + VectorShiftLeftLong(il, instr); + break; + case armv7::ARMV7_VSHR: + VectorShiftRight(il, instr); + break; + case armv7::ARMV7_VTBL: + case armv7::ARMV7_VTBX: + VectorTableLookup(il, instr); + break; case armv7::ARMV7_VSUB: if (instr->format->operationFlags & (INSTR_FORMAT_FLAG_F32 | INSTR_FORMAT_FLAG_F64)) { @@ -1754,8 +4599,9 @@ bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il, } else { - // Non scalar unsupported. - il.AddInstruction(il.Unimplemented()); + size_t size = GetRegisterSize(instr, 0); + il.AddInstruction(WriteArithOperand(il, instr, + il.Sub(size, ReadILOperand(il, instr, 1, size), ReadILOperand(il, instr, 2, size)), size)); } break; case armv7::ARMV7_VFMA: @@ -1773,13 +4619,122 @@ bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il, il.FloatSub(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 0), il.FloatMult( GetRegisterSize(instr, 0), ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2))))); + } + else + { + il.AddInstruction(il.Unimplemented()); + } + break; + case armv7::ARMV7_VHADD: + HalvingVectorAdd(il, instr); + break; + case armv7::ARMV7_VFNMS: + case armv7::ARMV7_VNMLS: + if (instr->format->operationFlags & (INSTR_FORMAT_FLAG_F32 | INSTR_FORMAT_FLAG_F64)) + { + size_t size = GetRegisterSize(instr, 0); + ExprId product = il.FloatMult(size, ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2)); + if ((strncmp(instr->format->operation, "vfnma", 5) == 0) || + (strncmp(instr->format->operation, "vnmla", 5) == 0)) + { + il.AddInstruction(WriteArithOperand(il, instr, + il.FloatNeg(size, il.FloatAdd(size, ReadILOperand(il, instr, 0), product)))); + } + else if ((strncmp(instr->format->operation, "vfnms", 5) == 0) || + (strncmp(instr->format->operation, "vnmls", 5) == 0)) + { + il.AddInstruction(WriteArithOperand(il, instr, + il.FloatNeg(size, il.FloatSub(size, ReadILOperand(il, instr, 0), product)))); + } + else + { + il.AddInstruction(il.Unimplemented()); + } + } + else + { + il.AddInstruction(il.Unimplemented()); + } + break; + case armv7::ARMV7_VMAXNM: + { + uint32_t intrinsic = ARMV7_INTRIN_VMAXNM; + if (strncmp(instr->format->operation, "vminnm", 6) == 0) + intrinsic = ARMV7_INTRIN_VMINNM; + else if (strncmp(instr->format->operation, "vmaxnm", 6) != 0) + { + il.AddInstruction(il.Unimplemented()); + break; } + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + intrinsic, + { ReadILOperand(il, instr, 1, GetRegisterSize(instr, 0)), + ReadILOperand(il, instr, 2, GetRegisterSize(instr, 0)) })); + break; + } + case armv7::ARMV7_VMAX: + VectorMaximumMinimum(il, instr, ARMV7_INTRIN_VMAX); + break; + case armv7::ARMV7_VMIN: + VectorMaximumMinimum(il, instr, ARMV7_INTRIN_VMIN); + break; + case armv7::ARMV7_VPMAX: + if (strncmp(instr->format->operation, "vpmin", 5) == 0) + VectorMaximumMinimum(il, instr, ARMV7_INTRIN_VPMIN); + else if (strncmp(instr->format->operation, "vpmax", 5) == 0) + VectorMaximumMinimum(il, instr, ARMV7_INTRIN_VPMAX); else - { - // Non scalar unsupported. il.AddInstruction(il.Unimplemented()); + break; + case armv7::ARMV7_VREV16: + VectorReverse(il, instr, ARMV7_INTRIN_VREV16); + break; + case armv7::ARMV7_VREV32: + VectorReverse(il, instr, ARMV7_INTRIN_VREV32); + break; + case armv7::ARMV7_VREV64: + VectorReverse(il, instr, ARMV7_INTRIN_VREV64); + break; + case armv7::ARMV7_VEXT: + VectorExtract(il, instr); + break; + case armv7::ARMV7_VMLA: + case armv7::ARMV7_VMLS: + if (instr->format->operationFlags & (INSTR_FORMAT_FLAG_F32 | INSTR_FORMAT_FLAG_F64)) + { + size_t size = GetRegisterSize(instr, 0); + ExprId product = il.FloatMult(size, ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2)); + if (strncmp(instr->format->operation, "vmla", 4) == 0) + { + il.AddInstruction(WriteArithOperand(il, instr, + il.FloatAdd(size, ReadILOperand(il, instr, 0), product))); + } + else if (strncmp(instr->format->operation, "vmls", 4) == 0) + { + il.AddInstruction(WriteArithOperand(il, instr, + il.FloatSub(size, ReadILOperand(il, instr, 0), product))); + } + else + { + il.AddInstruction(il.Unimplemented()); + } + } + else + { + uint32_t intrinsic = (strncmp(instr->format->operation, "vmls", 4) == 0) ? ARMV7_INTRIN_VMLS : ARMV7_INTRIN_VMLA; + if (!VectorMultiplyAccumulateIntrinsic(il, instr, intrinsic)) + il.AddInstruction(il.Unimplemented()); } break; + case armv7::ARMV7_VMLAL: + case armv7::ARMV7_VMLSL: + { + uint32_t intrinsic = (strncmp(instr->format->operation, "vmlsl", 5) == 0) ? ARMV7_INTRIN_VMLSL : ARMV7_INTRIN_VMLAL; + if (!VectorMultiplyAccumulateIntrinsic(il, instr, intrinsic)) + il.AddInstruction(il.Unimplemented()); + break; + } case armv7::ARMV7_VMUL: if (instr->format->operationFlags & (INSTR_FORMAT_FLAG_F32 | INSTR_FORMAT_FLAG_F64)) { @@ -1787,11 +4742,31 @@ bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il, il.FloatMult(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2)))); } else + { + if (!VectorMultiplyIntrinsic(il, instr)) + il.AddInstruction(il.Unimplemented()); + } + break; + case armv7::ARMV7_VQDMULL: + if (!VectorSaturatingDoublingMultiplyLongIntrinsic(il, instr)) + il.AddInstruction(il.Unimplemented()); + break; + case armv7::ARMV7_VNMUL: + if (instr->format->operationFlags & (INSTR_FORMAT_FLAG_F32 | INSTR_FORMAT_FLAG_F64)) + { + il.AddInstruction(WriteArithOperand(il, instr, + il.FloatNeg(GetRegisterSize(instr, 0), + il.FloatMult(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 1), ReadILOperand(il, instr, 2))))); + } + else { // Non scalar unsupported. il.AddInstruction(il.Unimplemented()); } break; + case armv7::ARMV7_VCMP: + FloatCompare(il, instr); + break; case armv7::ARMV7_VDIV: if (instr->format->operationFlags & (INSTR_FORMAT_FLAG_F32 | INSTR_FORMAT_FLAG_F64)) { @@ -1816,10 +4791,100 @@ bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il, il.AddInstruction(il.Unimplemented()); } break; + case armv7::ARMV7_VSQRT: + if (instr->format->operationFlags & (INSTR_FORMAT_FLAG_F32 | INSTR_FORMAT_FLAG_F64)) + { + il.AddInstruction( + WriteArithOperand(il, instr, il.FloatSqrt(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 1)))); + } + else + { + // Non scalar unsupported. + il.AddInstruction(il.Unimplemented()); + } + break; + case armv7::ARMV7_VSEL: + { + LowLevelILLabel trueCode, falseCode, done; + size_t size = GetRegisterSize(instr, 0); + il.AddInstruction(il.If(GetCondition(il, instr->fields[FIELD_cond]), trueCode, falseCode)); + il.MarkLabel(trueCode); + il.AddInstruction(WriteILOperand(il, instr, 0, ReadILOperand(il, instr, 1), size)); + il.AddInstruction(il.Goto(done)); + il.MarkLabel(falseCode); + il.AddInstruction(WriteILOperand(il, instr, 0, ReadILOperand(il, instr, 2), size)); + il.MarkLabel(done); + break; + } + case armv7::ARMV7_VRINTA: + if (strncmp(instr->format->operation, "vrinta", 6) == 0) + { + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(GetRegisterOperand(instr, 0)) }, + ARMV7_INTRIN_VRINTA, + { ReadILOperand(il, instr, 1, GetRegisterSize(instr, 0)) })); + } + else + { + il.AddInstruction(WriteILOperand(il, instr, 0, RoundFloatOperand(il, instr), GetRegisterSize(instr, 0))); + } + break; + case armv7::ARMV7_VRINTR: + il.AddInstruction(WriteILOperand(il, instr, 0, RoundFloatOperand(il, instr), GetRegisterSize(instr, 0))); + break; case armv7::ARMV7_VMRS: - // TODO: If this sets the apsr register we do not track that in the core flag group. - il.AddInstruction(WriteILOperand(il, instr, 0, ReadILOperand(il, instr, 1), GetRegisterSize(instr, 1))); + { + int status_reg = GetVfpStatusRegister(instr, 1); + if (status_reg == REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + break; + } + + if ((instr->format->operands[0].type == OPERAND_FORMAT_RT_MRC) && (instr->fields[FIELD_Rt_mrc] == 15)) + { + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(LLIL_TEMP(0)) }, + ARMV7_INTRIN_VMRS, + { il.Const(4, status_reg) } + )); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 30)))); + il.AddInstruction(il.SetFlag(IL_FLAG_C, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 29)))); + il.AddInstruction(il.SetFlag(IL_FLAG_V, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 28)))); + break; + } + + uint32_t dest_reg = GetRegisterOperand(instr, 0); + if (dest_reg == REG_INVALID) + { + il.AddInstruction(il.Unimplemented()); + break; + } + il.AddInstruction(il.Intrinsic( + { RegisterOrFlag::Register(dest_reg) }, + ARMV7_INTRIN_VMRS, + { il.Const(4, status_reg) } + )); + break; + } + case armv7::ARMV7_VMSR: + { + int status_reg = GetVfpStatusRegister(instr, 0); + uint32_t source_reg = GetRegisterOperand(instr, 1); + if ((status_reg == REG_INVALID) || (source_reg == REG_INVALID)) + { + il.AddInstruction(il.Unimplemented()); + break; + } + + il.AddInstruction(il.Intrinsic( + {}, + ARMV7_INTRIN_VMSR, + { il.Const(4, status_reg), il.Register(GetRegisterSize(instr, 1), source_reg) } + )); break; + } case armv7::ARMV7_VCVT: if (IS_FIELD_PRESENT(instr, FIELD_to_fixed)) { @@ -1830,8 +4895,35 @@ bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il, /* VCVT.F64.
,
,# */ /* VCVT.
,,# */ /* VCVT.
,
,# */ - // TODO: fixed-point unsupported. - il.AddInstruction(il.Unimplemented()); + size_t floatSize = GetRegisterSize(instr, 0); + size_t fixedSize = instr->fields[FIELD_size] / 8; + bool isUnsigned = instr->fields[FIELD_unsigned]; + uint64_t fractionalBits = instr->fields[FIELD_imm]; + auto fixedSource = [&]() { + ExprId value = ReadILOperand(il, instr, 1, GetRegisterSize(instr, 1)); + if (fixedSize < GetRegisterSize(instr, 1)) + value = il.LowPart(fixedSize, value); + return value; + }; + + if (instr->fields[FIELD_to_fixed]) + { + ExprId scaled = il.FloatMult(floatSize, + ReadILOperand(il, instr, 1, floatSize), + FixedPointScale(il, floatSize, fractionalBits)); + ExprId converted = il.FloatToInt(floatSize, il.RoundToInt(floatSize, scaled)); + if (isUnsigned) + converted = il.ZeroExtend(floatSize, converted); + il.AddInstruction(WriteILOperand(il, instr, 0, converted, floatSize)); + } + else + { + ExprId converted = isUnsigned + ? il.IntToFloat(floatSize, il.ZeroExtend(floatSize, fixedSource())) + : il.IntToFloat(floatSize, il.SignExtend(floatSize, fixedSource())); + il.AddInstruction(WriteILOperand(il, instr, 0, + il.FloatDiv(floatSize, converted, FixedPointScale(il, floatSize, fractionalBits)), floatSize)); + } } else if (IS_FIELD_PRESENT(instr, FIELD_fbits)) { @@ -1978,7 +5070,20 @@ bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il, } else /* if (instr->format->operandCount == 2) */ { - if (instr->format->operands[1].type == OPERAND_FORMAT_IMM64 && strcmp(instr->format->operands[0].prefix, "q") == 0) + if (instr->format->operands[0].type == OPERAND_FORMAT_REG_INDEX) + { + const instruction_operand_format& op = instr->format->operands[0]; + size_t regSize = RegisterSizeFromPrefix(op.prefix); + uint32_t reg = GetRegisterByIndex(instr->fields[op.field0], op.prefix); + il.AddInstruction(il.SetRegister(regSize, reg, + InsertVectorElement(il, instr, 0, ReadILOperand(il, instr, 1), GetRegisterSize(instr, 1)))); + } + else if (instr->format->operands[1].type == OPERAND_FORMAT_REG_INDEX) + { + il.AddInstruction(WriteILOperand(il, instr, 0, + ReadVectorElement(il, instr, 1, GetRegisterSize(instr, 0)))); + } + else if (instr->format->operands[1].type == OPERAND_FORMAT_IMM64 && strcmp(instr->format->operands[0].prefix, "q") == 0) // Load immediate in high and low il.AddInstruction(WriteILOperand(il, instr, 0, il.Or(16, ReadILOperand(il, instr, 1), @@ -2008,64 +5113,161 @@ bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il, // } } break; + case armv7::ARMV7_VSTM: case armv7::ARMV7_VSTMDB: + case armv7::ARMV7_VSTMIA: { - // TODO: Clean this code up... - const char* prefix = "d"; - if (IS_FIELD_PRESENT(instr, FIELD_single_regs)) + VfpLoadStoreMultiple(il, instr, false); + break; + } + case armv7::ARMV7_VST1: + { + ExprId base = GetMemoryAddress(il, instr, 1, 4, false); + size_t totalSize = 0; + + if (instr->format->operands[0].type == OPERAND_FORMAT_REGISTERS) { - if (instr->fields[FIELD_single_regs] == 1) + unsigned int d = instr->fields[FIELD_d]; + unsigned int inc = 1; + if (IS_FIELD_PRESENT(instr, FIELD_inc)) + inc = instr->fields[FIELD_inc]; + int regs = instr->fields[FIELD_regs]; + for (int i = 0; i < regs; ++i) { - prefix = "s"; + int regIdx = (d + i * inc) % 32; + size_t offset = i * 8; + il.AddInstruction(il.Store(8, + offset == 0 ? base : il.Add(4, base, il.Const(4, offset)), + il.Register(8, GetRegisterByIndex(regIdx, "d")))); } + totalSize = regs * 8; } - auto regSize = RegisterSizeFromPrefix(prefix); - unsigned int d = instr->fields[FIELD_d]; - unsigned int inc = 1; - if (IS_FIELD_PRESENT(instr, FIELD_inc)) - inc = instr->fields[FIELD_inc]; - int regs = instr->fields[FIELD_regs]; - for (int i = 0; i < regs; ++i) + else if (instr->format->operands[0].type == OPERAND_FORMAT_REGISTERS_INDEXED) { - if (d + (i * inc) >= 32 && strcmp(prefix, "s") == 0) - break; - if (i >= 16 && strcmp(prefix, "d") == 0) - break; - int regIdx = (d + i * inc) % 32; - il.Store(regSize, il.Add(4, ReadILOperand(il, instr, 0), il.Const(4, i * regSize)), - il.Register(regSize, GetRegisterByIndex(regIdx, prefix))); + size_t elementSize = instr->fields[FIELD_ebytes]; + unsigned int d = instr->fields[FIELD_d]; + unsigned int inc = 1; + if (IS_FIELD_PRESENT(instr, FIELD_inc)) + inc = instr->fields[FIELD_inc]; + unsigned int index = instr->fields[FIELD_index]; + int length = instr->fields[FIELD_length]; + for (int i = 0; i < length; ++i) + { + int regIdx = (d + i * inc) % 32; + size_t offset = i * elementSize; + il.AddInstruction(il.Store(elementSize, + offset == 0 ? base : il.Add(4, base, il.Const(4, offset)), + ReadVst1Element(il, GetRegisterByIndex(regIdx, "d"), elementSize, index))); + } + totalSize = length * elementSize; + } + else + { + il.AddInstruction(il.Unimplemented()); + break; + } + + if (HasWriteback(instr, 1)) + { + uint32_t baseReg = GetRegisterByIndex(instr->fields[instr->format->operands[1].field0]); + if (IS_FIELD_PRESENT(instr, FIELD_register_index) && instr->fields[FIELD_register_index]) + { + uint32_t indexReg = GetRegisterByIndex(instr->fields[FIELD_m]); + il.AddInstruction(il.SetRegister(4, baseReg, + il.Add(4, il.Register(4, baseReg), il.Register(4, indexReg)))); + } + else + { + il.AddInstruction(il.SetRegister(4, baseReg, + il.Add(4, il.Register(4, baseReg), il.Const(4, totalSize)))); + } } break; } - case armv7::ARMV7_VLDMDB: + case armv7::ARMV7_VST2: + StructuredVectorStoreIntrinsic(il, instr, ARMV7_INTRIN_VST2, 2); + break; + case armv7::ARMV7_VST4: + StructuredVectorStoreIntrinsic(il, instr, ARMV7_INTRIN_VST4, 4); + break; + case armv7::ARMV7_VLD2: + StructuredVectorLoadIntrinsic(il, instr, ARMV7_INTRIN_VLD2, 2); + break; + case armv7::ARMV7_VLD4: + StructuredVectorLoadIntrinsic(il, instr, ARMV7_INTRIN_VLD4, 4); + break; + case armv7::ARMV7_VLD1: { - // TODO: Clean this code up... - const char* prefix = "d"; - if (IS_FIELD_PRESENT(instr, FIELD_single_regs)) + ExprId base = GetMemoryAddress(il, instr, 1, 4, false); + size_t totalSize = 0; + + if (instr->format->operands[0].type == OPERAND_FORMAT_REGISTERS) { - if (instr->fields[FIELD_single_regs] == 1) + unsigned int d = instr->fields[FIELD_d]; + unsigned int inc = 1; + if (IS_FIELD_PRESENT(instr, FIELD_inc)) + inc = instr->fields[FIELD_inc]; + int regs = IS_FIELD_PRESENT(instr, FIELD_regs_n) ? instr->fields[FIELD_regs_n] : instr->fields[FIELD_regs]; + for (int i = 0; i < regs; ++i) { - prefix = "s"; + int regIdx = (d + i * inc) % 32; + size_t offset = i * 8; + il.AddInstruction(il.SetRegister(8, GetRegisterByIndex(regIdx, "d"), + il.Load(8, offset == 0 ? base : il.Add(4, base, il.Const(4, offset))))); } + totalSize = regs * 8; } - auto regSize = RegisterSizeFromPrefix(prefix); - unsigned int d = instr->fields[FIELD_d]; - unsigned int inc = 1; - if (IS_FIELD_PRESENT(instr, FIELD_inc)) - inc = instr->fields[FIELD_inc]; - int regs = instr->fields[FIELD_regs]; - for (int i = 0; i < regs; ++i) + else if (instr->format->operands[0].type == OPERAND_FORMAT_REGISTERS_INDEXED) { - if (d + (i * inc) >= 32 && strcmp(prefix, "s") == 0) - break; - if (i >= 16 && strcmp(prefix, "d") == 0) - break; - int regIdx = (d + i * inc) % 32; - il.AddInstruction(il.SetRegister(regSize, GetRegisterByIndex(regIdx, prefix), - il.Load(regSize, il.Add(4, ReadILOperand(il, instr, 0), il.Const(4, i * regSize))))); + size_t elementSize = instr->fields[FIELD_ebytes]; + unsigned int d = instr->fields[FIELD_d]; + unsigned int inc = 1; + if (IS_FIELD_PRESENT(instr, FIELD_inc)) + inc = instr->fields[FIELD_inc]; + unsigned int index = instr->fields[FIELD_index]; + int length = instr->fields[FIELD_length]; + for (int i = 0; i < length; ++i) + { + int regIdx = (d + i * inc) % 32; + size_t offset = i * elementSize; + uint32_t reg = GetRegisterByIndex(regIdx, "d"); + il.AddInstruction(il.SetRegister(8, reg, + InsertVld1Element(il, reg, + il.Load(elementSize, offset == 0 ? base : il.Add(4, base, il.Const(4, offset))), + elementSize, index))); + } + totalSize = length * elementSize; + } + else + { + il.AddInstruction(il.Unimplemented()); + break; + } + + if (HasWriteback(instr, 1)) + { + uint32_t baseReg = GetRegisterByIndex(instr->fields[instr->format->operands[1].field0]); + if (IS_FIELD_PRESENT(instr, FIELD_register_index) && instr->fields[FIELD_register_index]) + { + uint32_t indexReg = GetRegisterByIndex(instr->fields[FIELD_m]); + il.AddInstruction(il.SetRegister(4, baseReg, + il.Add(4, il.Register(4, baseReg), il.Register(4, indexReg)))); + } + else + { + il.AddInstruction(il.SetRegister(4, baseReg, + il.Add(4, il.Register(4, baseReg), il.Const(4, totalSize)))); + } } break; } + case armv7::ARMV7_VLDM: + case armv7::ARMV7_VLDMDB: + case armv7::ARMV7_VLDMIA: + { + VfpLoadStoreMultiple(il, instr, true); + break; + } case armv7::ARMV7_VPUSH: { // TODO: Clean this code up... From 3dcf465eb9a6e0599e737c990b267c29642fb8b4 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Thu, 11 Jun 2026 15:16:21 -0400 Subject: [PATCH 2/2] Coalesce Thumb IT blocks with trailing conditional branches --- arch/armv7/thumb2_disasm/arch_thumb2.cpp | 291 +++++++++++++++++------ 1 file changed, 219 insertions(+), 72 deletions(-) diff --git a/arch/armv7/thumb2_disasm/arch_thumb2.cpp b/arch/armv7/thumb2_disasm/arch_thumb2.cpp index 600596f1c8..5a49dc6018 100644 --- a/arch/armv7/thumb2_disasm/arch_thumb2.cpp +++ b/arch/armv7/thumb2_disasm/arch_thumb2.cpp @@ -20,6 +20,55 @@ using namespace std; #define snprintf _snprintf #endif +static bool IsConditionalBranch(const decomp_result& decomp) +{ + return (decomp.mnem == ARMV7_B) && (decomp.format->operationFlags & INSTR_FORMAT_FLAG_CONDITIONAL) + && (decomp.fields[FIELD_cond] != COND_AL); +} + +static bool IsSameOrInvertedCondition(uint32_t lhs, uint32_t rhs) +{ + return (lhs == rhs) || ((lhs < COND_AL) && (rhs < COND_AL) && ((lhs ^ 1) == rhs)); +} + +static bool ThumbITInstructionWritesAPSR(const decomp_result& decomp) +{ + switch (decomp.mnem) + { + case ARMV7_CMN: + case ARMV7_CMP: + case ARMV7_TEQ: + case ARMV7_TST: + return true; + default: + return false; + } +} + +static uint32_t GetConditionalBranchTarget(const decomp_result& decomp) +{ + return decomp.pc + decomp.fields[decomp.format->operands[0].field0]; +} + +static void EmitDirectThumbJump(Architecture* arch, LowLevelILFunction& il, uint32_t target) +{ + BNLowLevelILLabel* label = il.GetLabelForAddress(arch, target); + if (label) + il.AddInstruction(il.Goto(*label)); + else + il.AddInstruction(il.Jump(il.ConstPointer(4, target))); +} + +struct ThumbITSlot +{ + uint32_t addr = 0; + decomp_result decomp = {}; + bool thenSlot = false; + bool lift = false; + bool directBranch = false; + uint32_t branchTarget = 0; +}; + static Ref get_msr_op_enum() { EnumerationBuilder builder; @@ -167,7 +216,9 @@ class Thumb2Architecture: public ArmCommonArchitecture virtual size_t GetMaxInstructionLength() const override { - return 18; // IT blocks can have up to four following associated instructions + // IT blocks can have up to four following associated instructions, and + // may be coalesced with a following conditional branch. + return 22; } virtual size_t GetInstructionAlignment() const override @@ -232,6 +283,8 @@ class Thumb2Architecture: public ArmCommonArchitecture bool falseBranched = false; bool trueReturned = false; bool falseReturned = false; + bool trueWroteFlags = false; + bool falseWroteFlags = false; uint64_t trueBranchTargetAddr = 0; uint64_t falseBranchTargetAddr = 0; @@ -240,56 +293,95 @@ class Thumb2Architecture: public ArmCommonArchitecture { bool isTrue = (i == 0) || (((mask >> (4 - i)) & 1) == (cond & 1)); - InstructionInfo innerResult; - if (!GetInstructionInfo(data + offset, addr + offset, maxLen - offset, innerResult)) + if (offset >= maxLen || (maxLen - offset) < 2) + break; + + decomp_result innerDecomp; + size_t remainingLen = maxLen - offset; + bool decoded = populateDecomposeRequest(&request, data + offset, remainingLen, addr + offset, + IFTHEN_YES, ((i + 1) >= instrCount) ? IFTHENLAST_YES : IFTHENLAST_NO) + && (thumb_decompose(&request, &innerDecomp) == STATUS_OK) + && !(innerDecomp.status & STATUS_UNDEFINED) && innerDecomp.format; + if (!decoded) break; - if ((offset + innerResult.length) > maxLen) + size_t innerLen = innerDecomp.instrSize / 8; + if ((innerLen == 0) || (innerLen > remainingLen)) break; bool& terminated = isTrue ? trueTerminated : falseTerminated; bool& branched = isTrue ? trueBranched : falseBranched; bool& returned = isTrue ? trueReturned : falseReturned; + bool& wroteFlags = isTrue ? trueWroteFlags : falseWroteFlags; uint64_t& branchTarget = isTrue ? trueBranchTargetAddr : falseBranchTargetAddr; // Only process if the conditional branch we're following isn't terminated // Otherwise, just track if the arch is switching and the offset if (!terminated) { - for (size_t j = 0; j < innerResult.branchCount; j++) + wroteFlags |= ThumbITInstructionWritesAPSR(innerDecomp); + + InstructionInfo innerResult; + if (GetInstructionInfo(data + offset, addr + offset, remainingLen, innerResult)) { - switch (innerResult.branchType[j]) + for (size_t j = 0; j < innerResult.branchCount; j++) { - case UnconditionalBranch: - case TrueBranch: - case FalseBranch: - branched = true; - terminated = true; - branchTarget = innerResult.branchTarget[j]; - break; - case FunctionReturn: - returned = true; - terminated = true; - break; - case CallDestination: - result.AddBranch(CallDestination, innerResult.branchTarget[j], - innerResult.branchArch[j] ? m_armArch : this); - break; - case UnresolvedBranch: - case IndirectBranch: - case ExceptionBranch: - // We don't know the branch target so just set terminated - terminated = true; - break; - default: - break; + switch (innerResult.branchType[j]) + { + case UnconditionalBranch: + case TrueBranch: + case FalseBranch: + branched = true; + terminated = true; + branchTarget = innerResult.branchTarget[j]; + break; + case FunctionReturn: + returned = true; + terminated = true; + break; + case CallDestination: + result.AddBranch(CallDestination, innerResult.branchTarget[j], + innerResult.branchArch[j] ? m_armArch : this); + break; + case UnresolvedBranch: + case IndirectBranch: + case ExceptionBranch: + // We don't know the branch target so just set terminated + terminated = true; + break; + default: + break; + } } + + if (innerResult.archTransitionByTargetAddr) + result.archTransitionByTargetAddr = true; } } - if (innerResult.archTransitionByTargetAddr) - result.archTransitionByTargetAddr = true; + offset += innerLen; + } + + decomp_result branchDecomp; + if ((offset < maxLen) && ((maxLen - offset) >= 2) + && populateDecomposeRequest(&request, data + offset, maxLen - offset, addr + offset, IFTHEN_NO, IFTHENLAST_NO) + && (thumb_decompose(&request, &branchDecomp) == STATUS_OK) + && ((offset + (branchDecomp.instrSize / 8)) <= maxLen) + && !(branchDecomp.status & STATUS_UNDEFINED) && branchDecomp.format && IsConditionalBranch(branchDecomp) + && IsSameOrInvertedCondition(branchDecomp.fields[FIELD_cond], cond)) + { + bool branchOnTrue = branchDecomp.fields[FIELD_cond] == cond; + bool& terminated = branchOnTrue ? trueTerminated : falseTerminated; + bool& branched = branchOnTrue ? trueBranched : falseBranched; + bool& wroteFlags = branchOnTrue ? trueWroteFlags : falseWroteFlags; + uint64_t& branchTarget = branchOnTrue ? trueBranchTargetAddr : falseBranchTargetAddr; - offset += innerResult.length; + if (!terminated && !wroteFlags) + { + branched = true; + terminated = true; + branchTarget = GetConditionalBranchTarget(branchDecomp); + offset += branchDecomp.instrSize / 8; + } } result.length = offset; @@ -2626,82 +2718,137 @@ class Thumb2Architecture: public ArmCommonArchitecture uint32_t mask = decomp.fields[FIELD_mask]; uint32_t cond = decomp.fields[FIELD_firstcond]; - // Calculate number of instructions size_t instrCount; - if (decomp.fields[FIELD_mask] & 1) + if (mask & 1) instrCount = 4; - else if (decomp.fields[FIELD_mask] & 2) + else if (mask & 2) instrCount = 3; - else if (decomp.fields[FIELD_mask] & 4) + else if (mask & 4) instrCount = 2; else instrCount = 1; - // decompose all instructions in the if-then block - vector addrsTrue, addrsFalse; - vector decompsTrue, decompsFalse; + // Decompose all instructions in the IT block and keep their original + // mask slot. A path may skip later slots once it has branched/returned. + vector slots; + bool pathTerminated[2] = {false, false}; + bool pathHasBody[2] = {false, false}; + bool pathWroteFlags[2] = {false, false}; for (size_t i = 0; i < instrCount; i++) { if (offset >= len || (len - offset) < 2) return false; - bool isTrue = (i == 0) || (((mask >> (4 - i)) & 1) == (cond & 1)); + bool thenSlot = (i == 0) || (((mask >> (4 - i)) & 1) == (cond & 1)); + size_t stateIdx = thenSlot ? 0 : 1; size_t remainingLen = len - offset; - if (!populateDecomposeRequest(&request, data+offset, remainingLen, addr+offset, - IFTHEN_YES, ((i + 1) >= instrCount) ? IFTHENLAST_YES : IFTHENLAST_NO)) - return false; - - if (thumb_decompose(&request, &decomp) != STATUS_OK) + bool decoded = populateDecomposeRequest(&request, data + offset, remainingLen, addr + offset, + IFTHEN_YES, ((i + 1) >= instrCount) ? IFTHENLAST_YES : IFTHENLAST_NO) + && (thumb_decompose(&request, &decomp) == STATUS_OK) + && !(decomp.status & STATUS_UNDEFINED) && decomp.format; + if (!decoded) return false; if ((decomp.instrSize / 8) > remainingLen) return false; - if ((decomp.status & STATUS_UNDEFINED) || (!decomp.format)) - return false; - if (isTrue) { - addrsTrue.push_back(request.addr); - decompsTrue.push_back(decomp); - } - else { - addrsFalse.push_back(request.addr); - decompsFalse.push_back(decomp); + ThumbITSlot slot; + slot.addr = request.addr; + slot.decomp = decomp; + slot.thenSlot = thenSlot; + slot.lift = !pathTerminated[stateIdx]; + slots.push_back(slot); + pathHasBody[stateIdx] |= slot.lift; + + if (slot.lift) + { + pathWroteFlags[stateIdx] |= ThumbITInstructionWritesAPSR(decomp); + + InstructionInfo innerResult; + if (GetInstructionInfo(data + offset, addr + offset, remainingLen, innerResult)) + { + for (size_t j = 0; j < innerResult.branchCount; j++) + { + switch (innerResult.branchType[j]) + { + case UnconditionalBranch: + case TrueBranch: + case FalseBranch: + case FunctionReturn: + case UnresolvedBranch: + case IndirectBranch: + case ExceptionBranch: + pathTerminated[stateIdx] = true; + break; + default: + break; + } + } + } } offset += decomp.instrSize / 8; } + decomp_result branchDecomp; + + if ((offset < len) && ((len - offset) >= 2) + && populateDecomposeRequest(&request, data + offset, len - offset, addr + offset, IFTHEN_NO, IFTHENLAST_NO) + && (thumb_decompose(&request, &branchDecomp) == STATUS_OK) + && ((offset + (branchDecomp.instrSize / 8)) <= len) + && !(branchDecomp.status & STATUS_UNDEFINED) && branchDecomp.format && IsConditionalBranch(branchDecomp) + && IsSameOrInvertedCondition(branchDecomp.fields[FIELD_cond], cond)) + { + bool branchOnTrue = branchDecomp.fields[FIELD_cond] == cond; + size_t stateIdx = branchOnTrue ? 0 : 1; + if (!pathTerminated[stateIdx] && !pathWroteFlags[stateIdx]) + { + ThumbITSlot slot; + slot.addr = request.addr; + slot.thenSlot = branchOnTrue; + slot.lift = true; + slot.directBranch = true; + slot.branchTarget = GetConditionalBranchTarget(branchDecomp); + slots.push_back(slot); + pathHasBody[stateIdx] = true; + pathTerminated[stateIdx] = true; + offset += branchDecomp.instrSize / 8; + } + } + // generate IL LowLevelILLabel labelTrue, labelFalse, labelDone; il.AddInstruction(il.If(GetCondition(il, cond), labelTrue, labelFalse)); - // generate IL for "true" if-else members - il.MarkLabel(labelTrue); - - for (size_t i = 0; i < decompsTrue.size(); i++) + auto liftPath = [&](bool thenPath, LowLevelILLabel& label) { - il.SetCurrentAddress(this, addrsTrue[i]); - GetLowLevelILForThumbInstruction(this, il, &(decompsTrue[i]), true); - } + size_t stateIdx = thenPath ? 0 : 1; - if (decompsFalse.empty()) { - il.MarkLabel(labelFalse); - } - else { - il.AddInstruction(il.Goto(labelDone)); - il.MarkLabel(labelFalse); + il.MarkLabel(label); - // generate IL for "false" if-else members - for (int i = 0; i < decompsFalse.size(); i++) + for (auto& slot : slots) { - il.SetCurrentAddress(this, addrsFalse[i]); - GetLowLevelILForThumbInstruction(this, il, &(decompsFalse[i]), true); + if (!slot.lift || (slot.thenSlot != thenPath)) + continue; + + il.SetCurrentAddress(this, slot.addr); + if (slot.directBranch) + EmitDirectThumbJump(this, il, slot.branchTarget); + else + GetLowLevelILForThumbInstruction(this, il, &slot.decomp, true); } + if (thenPath && pathHasBody[1] && !pathTerminated[stateIdx]) + il.AddInstruction(il.Goto(labelDone)); + }; + + liftPath(true, labelTrue); + liftPath(false, labelFalse); + + if (pathHasBody[1]) il.MarkLabel(labelDone); - } len = offset; return true;