blob: e0a913a6bb0cd89a0683e8c636788a4f24b1b0a3 [file] [log] [blame]
// Copyright (c) 2012-2013 ARM Limited
// All rights reserved
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: Giacomo Gabrielli
// Mbou Eyole
output header {{
namespace Aarch64
{
// AdvSIMD three same
template <typename DecoderFeatures>
StaticInstPtr decodeNeon3Same(ExtMachInst machInst);
// AdvSIMD three different
inline StaticInstPtr decodeNeon3Diff(ExtMachInst machInst);
// AdvSIMD two-reg misc
inline StaticInstPtr decodeNeon2RegMisc(ExtMachInst machInst);
// AdvSIMD across lanes
inline StaticInstPtr decodeNeonAcrossLanes(ExtMachInst machInst);
// AdvSIMD copy
inline StaticInstPtr decodeNeonCopy(ExtMachInst machInst);
// AdvSIMD vector x indexed element
template <typename DecoderFeatures>
StaticInstPtr decodeNeonIndexedElem(ExtMachInst machInst);
// AdvSIMD modified immediate
inline StaticInstPtr decodeNeonModImm(ExtMachInst machInst);
// AdvSIMD shift by immediate
inline StaticInstPtr decodeNeonShiftByImm(ExtMachInst machInst);
// AdvSIMD TBL/TBX
inline StaticInstPtr decodeNeonTblTbx(ExtMachInst machInst);
// AdvSIMD ZIP/UZP/TRN
inline StaticInstPtr decodeNeonZipUzpTrn(ExtMachInst machInst);
// AdvSIMD EXT
inline StaticInstPtr decodeNeonExt(ExtMachInst machInst);
// AdvSIMD scalar three same
inline StaticInstPtr decodeNeonSc3Same(ExtMachInst machInst);
// AdvSIMD scalar three different
inline StaticInstPtr decodeNeonSc3Diff(ExtMachInst machInst);
// AdvSIMD scalar two-reg misc
inline StaticInstPtr decodeNeonSc2RegMisc(ExtMachInst machInst);
// AdvSIMD scalar pairwise
inline StaticInstPtr decodeNeonScPwise(ExtMachInst machInst);
// AdvSIMD scalar copy
inline StaticInstPtr decodeNeonScCopy(ExtMachInst machInst);
// AdvSIMD scalar x indexed element
inline StaticInstPtr decodeNeonScIndexedElem(ExtMachInst machInst);
// AdvSIMD scalar shift by immediate
inline StaticInstPtr decodeNeonScShiftByImm(ExtMachInst machInst);
// AdvSIMD load/store
inline StaticInstPtr decodeNeonMem(ExtMachInst machInst);
}
}};
output decoder {{
namespace Aarch64
{
template <typename DecoderFeatures>
StaticInstPtr
decodeNeon3Same(ExtMachInst machInst)
{
uint8_t q = bits(machInst, 30);
uint8_t u = bits(machInst, 29);
uint8_t size = bits(machInst, 23, 22);
uint8_t opcode = bits(machInst, 15, 11);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16);
uint8_t size_q = (size << 1) | q;
uint8_t sz_q = size_q & 0x3;
switch (opcode) {
case 0x00:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UhaddDX, UhaddQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<ShaddDX, ShaddQX>(
q, size, machInst, vd, vn, vm);
case 0x01:
if (size_q == 0x6)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeXReg<UqaddDX, UqaddQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeXReg<SqaddDX, SqaddQX>(
q, size, machInst, vd, vn, vm);
case 0x02:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UrhaddDX, UrhaddQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SrhaddDX, SrhaddQX>(
q, size, machInst, vd, vn, vm);
case 0x03:
switch (size) {
case 0x0:
if (u) {
if (q)
return new EorQX<uint64_t>(machInst, vd, vn, vm);
else
return new EorDX<uint64_t>(machInst, vd, vn, vm);
} else {
if (q)
return new AndQX<uint64_t>(machInst, vd, vn, vm);
else
return new AndDX<uint64_t>(machInst, vd, vn, vm);
}
case 0x1:
if (u) {
if (q)
return new BslQX<uint64_t>(machInst, vd, vn, vm);
else
return new BslDX<uint64_t>(machInst, vd, vn, vm);
} else {
if (q)
return new BicQX<uint64_t>(machInst, vd, vn, vm);
else
return new BicDX<uint64_t>(machInst, vd, vn, vm);
}
case 0x2:
if (u) {
if (q)
return new BitQX<uint64_t>(machInst, vd, vn, vm);
else
return new BitDX<uint64_t>(machInst, vd, vn, vm);
} else {
if (q)
return new OrrQX<uint64_t>(machInst, vd, vn, vm);
else
return new OrrDX<uint64_t>(machInst, vd, vn, vm);
}
case 0x3:
if (u) {
if (q)
return new BifQX<uint64_t>(machInst, vd, vn, vm);
else
return new BifDX<uint64_t>(machInst, vd, vn, vm);
} else {
if (q)
return new OrnQX<uint64_t>(machInst, vd, vn, vm);
else
return new OrnDX<uint64_t>(machInst, vd, vn, vm);
}
}
case 0x04:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UhsubDX, UhsubQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<ShsubDX, ShsubQX>(
q, size, machInst, vd, vn, vm);
case 0x05:
if (size_q == 0x6)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeXReg<UqsubDX, UqsubQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeXReg<SqsubDX, SqsubQX>(
q, size, machInst, vd, vn, vm);
case 0x06:
if (size_q == 0x6)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeXReg<CmhiDX, CmhiQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeXReg<CmgtDX, CmgtQX>(
q, size, machInst, vd, vn, vm);
case 0x07:
if (size_q == 0x6)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeXReg<CmhsDX, CmhsQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeXReg<CmgeDX, CmgeQX>(
q, size, machInst, vd, vn, vm);
case 0x08:
if (size_q == 0x6)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeXReg<UshlDX, UshlQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeXReg<SshlDX, SshlQX>(
q, size, machInst, vd, vn, vm);
case 0x09:
if (size_q == 0x6)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeXReg<UqshlDX, UqshlQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeXReg<SqshlDX, SqshlQX>(
q, size, machInst, vd, vn, vm);
case 0x0a:
if (size_q == 0x6)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeXReg<UrshlDX, UrshlQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeXReg<SrshlDX, SrshlQX>(
q, size, machInst, vd, vn, vm);
case 0x0b:
if (size_q == 0x6)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeXReg<UqrshlDX, UqrshlQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeXReg<SqrshlDX, SqrshlQX>(
q, size, machInst, vd, vn, vm);
case 0x0c:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UmaxDX, UmaxQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SmaxDX, SmaxQX>(
q, size, machInst, vd, vn, vm);
case 0x0d:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UminDX, UminQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SminDX, SminQX>(
q, size, machInst, vd, vn, vm);
case 0x0e:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UabdDX, UabdQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SabdDX, SabdQX>(
q, size, machInst, vd, vn, vm);
case 0x0f:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UabaDX, UabaQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SabaDX, SabaQX>(
q, size, machInst, vd, vn, vm);
case 0x10:
if (size_q == 0x6)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeXReg<SubDX, SubQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonUThreeXReg<AddDX, AddQX>(
q, size, machInst, vd, vn, vm);
case 0x11:
if (size_q == 0x6)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeXReg<CmeqDX, CmeqQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonUThreeXReg<CmtstDX, CmtstQX>(
q, size, machInst, vd, vn, vm);
case 0x12:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<MlsDX, MlsQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonUThreeSReg<MlaDX, MlaQX>(
q, size, machInst, vd, vn, vm);
case 0x13:
if (size == 0x3 || (size != 0x0 && bits(machInst, 29)))
return new Unknown64(machInst);
if (u) {
if (q)
return new PmulQX<uint8_t>(machInst, vd, vn, vm);
else
return new PmulDX<uint8_t>(machInst, vd, vn, vm);
} else {
return decodeNeonUThreeSReg<MulDX, MulQX>(
q, size, machInst, vd, vn, vm);
}
case 0x14:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UmaxpDX, UmaxpQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SmaxpDX, SmaxpQX>(
q, size, machInst, vd, vn, vm);
case 0x15:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UminpDX, UminpQX>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SminpDX, SminpQX>(
q, size, machInst, vd, vn, vm);
case 0x16:
if (size == 0x3 || size == 0x0)
return new Unknown64(machInst);
if (u) {
if (q)
return decodeNeonSThreeHAndWReg<SqrdmulhQX>(
size, machInst, vd, vn, vm);
else
return decodeNeonSThreeHAndWReg<SqrdmulhDX>(
size, machInst, vd, vn, vm);
} else {
if (q)
return decodeNeonSThreeHAndWReg<SqdmulhQX>(
size, machInst, vd, vn, vm);
else
return decodeNeonSThreeHAndWReg<SqdmulhDX>(
size, machInst, vd, vn, vm);
}
case 0x17:
if (u || size_q == 0x6)
return new Unknown64(machInst);
else
return decodeNeonUThreeXReg<AddpDX, AddpQX>(
q, size, machInst, vd, vn, vm);
case 0x18:
if (sz_q == 0x2)
return new Unknown64(machInst);
if (size < 0x2) {
if (u)
return decodeNeonUThreeFpReg<FmaxnmpDX, FmaxnmpQX>(
q, size & 0x1, machInst, vd, vn, vm);
else
return decodeNeonUThreeFpReg<FmaxnmDX, FmaxnmQX>(
q, size & 0x1, machInst, vd, vn, vm);
} else {
if (u)
return decodeNeonUThreeFpReg<FminnmpDX, FminnmpQX>(
q, size & 0x1, machInst, vd, vn, vm);
else
return decodeNeonUThreeFpReg<FminnmDX, FminnmQX>(
q, size & 0x1, machInst, vd, vn, vm);
}
case 0x19:
if (size < 0x2) {
if (u || sz_q == 0x2)
return new Unknown64(machInst);
else
return decodeNeonUThreeFpReg<FmlaDX, FmlaQX>(
q, size & 0x1, machInst, vd, vn, vm);
} else {
if (u || sz_q == 0x2)
return new Unknown64(machInst);
else
return decodeNeonUThreeFpReg<FmlsDX, FmlsQX>(
q, size & 0x1, machInst, vd, vn, vm);
}
case 0x1a:
if (sz_q == 0x2)
return new Unknown64(machInst);
if (size < 0x2) {
if (u)
return decodeNeonUThreeFpReg<FaddpDX, FaddpQX>(
q, size & 0x1, machInst, vd, vn, vm);
else
return decodeNeonUThreeFpReg<FaddDX, FaddQX>(
q, size & 0x1, machInst, vd, vn, vm);
} else {
if (u)
return decodeNeonUThreeFpReg<FabdDX, FabdQX>(
q, size & 0x1, machInst, vd, vn, vm);
else
return decodeNeonUThreeFpReg<FsubDX, FsubQX>(
q, size & 0x1, machInst, vd, vn, vm);
}
case 0x1b:
if (size < 0x2 && sz_q != 0x2) {
if (u)
return decodeNeonUThreeFpReg<FmulDX, FmulQX>(
q, size & 0x1, machInst, vd, vn, vm);
else
return decodeNeonUThreeFpReg<FmulxDX, FmulxQX>(
q, size & 0x1, machInst, vd, vn, vm);
} else {
return new Unknown64(machInst);
}
case 0x1c:
if (size < 0x2) {
if (u)
return decodeNeonUThreeFpReg<FcmgeDX, FcmgeQX>(
q, size & 0x1, machInst, vd, vn, vm);
else
return decodeNeonUThreeFpReg<FcmeqDX, FcmeqQX>(
q, size & 0x1, machInst, vd, vn, vm);
} else {
if (u)
return decodeNeonUThreeFpReg<FcmgtDX, FcmgtQX>(
q, size & 0x1, machInst, vd, vn, vm);
else
return new Unknown64(machInst);
}
case 0x1d:
if (size < 0x2) {
if (u)
return decodeNeonUThreeFpReg<FacgeDX, FacgeQX>(
q, size & 0x1, machInst, vd, vn, vm);
else
return new Unknown64(machInst);
} else {
if (u)
return decodeNeonUThreeFpReg<FacgtDX, FacgtQX>(
q, size & 0x1, machInst, vd, vn, vm);
else
return new Unknown64(machInst);
}
case 0x1e:
if (sz_q == 0x2)
return new Unknown64(machInst);
if (size < 0x2) {
if (u)
return decodeNeonUThreeFpReg<FmaxpDX, FmaxpQX>(
q, size & 0x1, machInst, vd, vn, vm);
else
return decodeNeonUThreeFpReg<FmaxDX, FmaxQX>(
q, size & 0x1, machInst, vd, vn, vm);
} else {
if (u)
return decodeNeonUThreeFpReg<FminpDX, FminpQX>(
q, size & 0x1, machInst, vd, vn, vm);
else
return decodeNeonUThreeFpReg<FminDX, FminQX>(
q, size & 0x1, machInst, vd, vn, vm);
}
case 0x1f:
if (sz_q == 0x2)
return new Unknown64(machInst);
if (size < 0x2) {
if (u)
return decodeNeonUThreeFpReg<FdivDX, FdivQX>(
q, size & 0x1, machInst, vd, vn, vm);
else
return decodeNeonUThreeFpReg<FrecpsDX, FrecpsQX>(
q, size & 0x1, machInst, vd, vn, vm);
} else {
if (u)
return new Unknown64(machInst);
else
return decodeNeonUThreeFpReg<FrsqrtsDX, FrsqrtsQX>(
q, size & 0x1, machInst, vd, vn, vm);
}
default:
return new Unknown64(machInst);
}
}
StaticInstPtr
decodeNeon3Diff(ExtMachInst machInst)
{
uint8_t q = bits(machInst, 30);
uint8_t u = bits(machInst, 29);
uint8_t size = bits(machInst, 23, 22);
uint8_t opcode = bits(machInst, 15, 12);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16);
switch (opcode) {
case 0x0:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UaddlX, Uaddl2X>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SaddlX, Saddl2X>(
q, size, machInst, vd, vn, vm);
case 0x1:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UaddwX, Uaddw2X>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SaddwX, Saddw2X>(
q, size, machInst, vd, vn, vm);
case 0x2:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UsublX, Usubl2X>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SsublX, Ssubl2X>(
q, size, machInst, vd, vn, vm);
case 0x3:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UsubwX, Usubw2X>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SsubwX, Ssubw2X>(
q, size, machInst, vd, vn, vm);
case 0x4:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<RaddhnX, Raddhn2X>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonUThreeSReg<AddhnX, Addhn2X>(
q, size, machInst, vd, vn, vm);
case 0x5:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UabalX, Uabal2X>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SabalX, Sabal2X>(
q, size, machInst, vd, vn, vm);
case 0x6:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<RsubhnX, Rsubhn2X>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonUThreeSReg<SubhnX, Subhn2X>(
q, size, machInst, vd, vn, vm);
case 0x7:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UabdlX, Uabdl2X>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SabdlX, Sabdl2X>(
q, size, machInst, vd, vn, vm);
case 0x8:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UmlalX, Umlal2X>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SmlalX, Smlal2X>(
q, size, machInst, vd, vn, vm);
case 0x9:
if (u || (size == 0x0 || size == 0x3)) {
return new Unknown64(machInst);
} else {
if (q) {
return decodeNeonSThreeHAndWReg<Sqdmlal2X>(
size, machInst, vd, vn, vm);
} else {
return decodeNeonSThreeHAndWReg<SqdmlalX>(
size, machInst, vd, vn, vm);
}
}
case 0xa:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UmlslX, Umlsl2X>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SmlslX, Smlsl2X>(
q, size, machInst, vd, vn, vm);
case 0xb:
if (u || (size == 0x0 || size == 0x3)) {
return new Unknown64(machInst);
} else {
if (q) {
return decodeNeonSThreeHAndWReg<Sqdmlsl2X>(
size, machInst, vd, vn, vm);
} else {
return decodeNeonSThreeHAndWReg<SqdmlslX>(
size, machInst, vd, vn, vm);
}
}
case 0xc:
if (size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeSReg<UmullX, Umull2X>(
q, size, machInst, vd, vn, vm);
else
return decodeNeonSThreeSReg<SmullX, Smull2X>(
q, size, machInst, vd, vn, vm);
case 0xd:
if (u || (size == 0x0 || size == 0x3)) {
return new Unknown64(machInst);
} else {
if (q) {
return decodeNeonSThreeHAndWReg<Sqdmull2X>(
size, machInst, vd, vn, vm);
} else {
return decodeNeonSThreeHAndWReg<SqdmullX>(
size, machInst, vd, vn, vm);
}
}
case 0xe:
if (u || size != 0) {
return new Unknown64(machInst);
} else {
if (q)
return new Pmull2X<uint8_t>(machInst, vd, vn, vm);
else
return new PmullX<uint8_t>(machInst, vd, vn, vm);
}
default:
return new Unknown64(machInst);
}
}
StaticInstPtr
decodeNeon2RegMisc(ExtMachInst machInst)
{
uint8_t q = bits(machInst, 30);
uint8_t u = bits(machInst, 29);
uint8_t size = bits(machInst, 23, 22);
uint8_t opcode = bits(machInst, 16, 12);
IntRegIndex vd = (IntRegIndex)(uint8_t)bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5);
uint8_t size_q = (size << 1) | q;
uint8_t sz_q = size_q & 0x3;
uint8_t op = (uint8_t)((bits(machInst, 12) << 1) |
bits(machInst, 29));
uint8_t switchVal = opcode | ((u ? 1 : 0) << 5);
switch (switchVal) {
case 0x00:
if (op + size >= 3)
return new Unknown64(machInst);
return decodeNeonUTwoMiscSReg<Rev64DX, Rev64QX>(
q, size, machInst, vd, vn);
case 0x01:
if (op + size >= 3)
return new Unknown64(machInst);
if (q)
return new Rev16QX<uint8_t>(machInst, vd, vn);
else
return new Rev16DX<uint8_t>(machInst, vd, vn);
case 0x02:
if (size == 0x3)
return new Unknown64(machInst);
return decodeNeonSTwoMiscSReg<SaddlpDX, SaddlpQX>(
q, size, machInst, vd, vn);
case 0x03:
if (size_q == 0x6)
return new Unknown64(machInst);
return decodeNeonUTwoMiscXReg<SuqaddDX, SuqaddQX>(
q, size, machInst, vd, vn);
case 0x04:
if (size == 0x3)
return new Unknown64(machInst);
return decodeNeonSTwoMiscSReg<ClsDX, ClsQX>(
q, size, machInst, vd, vn);
case 0x05:
if (size != 0x0)
return new Unknown64(machInst);
if (q)
return new CntQX<uint8_t>(machInst, vd, vn);
else
return new CntDX<uint8_t>(machInst, vd, vn);
case 0x06:
if (size == 0x3)
return new Unknown64(machInst);
return decodeNeonSTwoMiscSReg<SadalpDX, SadalpQX>(
q, size, machInst, vd, vn);
case 0x07:
if (size_q == 0x6)
return new Unknown64(machInst);
return decodeNeonSTwoMiscXReg<SqabsDX, SqabsQX>(
q, size, machInst, vd, vn);
case 0x08:
if (size_q == 0x6)
return new Unknown64(machInst);
return decodeNeonSTwoMiscXReg<CmgtZeroDX, CmgtZeroQX>(
q, size, machInst, vd, vn);
case 0x09:
if (size_q == 0x6)
return new Unknown64(machInst);
return decodeNeonSTwoMiscXReg<CmeqZeroDX, CmeqZeroQX>(
q, size, machInst, vd, vn);
case 0x0a:
if (size_q == 0x6)
return new Unknown64(machInst);
return decodeNeonSTwoMiscXReg<CmltZeroDX, CmltZeroQX>(
q, size, machInst, vd, vn);
case 0x0b:
if (size_q == 0x6)
return new Unknown64(machInst);
return decodeNeonSTwoMiscXReg<AbsDX, AbsQX>(
q, size, machInst, vd, vn);
case 0x0c:
if (size < 0x2 || sz_q == 0x2)
return new Unknown64(machInst);
return decodeNeonUTwoMiscFpReg<FcmgtZeroDX, FcmgtZeroQX>(
q, size & 0x1, machInst, vd, vn);
case 0x0d:
if (size < 0x2 || sz_q == 0x2)
return new Unknown64(machInst);
return decodeNeonUTwoMiscFpReg<FcmeqZeroDX, FcmeqZeroQX>(
q, size & 0x1, machInst, vd, vn);
case 0x0e:
if (size < 0x2 || sz_q == 0x2)
return new Unknown64(machInst);
return decodeNeonUTwoMiscFpReg<FcmltZeroDX, FcmltZeroQX>(
q, size & 0x1, machInst, vd, vn);
case 0x0f:
if (size < 0x2 || sz_q == 0x2)
return new Unknown64(machInst);
return decodeNeonUTwoMiscFpReg<FabsDX, FabsQX>(
q, size & 0x1, machInst, vd, vn);
case 0x12:
if (size == 0x3)
return new Unknown64(machInst);
return decodeNeonUTwoMiscSReg<XtnX, Xtn2X>(
q, size, machInst, vd, vn);
case 0x14:
if (size == 0x3)
return new Unknown64(machInst);
return decodeNeonSTwoMiscSReg<SqxtnX, Sqxtn2X>(
q, size, machInst, vd, vn);
case 0x16:
if (size > 0x1)
return new Unknown64(machInst);
if (q) {
if (size)
return new Fcvtn2X<uint32_t>(machInst, vd, vn);
else
return new Fcvtn2X<uint16_t>(machInst, vd, vn);
} else {
if (size)
return new FcvtnX<uint32_t>(machInst, vd, vn);
else
return new FcvtnX<uint16_t>(machInst, vd, vn);
}
case 0x17:
if (size > 0x1)
return new Unknown64(machInst);
if (q) {
if (size)
return new Fcvtl2X<uint32_t>(machInst, vd, vn);
else
return new Fcvtl2X<uint16_t>(machInst, vd, vn);
} else {
if (size)
return new FcvtlX<uint32_t>(machInst, vd, vn);
else
return new FcvtlX<uint16_t>(machInst, vd, vn);
}
case 0x18:
if (sz_q == 0x2)
return new Unknown64(machInst);
if (size < 0x2)
return decodeNeonUTwoMiscFpReg<FrintnDX, FrintnQX>(
q, size & 0x1, machInst, vd, vn);
else
return decodeNeonUTwoMiscFpReg<FrintpDX, FrintpQX>(
q, size & 0x1, machInst, vd, vn);
case 0x19:
if (sz_q == 0x2)
return new Unknown64(machInst);
if (size < 0x2)
return decodeNeonUTwoMiscFpReg<FrintmDX, FrintmQX>(
q, size & 0x1, machInst, vd, vn);
else
return decodeNeonUTwoMiscFpReg<FrintzDX, FrintzQX>(
q, size & 0x1, machInst, vd, vn);
case 0x1a:
if (sz_q == 0x2)
return new Unknown64(machInst);
if (size < 0x2)
return decodeNeonUTwoMiscFpReg<FcvtnsDX, FcvtnsQX>(
q, size & 0x1, machInst, vd, vn);
else
return decodeNeonUTwoMiscFpReg<FcvtpsDX, FcvtpsQX>(
q, size & 0x1, machInst, vd, vn);
case 0x1b:
if (sz_q == 0x2)
return new Unknown64(machInst);
if (size < 0x2)
return decodeNeonUTwoMiscFpReg<FcvtmsDX, FcvtmsQX>(
q, size & 0x1, machInst, vd, vn);
else
return decodeNeonUTwoMiscFpReg<FcvtzsIntDX, FcvtzsIntQX>(
q, size & 0x1, machInst, vd, vn);
case 0x1c:
if (size < 0x2) {
if (sz_q == 0x2)
return new Unknown64(machInst);
return decodeNeonUTwoMiscFpReg<FcvtasDX, FcvtasQX>(
q, size & 0x1, machInst, vd, vn);
} else {
if (size & 0x1)
return new Unknown64(machInst);
if (q)
return new UrecpeQX<uint32_t>(machInst, vd, vn);
else
return new UrecpeDX<uint32_t>(machInst, vd, vn);
}
case 0x1d:
if (sz_q == 0x2)
return new Unknown64(machInst);
if (size < 0x2) {
if (q) {
if (size & 0x1)
return new ScvtfIntDQX<uint64_t>(machInst, vd, vn);
else
return new ScvtfIntSQX<uint32_t>(machInst, vd, vn);
} else {
if (size & 0x1)
return new Unknown(machInst);
else
return new ScvtfIntDX<uint32_t>(machInst, vd, vn);
}
} else {
return decodeNeonUTwoMiscFpReg<FrecpeDX, FrecpeQX>(
q, size & 0x1, machInst, vd, vn);
}
case 0x20:
if (op + size >= 3)
return new Unknown64(machInst);
if (q) {
if (size & 0x1)
return new Rev32QX<uint16_t>(machInst, vd, vn);
else
return new Rev32QX<uint8_t>(machInst, vd, vn);
} else {
if (size & 0x1)
return new Rev32DX<uint16_t>(machInst, vd, vn);
else
return new Rev32DX<uint8_t>(machInst, vd, vn);
}
case 0x22:
if (size == 0x3)
return new Unknown64(machInst);
return decodeNeonUTwoMiscSReg<UaddlpDX, UaddlpQX>(
q, size, machInst, vd, vn);
case 0x23:
if (size_q == 0x6)
return new Unknown64(machInst);
return decodeNeonUTwoMiscXReg<UsqaddDX, UsqaddQX>(
q, size, machInst, vd, vn);
return new Unknown64(machInst);
case 0x24:
if (size == 0x3)
return new Unknown64(machInst);
return decodeNeonSTwoMiscSReg<ClzDX, ClzQX>(
q, size, machInst, vd, vn);
case 0x25:
if (size == 0x0) {
if (q)
return new MvnQX<uint64_t>(machInst, vd, vn);
else
return new MvnDX<uint64_t>(machInst, vd, vn);
} else if (size == 0x1) {
if (q)
return new RbitQX<uint8_t>(machInst, vd, vn);
else
return new RbitDX<uint8_t>(machInst, vd, vn);
} else {
return new Unknown64(machInst);
}
case 0x26:
if (size == 0x3)
return new Unknown64(machInst);
return decodeNeonUTwoMiscSReg<UadalpDX, UadalpQX>(
q, size, machInst, vd, vn);
case 0x27:
if (size_q == 0x6)
return new Unknown64(machInst);
return decodeNeonSTwoMiscXReg<SqnegDX, SqnegQX>(
q, size, machInst, vd, vn);
case 0x28:
if (size_q == 0x6)
return new Unknown64(machInst);
return decodeNeonSTwoMiscXReg<CmgeZeroDX, CmgeZeroQX>(
q, size, machInst, vd, vn);
case 0x29:
if (size_q == 0x6)
return new Unknown64(machInst);
return decodeNeonSTwoMiscXReg<CmleZeroDX, CmleZeroQX>(
q, size, machInst, vd, vn);
case 0x2b:
if (size_q == 0x6)
return new Unknown64(machInst);
return decodeNeonSTwoMiscXReg<NegDX, NegQX>(
q, size, machInst, vd, vn);
case 0x2c:
if (size < 0x2 || sz_q == 0x2)
return new Unknown64(machInst);
return decodeNeonUTwoMiscFpReg<FcmgeZeroDX, FcmgeZeroQX>(
q, size & 0x1, machInst, vd, vn);
case 0x2d:
if (size < 0x2 || sz_q == 0x2)
return new Unknown64(machInst);
return decodeNeonUTwoMiscFpReg<FcmleZeroDX, FcmleZeroQX>(
q, size & 0x1, machInst, vd, vn);
case 0x2f:
if (size < 0x2 || size_q == 0x6)
return new Unknown64(machInst);
return decodeNeonUTwoMiscFpReg<FnegDX, FnegQX>(
q, size & 0x1, machInst, vd, vn);
case 0x32:
if (size == 0x3)
return new Unknown64(machInst);
return decodeNeonSTwoMiscSReg<SqxtunX, Sqxtun2X>(
q, size, machInst, vd, vn);
case 0x33:
if (size == 0x3)
return new Unknown64(machInst);
return decodeNeonUTwoMiscSReg<ShllX, Shll2X>(
q, size, machInst, vd, vn);
case 0x34:
if (size == 0x3)
return new Unknown64(machInst);
return decodeNeonUTwoMiscSReg<UqxtnX, Uqxtn2X>(
q, size, machInst, vd, vn);
case 0x36:
if (size != 0x1)
return new Unknown64(machInst);
if (q)
return new Fcvtxn2X<uint32_t>(machInst, vd, vn);
else
return new FcvtxnX<uint32_t>(machInst, vd, vn);
case 0x38:
if (size > 0x1 || sz_q == 0x2)
return new Unknown64(machInst);
return decodeNeonUTwoMiscFpReg<FrintaDX, FrintaQX>(
q, size & 0x1, machInst, vd, vn);
case 0x39:
if (sz_q == 0x2)
return new Unknown64(machInst);
if (size < 0x2)
return decodeNeonUTwoMiscFpReg<FrintxDX, FrintxQX>(
q, size & 0x1, machInst, vd, vn);
else
return decodeNeonUTwoMiscFpReg<FrintiDX, FrintiQX>(
q, size & 0x1, machInst, vd, vn);
case 0x3a:
if (sz_q == 0x2)
return new Unknown64(machInst);
if (size < 0x2)
return decodeNeonUTwoMiscFpReg<FcvtnuDX, FcvtnuQX>(
q, size & 0x1, machInst, vd, vn);
else
return decodeNeonUTwoMiscFpReg<FcvtpuDX, FcvtpuQX>(
q, size & 0x1, machInst, vd, vn);
case 0x3b:
if (sz_q == 0x2)
return new Unknown64(machInst);
if (size < 0x2)
return decodeNeonUTwoMiscFpReg<FcvtmuDX, FcvtmuQX>(
q, size & 0x1, machInst, vd, vn);
else
return decodeNeonUTwoMiscFpReg<FcvtzuIntDX, FcvtzuIntQX>(
q, size & 0x1, machInst, vd, vn);
case 0x3c:
if (size < 0x2) {
return decodeNeonUTwoMiscFpReg<FcvtauDX, FcvtauQX>(
q, size & 0x1, machInst, vd, vn);
} else if (size == 0x2) {
if (q)
return new UrsqrteQX<uint32_t>(machInst, vd, vn);
else
return new UrsqrteDX<uint32_t>(machInst, vd, vn);
} else {
return new Unknown64(machInst);
}
case 0x3d:
if (sz_q == 0x2)
return new Unknown64(machInst);
if (size < 0x2)
return decodeNeonUTwoMiscFpReg<UcvtfIntDX, UcvtfIntQX>(
q, size & 0x1, machInst, vd, vn);
else
return decodeNeonUTwoMiscFpReg<FrsqrteDX, FrsqrteQX>(
q, size & 0x1, machInst, vd, vn);
case 0x3f:
if (size < 0x2 || sz_q == 0x2)
return new Unknown64(machInst);
return decodeNeonUTwoMiscFpReg<FsqrtDX, FsqrtQX>(
q, size & 0x1, machInst, vd, vn);
default:
return new Unknown64(machInst);
}
}
StaticInstPtr
decodeNeonAcrossLanes(ExtMachInst machInst)
{
uint8_t q = bits(machInst, 30);
uint8_t u = bits(machInst, 29);
uint8_t size = bits(machInst, 23, 22);
uint8_t opcode = bits(machInst, 16, 12);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
uint8_t size_q = (size << 1) | q;
uint8_t sz_q = size_q & 0x3;
uint8_t switchVal = opcode | ((u ? 1 : 0) << 5);
switch (switchVal) {
case 0x03:
if (size_q == 0x4 || size == 0x3)
return new Unknown64(machInst);
return decodeNeonSAcrossLanesLongReg<SaddlvDX, SaddlvQX,
SaddlvBQX>(
q, size, machInst, vd, vn);
case 0x0a:
if (size_q == 0x4 || size == 0x3)
return new Unknown64(machInst);
return decodeNeonSAcrossLanesReg<SmaxvDX, SmaxvQX>(
q, size, machInst, vd, vn);
case 0x1a:
if (size_q == 0x4 || size == 0x3)
return new Unknown64(machInst);
return decodeNeonSAcrossLanesReg<SminvDX, SminvQX>(
q, size, machInst, vd, vn);
case 0x1b:
if (size_q == 0x4 || size == 0x3)
return new Unknown64(machInst);
return decodeNeonUAcrossLanesReg<AddvDX, AddvQX>(
q, size, machInst, vd, vn);
case 0x23:
if (size_q == 0x4 || size == 0x3)
return new Unknown64(machInst);
return decodeNeonUAcrossLanesLongReg<UaddlvDX, UaddlvQX,
UaddlvBQX>(
q, size, machInst, vd, vn);
case 0x2a:
if (size_q == 0x4 || size == 0x3)
return new Unknown64(machInst);
return decodeNeonUAcrossLanesReg<UmaxvDX, UmaxvQX>(
q, size, machInst, vd, vn);
case 0x2c:
if (sz_q != 0x1)
return new Unknown64(machInst);
if (size < 0x2) {
if (q)
return new FmaxnmvQX<uint32_t>(machInst, vd, vn);
else
return new Unknown64(machInst);
} else {
if (q)
return new FminnmvQX<uint32_t>(machInst, vd, vn);
else
return new Unknown64(machInst);
}
case 0x2f:
if (sz_q != 0x1)
return new Unknown64(machInst);
if (size < 0x2) {
if (q)
return new FmaxvQX<uint32_t>(machInst, vd, vn);
else
return new Unknown64(machInst);
} else {
if (q)
return new FminvQX<uint32_t>(machInst, vd, vn);
else
return new Unknown64(machInst);
}
case 0x3a:
if (size_q == 0x4 || size == 0x3)
return new Unknown64(machInst);
return decodeNeonUAcrossLanesReg<UminvDX, UminvQX>(
q, size, machInst, vd, vn);
default:
return new Unknown64(machInst);
}
}
StaticInstPtr
decodeNeonCopy(ExtMachInst machInst)
{
uint8_t q = bits(machInst, 30);
uint8_t op = bits(machInst, 29);
uint8_t imm5 = bits(machInst, 20, 16);
uint8_t imm4 = bits(machInst, 14, 11);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
uint8_t imm5_pos = findLsbSet(imm5);
uint8_t index1 = 0, index2 = 0;
if (op) {
if (!q || (imm4 & mask(imm5_pos)))
return new Unknown64(machInst);
index1 = bits(imm5, 4, imm5_pos + 1); // dst
index2 = bits(imm4, 3, imm5_pos); // src
switch (imm5_pos) {
case 0:
return new InsElemX<uint8_t>(machInst, vd, vn, index1, index2);
case 1:
return new InsElemX<uint16_t>(machInst, vd, vn, index1, index2);
case 2:
return new InsElemX<uint32_t>(machInst, vd, vn, index1, index2);
case 3:
return new InsElemX<uint64_t>(machInst, vd, vn, index1, index2);
default:
return new Unknown64(machInst);
}
}
switch (imm4) {
case 0x0:
index1 = bits(imm5, 4, imm5_pos + 1);
switch (imm5_pos) {
case 0:
if (q)
return new DupElemQX<uint8_t>(machInst, vd, vn, index1);
else
return new DupElemDX<uint8_t>(machInst, vd, vn, index1);
case 1:
if (q)
return new DupElemQX<uint16_t>(machInst, vd, vn, index1);
else
return new DupElemDX<uint16_t>(machInst, vd, vn, index1);
case 2:
if (q)
return new DupElemQX<uint32_t>(machInst, vd, vn, index1);
else
return new DupElemDX<uint32_t>(machInst, vd, vn, index1);
case 3:
if (q)
return new DupElemQX<uint64_t>(machInst, vd, vn, index1);
else
return new Unknown64(machInst);
default:
return new Unknown64(machInst);
}
case 0x1:
switch (imm5) {
case 0x1:
if (q)
return new DupGprWQX<uint8_t>(machInst, vd, vn);
else
return new DupGprWDX<uint8_t>(machInst, vd, vn);
case 0x2:
if (q)
return new DupGprWQX<uint16_t>(machInst, vd, vn);
else
return new DupGprWDX<uint16_t>(machInst, vd, vn);
case 0x4:
if (q)
return new DupGprWQX<uint32_t>(machInst, vd, vn);
else
return new DupGprWDX<uint32_t>(machInst, vd, vn);
case 0x8:
if (q)
return new DupGprXQX<uint64_t>(machInst, vd, vn);
else
return new Unknown64(machInst);
}
case 0x3:
index1 = imm5 >> (imm5_pos + 1);
switch (imm5_pos) {
case 0:
return new InsGprWX<uint8_t>(machInst, vd, vn, index1);
case 1:
return new InsGprWX<uint16_t>(machInst, vd, vn, index1);
case 2:
return new InsGprWX<uint32_t>(machInst, vd, vn, index1);
case 3:
return new InsGprXX<uint64_t>(machInst, vd, vn, index1);
default:
return new Unknown64(machInst);
}
case 0x5:
index1 = bits(imm5, 4, imm5_pos + 1);
switch (imm5_pos) {
case 0:
if (q)
return new SmovXX<int8_t>(machInst, vd, vn, index1);
else
return new SmovWX<int8_t>(machInst, vd, vn, index1);
case 1:
if (q)
return new SmovXX<int16_t>(machInst, vd, vn, index1);
else
return new SmovWX<int16_t>(machInst, vd, vn, index1);
case 2:
if (q)
return new SmovXX<int32_t>(machInst, vd, vn, index1);
else
return new Unknown64(machInst);
default:
return new Unknown64(machInst);
}
case 0x7:
index1 = imm5 >> (imm5_pos + 1);
if ((q && imm5_pos != 3) || (!q && imm5_pos >= 3))
return new Unknown64(machInst);
switch (imm5_pos) {
case 0:
return new UmovWX<uint8_t>(machInst, vd, vn, index1);
case 1:
return new UmovWX<uint16_t>(machInst, vd, vn, index1);
case 2:
return new UmovWX<uint32_t>(machInst, vd, vn, index1);
case 3:
return new UmovXX<uint64_t>(machInst, vd, vn, index1);
default:
return new Unknown64(machInst);
}
default:
return new Unknown64(machInst);
}
}
template <typename DecoderFeatures>
StaticInstPtr
decodeNeonIndexedElem(ExtMachInst machInst)
{
uint8_t q = bits(machInst, 30);
uint8_t u = bits(machInst, 29);
uint8_t size = bits(machInst, 23, 22);
uint8_t L = bits(machInst, 21);
uint8_t M = bits(machInst, 20);
uint8_t opcode = bits(machInst, 15, 12);
uint8_t H = bits(machInst, 11);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
IntRegIndex vm_bf = (IntRegIndex) (uint8_t) bits(machInst, 19, 16);
uint8_t index = 0;
uint8_t index_fp = 0;
uint8_t vmh = 0;
uint8_t sz = size & 0x1;
uint8_t sz_q = (sz << 1) | bits(machInst, 30);
uint8_t sz_L = (sz << 1) | L;
// Index and 2nd register operand for integer instructions
if (size == 0x1) {
index = (H << 2) | (L << 1) | M;
// vmh = 0;
} else if (size == 0x2) {
index = (H << 1) | L;
vmh = M;
}
IntRegIndex vm = (IntRegIndex) (uint8_t) (vmh << 4 | vm_bf);
// Index and 2nd register operand for FP instructions
vmh = M;
if ((size & 0x1) == 0) {
index_fp = (H << 1) | L;
} else if (L == 0) {
index_fp = H;
}
IntRegIndex vm_fp = (IntRegIndex) (uint8_t) (vmh << 4 | vm_bf);
switch (opcode) {
case 0x0:
if (!u || (size == 0x0 || size == 0x3))
return new Unknown64(machInst);
else
return decodeNeonUThreeImmHAndWReg<MlaElemDX, MlaElemQX>(
q, size, machInst, vd, vn, vm, index);
case 0x1:
if (!u && size >= 2 && sz_q != 0x2 && sz_L != 0x3)
return decodeNeonUThreeImmFpReg<FmlaElemDX, FmlaElemQX>(
q, sz, machInst, vd, vn, vm_fp, index_fp);
else
return new Unknown64(machInst);
case 0x2:
if (size == 0x0 || size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeImmHAndWReg<UmlalElemX, UmlalElem2X>(
q, size, machInst, vd, vn, vm, index);
else
return decodeNeonSThreeImmHAndWReg<SmlalElemX, SmlalElem2X>(
q, size, machInst, vd, vn, vm, index);
case 0x3:
if (u || (size == 0x0 || size == 0x3))
return new Unknown64(machInst);
else
return decodeNeonSThreeImmHAndWReg<SqdmlalElemX,
SqdmlalElem2X>(
q, size, machInst, vd, vn, vm, index);
case 0x4:
if (u && !(size == 0x0 || size == 0x3))
return decodeNeonUThreeImmHAndWReg<MlsElemDX, MlsElemQX>(
q, size, machInst, vd, vn, vm, index);
else
return new Unknown64(machInst);
case 0x5:
if (!u && size >= 0x2 && sz_L != 0x3 && sz_q != 0x2)
return decodeNeonUThreeImmFpReg<FmlsElemDX, FmlsElemQX>(
q, sz, machInst, vd, vn, vm_fp, index_fp);
else
return new Unknown64(machInst);
case 0x6:
if (size == 0x0 || size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeImmHAndWReg<UmlslElemX, UmlslElem2X>(
q, size, machInst, vd, vn, vm, index);
else
return decodeNeonSThreeImmHAndWReg<SmlslElemX, SmlslElem2X>(
q, size, machInst, vd, vn, vm, index);
case 0x7:
if (u || (size == 0x0 || size == 0x3))
return new Unknown64(machInst);
else
return decodeNeonSThreeImmHAndWReg<SqdmlslElemX,
SqdmlslElem2X>(
q, size, machInst, vd, vn, vm, index);
case 0x8:
if (u || (size == 0x0 || size == 0x3))
return new Unknown64(machInst);
else
return decodeNeonUThreeImmHAndWReg<MulElemDX, MulElemQX>(
q, size, machInst, vd, vn, vm, index);
case 0x9:
if (size >= 2 && sz_q != 0x2 && sz_L != 0x3) {
if (u)
return decodeNeonUThreeImmFpReg<FmulxElemDX, FmulxElemQX>(
q, sz, machInst, vd, vn, vm_fp, index_fp);
else
return decodeNeonUThreeImmFpReg<FmulElemDX, FmulElemQX>(
q, sz, machInst, vd, vn, vm_fp, index_fp);
} else {
return new Unknown64(machInst);
}
case 0xa:
if (size == 0x0 || size == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeImmHAndWReg<UmullElemX, UmullElem2X>(
q, size, machInst, vd, vn, vm, index);
else
return decodeNeonSThreeImmHAndWReg<SmullElemX, SmullElem2X>(
q, size, machInst, vd, vn, vm, index);
case 0xb:
if (u || (size == 0x0 || size == 0x3))
return new Unknown64(machInst);
else
return decodeNeonSThreeImmHAndWReg<SqdmullElemX, SqdmullElem2X>(
q, size, machInst, vd, vn, vm, index);
case 0xc:
if (u || (size == 0x0 || size == 0x3))
return new Unknown64(machInst);
else
return decodeNeonSThreeImmHAndWReg<SqdmulhElemDX, SqdmulhElemQX>(
q, size, machInst, vd, vn, vm, index);
case 0xd:
if (u || (size == 0x0 || size == 0x3))
return new Unknown64(machInst);
else
return decodeNeonSThreeImmHAndWReg<SqrdmulhElemDX, SqrdmulhElemQX>(
q, size, machInst, vd, vn, vm, index);
default:
return new Unknown64(machInst);
}
}
StaticInstPtr
decodeNeonModImm(ExtMachInst machInst)
{
uint8_t q = bits(machInst, 30);
uint8_t op = bits(machInst, 29);
uint8_t abcdefgh = (bits(machInst, 18, 16) << 5) |
bits(machInst, 9, 5);
uint8_t cmode = bits(machInst, 15, 12);
uint8_t o2 = bits(machInst, 11);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
if (o2 == 0x1 || (op == 0x1 && cmode == 0xf && !q))
return new Unknown64(machInst);
bool immValid = true;
const uint64_t bigImm = simd_modified_imm(op, cmode, abcdefgh,
immValid,
true /* isAarch64 */);
if (!immValid) {
return new Unknown(machInst);
}
if (op) {
if (bits(cmode, 3) == 0) {
if (bits(cmode, 0) == 0) {
if (q)
return new MvniQX<uint64_t>(machInst, vd, bigImm);
else
return new MvniDX<uint64_t>(machInst, vd, bigImm);
} else {
if (q)
return new BicImmQX<uint64_t>(machInst, vd, bigImm);
else
return new BicImmDX<uint64_t>(machInst, vd, bigImm);
}
} else {
if (bits(cmode, 2) == 1) {
switch (bits(cmode, 1, 0)) {
case 0:
case 1:
if (q)
return new MvniQX<uint64_t>(machInst, vd, bigImm);
else
return new MvniDX<uint64_t>(machInst, vd, bigImm);
case 2:
if (q)
return new MoviQX<uint64_t>(machInst, vd, bigImm);
else
return new MoviDX<uint64_t>(machInst, vd, bigImm);
case 3:
if (q)
return new FmovQX<uint64_t>(machInst, vd, bigImm);
else
return new MoviDX<uint64_t>(machInst, vd, bigImm);
}
} else {
if (bits(cmode, 0) == 0) {
if (q)
return new MvniQX<uint64_t>(machInst, vd, bigImm);
else
return new MvniDX<uint64_t>(machInst, vd, bigImm);
} else {
if (q)
return new BicImmQX<uint64_t>(machInst, vd,
bigImm);
else
return new BicImmDX<uint64_t>(machInst, vd,
bigImm);
}
}
}
} else {
if (bits(cmode, 3) == 0) {
if (bits(cmode, 0) == 0) {
if (q)
return new MoviQX<uint64_t>(machInst, vd, bigImm);
else
return new MoviDX<uint64_t>(machInst, vd, bigImm);
} else {
if (q)
return new OrrImmQX<uint64_t>(machInst, vd, bigImm);
else
return new OrrImmDX<uint64_t>(machInst, vd, bigImm);
}
} else {
if (bits(cmode, 2) == 1) {
if (bits(cmode, 1, 0) == 0x3) {
if (q)
return new FmovQX<uint32_t>(machInst, vd, bigImm);
else
return new FmovDX<uint32_t>(machInst, vd, bigImm);
} else {
if (q)
return new MoviQX<uint64_t>(machInst, vd, bigImm);
else
return new MoviDX<uint64_t>(machInst, vd, bigImm);
}
} else {
if (bits(cmode, 0) == 0) {
if (q)
return new MoviQX<uint64_t>(machInst, vd, bigImm);
else
return new MoviDX<uint64_t>(machInst, vd, bigImm);
} else {
if (q)
return new OrrImmQX<uint64_t>(machInst, vd,
bigImm);
else
return new OrrImmDX<uint64_t>(machInst, vd, bigImm);
}
}
}
}
return new Unknown(machInst);
}
StaticInstPtr
decodeNeonShiftByImm(ExtMachInst machInst)
{
uint8_t q = bits(machInst, 30);
uint8_t u = bits(machInst, 29);
uint8_t immh = bits(machInst, 22, 19);
uint8_t immb = bits(machInst, 18, 16);
uint8_t opcode = bits(machInst, 15, 11);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
uint8_t immh3 = bits(machInst, 22);
uint8_t immh3_q = (immh3 << 1) | q;
uint8_t op_u = (bits(machInst, 12) << 1) | u;
uint8_t size = findMsbSet(immh);
int shiftAmt = 0;
switch (opcode) {
case 0x00:
if (immh3_q == 0x2)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return decodeNeonUTwoShiftXReg<UshrDX, UshrQX>(
q, size, machInst, vd, vn, shiftAmt);
else
return decodeNeonSTwoShiftXReg<SshrDX, SshrQX>(
q, size, machInst, vd, vn, shiftAmt);
case 0x02:
if (immh3_q == 0x2)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return decodeNeonUTwoShiftXReg<UsraDX, UsraQX>(
q, size, machInst, vd, vn, shiftAmt);
else
return decodeNeonSTwoShiftXReg<SsraDX, SsraQX>(
q, size, machInst, vd, vn, shiftAmt);
case 0x04:
if (immh3_q == 0x2)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return decodeNeonUTwoShiftXReg<UrshrDX, UrshrQX>(
q, size, machInst, vd, vn, shiftAmt);
else
return decodeNeonSTwoShiftXReg<SrshrDX, SrshrQX>(
q, size, machInst, vd, vn, shiftAmt);
case 0x06:
if (immh3_q == 0x2)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return decodeNeonUTwoShiftXReg<UrsraDX, UrsraQX>(
q, size, machInst, vd, vn, shiftAmt);
else
return decodeNeonSTwoShiftXReg<SrsraDX, SrsraQX>(
q, size, machInst, vd, vn, shiftAmt);
case 0x08:
if (u && !(immh3_q == 0x2)) {
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
return decodeNeonUTwoShiftXReg<SriDX, SriQX>(
q, size, machInst, vd, vn, shiftAmt);
} else {
return new Unknown64(machInst);
}
case 0x0a:
if (immh3_q == 0x2)
return new Unknown64(machInst);
shiftAmt = ((immh << 3) | immb) - (8 << size);
if (u)
return decodeNeonUTwoShiftXReg<SliDX, SliQX>(
q, size, machInst, vd, vn, shiftAmt);
else
return decodeNeonUTwoShiftXReg<ShlDX, ShlQX>(
q, size, machInst, vd, vn, shiftAmt);
case 0x0c:
if (u && !(immh3_q == 0x2 || op_u == 0x0)) {
shiftAmt = ((immh << 3) | immb) - (8 << size);
return decodeNeonSTwoShiftXReg<SqshluDX, SqshluQX>(
q, size, machInst, vd, vn, shiftAmt);
} else {
return new Unknown64(machInst);
}
case 0x0e:
if (immh3_q == 0x2 || op_u == 0x0)
return new Unknown64(machInst);
shiftAmt = ((immh << 3) | immb) - (8 << size);
if (u)
return decodeNeonUTwoShiftXReg<UqshlImmDX, UqshlImmQX>(
q, size, machInst, vd, vn, shiftAmt);
else
return decodeNeonSTwoShiftXReg<SqshlImmDX, SqshlImmQX>(
q, size, machInst, vd, vn, shiftAmt);
case 0x10:
if (immh3)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return decodeNeonSTwoShiftSReg<SqshrunX, Sqshrun2X>(
q, size, machInst, vd, vn, shiftAmt);
else
return decodeNeonUTwoShiftSReg<ShrnX, Shrn2X>(
q, size, machInst, vd, vn, shiftAmt);
case 0x11:
if (immh3)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return decodeNeonSTwoShiftSReg<SqrshrunX, Sqrshrun2X>(
q, size, machInst, vd, vn, shiftAmt);
else
return decodeNeonUTwoShiftSReg<RshrnX, Rshrn2X>(
q, size, machInst, vd, vn, shiftAmt);
case 0x12:
if (immh3)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return decodeNeonUTwoShiftSReg<UqshrnX, Uqshrn2X>(
q, size, machInst, vd, vn, shiftAmt);
else
return decodeNeonSTwoShiftSReg<SqshrnX, Sqshrn2X>(
q, size, machInst, vd, vn, shiftAmt);
case 0x13:
if (immh3)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return decodeNeonUTwoShiftSReg<UqrshrnX, Uqrshrn2X>(
q, size, machInst, vd, vn, shiftAmt);
else
return decodeNeonSTwoShiftSReg<SqrshrnX, Sqrshrn2X>(
q, size, machInst, vd, vn, shiftAmt);
case 0x14:
if (immh3)
return new Unknown64(machInst);
shiftAmt = ((immh << 3) | immb) - (8 << size);
if (u)
return decodeNeonUTwoShiftSReg<UshllX, Ushll2X>(
q, size, machInst, vd, vn, shiftAmt);
else
return decodeNeonSTwoShiftSReg<SshllX, Sshll2X>(
q, size, machInst, vd, vn, shiftAmt);
case 0x1c:
if (immh < 0x4 || immh3_q == 0x2)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u) {
return decodeNeonUTwoShiftFpReg<UcvtfFixedDX, UcvtfFixedQX>(
q, size & 0x1, machInst, vd, vn, shiftAmt);
} else {
if (q) {
if (size & 0x1)
return new ScvtfFixedDQX<uint64_t>(machInst, vd, vn,
shiftAmt);
else
return new ScvtfFixedSQX<uint32_t>(machInst, vd, vn,
shiftAmt);
} else {
if (size & 0x1)
return new Unknown(machInst);
else
return new ScvtfFixedDX<uint32_t>(machInst, vd, vn,
shiftAmt);
}
}
case 0x1f:
if (immh < 0x4 || immh3_q == 0x2)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return decodeNeonUTwoShiftFpReg<FcvtzuFixedDX, FcvtzuFixedQX>(
q, size & 0x1, machInst, vd, vn, shiftAmt);
else
return decodeNeonUTwoShiftFpReg<FcvtzsFixedDX, FcvtzsFixedQX>(
q, size & 0x1, machInst, vd, vn, shiftAmt);
default:
return new Unknown64(machInst);
}
}
StaticInstPtr
decodeNeonTblTbx(ExtMachInst machInst)
{
uint8_t q = bits(machInst, 30);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16);
uint8_t switchVal = bits(machInst, 14, 12);
switch (switchVal) {
case 0x0:
if (q)
return new Tbl1QX<uint8_t>(machInst, vd, vn, vm);
else
return new Tbl1DX<uint8_t>(machInst, vd, vn, vm);
case 0x1:
if (q)
return new Tbx1QX<uint8_t>(machInst, vd, vn, vm);
else
return new Tbx1DX<uint8_t>(machInst, vd, vn, vm);
case 0x2:
if (q)
return new Tbl2QX<uint8_t>(machInst, vd, vn, vm);
else
return new Tbl2DX<uint8_t>(machInst, vd, vn, vm);
case 0x3:
if (q)
return new Tbx2QX<uint8_t>(machInst, vd, vn, vm);
else
return new Tbx2DX<uint8_t>(machInst, vd, vn, vm);
case 0x4:
if (q)
return new Tbl3QX<uint8_t>(machInst, vd, vn, vm);
else
return new Tbl3DX<uint8_t>(machInst, vd, vn, vm);
case 0x5:
if (q)
return new Tbx3QX<uint8_t>(machInst, vd, vn, vm);
else
return new Tbx3DX<uint8_t>(machInst, vd, vn, vm);
case 0x6:
if (q)
return new Tbl4QX<uint8_t>(machInst, vd, vn, vm);
else
return new Tbl4DX<uint8_t>(machInst, vd, vn, vm);
case 0x7:
if (q)
return new Tbx4QX<uint8_t>(machInst, vd, vn, vm);
else
return new Tbx4DX<uint8_t>(machInst, vd, vn, vm);
default:
return new Unknown64(machInst);
}
return new Unknown64(machInst);
}
StaticInstPtr
decodeNeonZipUzpTrn(ExtMachInst machInst)
{
uint8_t q = bits(machInst, 30);
uint8_t size = bits(machInst, 23, 22);
uint8_t opcode = bits(machInst, 14, 12);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16);
switch (opcode) {
case 0x1:
return decodeNeonUThreeXReg<Uzp1DX, Uzp1QX>(
q, size, machInst, vd, vn, vm);
case 0x2:
return decodeNeonUThreeXReg<Trn1DX, Trn1QX>(
q, size, machInst, vd, vn, vm);
case 0x3:
return decodeNeonUThreeXReg<Zip1DX, Zip1QX>(
q, size, machInst, vd, vn, vm);
case 0x5:
return decodeNeonUThreeXReg<Uzp2DX, Uzp2QX>(
q, size, machInst, vd, vn, vm);
case 0x6:
return decodeNeonUThreeXReg<Trn2DX, Trn2QX>(
q, size, machInst, vd, vn, vm);
case 0x7:
return decodeNeonUThreeXReg<Zip2DX, Zip2QX>(
q, size, machInst, vd, vn, vm);
default:
return new Unknown64(machInst);
}
return new Unknown64(machInst);
}
StaticInstPtr
decodeNeonExt(ExtMachInst machInst)
{
uint8_t q = bits(machInst, 30);
uint8_t op2 = bits(machInst, 23, 22);
uint8_t imm4 = bits(machInst, 14, 11);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16);
if (op2 != 0 || (q == 0x0 && bits(imm4, 3) == 0x1))
return new Unknown64(machInst);
uint8_t index = q ? imm4 : imm4 & 0x7;
if (q) {
return new ExtQX<uint8_t>(machInst, vd, vn, vm, index);
} else {
return new ExtDX<uint8_t>(machInst, vd, vn, vm, index);
}
}
StaticInstPtr
decodeNeonSc3Same(ExtMachInst machInst)
{
uint8_t u = bits(machInst, 29);
uint8_t size = bits(machInst, 23, 22);
uint8_t opcode = bits(machInst, 15, 11);
uint8_t s = bits(machInst, 11);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16);
switch (opcode) {
case 0x01:
if (u)
return decodeNeonUThreeUReg<UqaddScX>(
size, machInst, vd, vn, vm);
else
return decodeNeonSThreeUReg<SqaddScX>(
size, machInst, vd, vn, vm);
case 0x05:
if (u)
return decodeNeonUThreeUReg<UqsubScX>(
size, machInst, vd, vn, vm);
else
return decodeNeonSThreeUReg<SqsubScX>(
size, machInst, vd, vn, vm);
case 0x06:
if (size != 0x3)
return new Unknown64(machInst);
if (u)
return new CmhiDX<uint64_t>(machInst, vd, vn, vm);
else
return new CmgtDX<int64_t>(machInst, vd, vn, vm);
case 0x07:
if (size != 0x3)
return new Unknown64(machInst);
if (u)
return new CmhsDX<uint64_t>(machInst, vd, vn, vm);
else
return new CmgeDX<int64_t>(machInst, vd, vn, vm);
case 0x08:
if (!s && size != 0x3)
return new Unknown64(machInst);
if (u)
return new UshlDX<uint64_t>(machInst, vd, vn, vm);
else
return new SshlDX<int64_t>(machInst, vd, vn, vm);
case 0x09:
if (!s && size != 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeUReg<UqshlScX>(
size, machInst, vd, vn, vm);
else
return decodeNeonSThreeUReg<SqshlScX>(
size, machInst, vd, vn, vm);
case 0x0a:
if (!s && size != 0x3)
return new Unknown64(machInst);
if (u)
return new UrshlDX<uint64_t>(machInst, vd, vn, vm);
else
return new SrshlDX<int64_t>(machInst, vd, vn, vm);
case 0x0b:
if (!s && size != 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeUReg<UqrshlScX>(
size, machInst, vd, vn, vm);
else
return decodeNeonSThreeUReg<SqrshlScX>(
size, machInst, vd, vn, vm);
case 0x10:
if (size != 0x3)
return new Unknown64(machInst);
if (u)
return new SubDX<uint64_t>(machInst, vd, vn, vm);
else
return new AddDX<uint64_t>(machInst, vd, vn, vm);
case 0x11:
if (size != 0x3)
return new Unknown64(machInst);
if (u)
return new CmeqDX<uint64_t>(machInst, vd, vn, vm);
else
return new CmtstDX<uint64_t>(machInst, vd, vn, vm);
case 0x16:
if (size == 0x3 || size == 0x0)
return new Unknown64(machInst);
if (u)
return decodeNeonSThreeHAndWReg<SqrdmulhScX>(
size, machInst, vd, vn, vm);
else
return decodeNeonSThreeHAndWReg<SqdmulhScX>(
size, machInst, vd, vn, vm);
case 0x1a:
if (!u || size < 0x2)
return new Unknown64(machInst);
else
return decodeNeonUThreeScFpReg<FabdScX>(
size & 0x1, machInst, vd, vn, vm);
case 0x1b:
if (u || size > 0x1)
return new Unknown64(machInst);
else
return decodeNeonUThreeScFpReg<FmulxScX>(
size & 0x1, machInst, vd, vn, vm);
case 0x1c:
if (size < 0x2) {
if (u)
return decodeNeonUThreeScFpReg<FcmgeScX>(
size & 0x1, machInst, vd, vn, vm);
else
return decodeNeonUThreeScFpReg<FcmeqScX>(
size & 0x1, machInst, vd, vn, vm);
} else {
if (u)
return decodeNeonUThreeScFpReg<FcmgtScX>(
size & 0x1, machInst, vd, vn, vm);
else
return new Unknown64(machInst);
}
case 0x1d:
if (!u)
return new Unknown64(machInst);
if (size < 0x2)
return decodeNeonUThreeScFpReg<FacgeScX>(
size & 0x1, machInst, vd, vn, vm);
else
return decodeNeonUThreeScFpReg<FacgtScX>(
size & 0x1, machInst, vd, vn, vm);
case 0x1f:
if (u)
return new Unknown64(machInst);
if (size < 0x2)
return decodeNeonUThreeScFpReg<FrecpsScX>(
size & 0x1, machInst, vd, vn, vm);
else
return decodeNeonUThreeScFpReg<FrsqrtsScX>(
size & 0x1, machInst, vd, vn, vm);
default:
return new Unknown64(machInst);
}
}
StaticInstPtr
decodeNeonSc3Diff(ExtMachInst machInst)
{
if (bits(machInst, 29))
return new Unknown64(machInst);
uint8_t size = bits(machInst, 23, 22);
if (size == 0x0 || size == 0x3)
return new Unknown64(machInst);
uint8_t opcode = bits(machInst, 15, 12);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16);
switch (opcode) {
case 0x9:
return decodeNeonSThreeHAndWReg<SqdmlalScX>(size, machInst, vd, vn, vm);
case 0xb:
return decodeNeonSThreeHAndWReg<SqdmlslScX>(size, machInst, vd, vn, vm);
case 0xd:
return decodeNeonSThreeHAndWReg<SqdmullScX>(size, machInst, vd, vn, vm);
default:
return new Unknown64(machInst);
}
}
StaticInstPtr
decodeNeonSc2RegMisc(ExtMachInst machInst)
{
uint8_t u = bits(machInst, 29);
uint8_t size = bits(machInst, 23, 22);
uint8_t opcode = bits(machInst, 16, 12);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
uint8_t switchVal = opcode | ((u ? 1 : 0) << 5);
switch (switchVal) {
case 0x03:
return decodeNeonUTwoMiscUReg<SuqaddScX>(size, machInst, vd, vn);
case 0x07:
return decodeNeonSTwoMiscUReg<SqabsScX>(size, machInst, vd, vn);
case 0x08:
if (size != 0x3)
return new Unknown64(machInst);
else
return new CmgtZeroDX<int64_t>(machInst, vd, vn);
case 0x09:
if (size != 0x3)
return new Unknown64(machInst);
else
return new CmeqZeroDX<int64_t>(machInst, vd, vn);
case 0x0a:
if (size != 0x3)
return new Unknown64(machInst);
else
return new CmltZeroDX<int64_t>(machInst, vd, vn);
case 0x0b:
if (size != 0x3)
return new Unknown64(machInst);
else
return new AbsDX<int64_t>(machInst, vd, vn);
case 0x0c:
if (size < 0x2)
return new Unknown64(machInst);
else
return decodeNeonUTwoMiscScFpReg<FcmgtZeroScX>(
size & 0x1, machInst, vd, vn);
case 0x0d:
if (size < 0x2)
return new Unknown64(machInst);
else
return decodeNeonUTwoMiscScFpReg<FcmeqZeroScX>(
size & 0x1, machInst, vd, vn);
case 0x0e:
if (size < 0x2)
return new Unknown64(machInst);
else
return decodeNeonUTwoMiscScFpReg<FcmltZeroScX>(
size & 0x1, machInst, vd, vn);
case 0x14:
if (size == 0x3) {
return new Unknown64(machInst);
} else {
switch (size) {
case 0x0:
return new SqxtnScX<int8_t>(machInst, vd, vn);
case 0x1:
return new SqxtnScX<int16_t>(machInst, vd, vn);
case 0x2:
return new SqxtnScX<int32_t>(machInst, vd, vn);
}
}
case 0x1a:
if (size < 0x2)
return decodeNeonUTwoMiscScFpReg<FcvtnsScX>(
size & 0x1, machInst, vd, vn);
else
return decodeNeonUTwoMiscScFpReg<FcvtpsScX>(
size & 0x1, machInst, vd, vn);
case 0x1b:
if (size < 0x2)
return decodeNeonUTwoMiscScFpReg<FcvtmsScX>(
size & 0x1, machInst, vd, vn);
else
return decodeNeonUTwoMiscScFpReg<FcvtzsIntScX>(
size & 0x1, machInst, vd, vn);
case 0x1c:
if (size < 0x2)
return decodeNeonUTwoMiscScFpReg<FcvtasScX>(
size & 0x1, machInst, vd, vn);
else
return new Unknown64(machInst);
case 0x1d:
if (size < 0x2) {
if (size & 0x1)
return new ScvtfIntScDX<uint64_t>(machInst, vd, vn);
else
return new ScvtfIntScSX<uint32_t>(machInst, vd, vn);
} else {
return decodeNeonUTwoMiscScFpReg<FrecpeScX>(
size & 0x1, machInst, vd, vn);
}
case 0x1f:
if (size < 0x2)
return new Unknown64(machInst);
else
return decodeNeonUTwoMiscScFpReg<FrecpxX>(
size & 0x1, machInst, vd, vn);
case 0x23:
return decodeNeonUTwoMiscUReg<UsqaddScX>(size, machInst, vd, vn);
case 0x27:
return decodeNeonSTwoMiscUReg<SqnegScX>(size, machInst, vd, vn);
case 0x28:
if (size != 0x3)
return new Unknown64(machInst);
else
return new CmgeZeroDX<int64_t>(machInst, vd, vn);
case 0x29:
if (size != 0x3)
return new Unknown64(machInst);
else
return new CmleZeroDX<int64_t>(machInst, vd, vn);
case 0x2b:
if (size != 0x3)
return new Unknown64(machInst);
else
return new NegDX<int64_t>(machInst, vd, vn);
case 0x2c:
if (size < 0x2)
return new Unknown64(machInst);
else
return decodeNeonUTwoMiscScFpReg<FcmgeZeroScX>(
size & 0x1, machInst, vd, vn);
case 0x2d:
if (size < 0x2)
return new Unknown64(machInst);
else
return decodeNeonUTwoMiscScFpReg<FcmleZeroScX>(
size & 0x1, machInst, vd, vn);
case 0x32:
if (size == 0x3) {
return new Unknown64(machInst);
} else {
switch (size) {
case 0x0:
return new SqxtunScX<int8_t>(machInst, vd, vn);
case 0x1:
return new SqxtunScX<int16_t>(machInst, vd, vn);
case 0x2:
return new SqxtunScX<int32_t>(machInst, vd, vn);
}
}
case 0x34:
if (size == 0x3) {
return new Unknown64(machInst);
} else {
switch (size) {
case 0x0:
return new UqxtnScX<uint8_t>(machInst, vd, vn);
case 0x1:
return new UqxtnScX<uint16_t>(machInst, vd, vn);
case 0x2:
return new UqxtnScX<uint32_t>(machInst, vd, vn);
}
}
case 0x36:
if (size != 0x1) {
return new Unknown64(machInst);
} else {
return new FcvtxnScX<uint32_t>(machInst, vd, vn);
}
case 0x3a:
if (size < 0x2)
return decodeNeonUTwoMiscScFpReg<FcvtnuScX>(
size & 0x1, machInst, vd, vn);
else
return decodeNeonUTwoMiscScFpReg<FcvtpuScX>(
size & 0x1, machInst, vd, vn);
case 0x3b:
if (size < 0x2)
return decodeNeonUTwoMiscScFpReg<FcvtmuScX>(
size & 0x1, machInst, vd, vn);
else
return decodeNeonUTwoMiscScFpReg<FcvtzuIntScX>(
size & 0x1, machInst, vd, vn);
case 0x3c:
if (size < 0x2)
return decodeNeonUTwoMiscScFpReg<FcvtauScX>(
size & 0x1, machInst, vd, vn);
else
return new Unknown64(machInst);
case 0x3d:
if (size < 0x2)
return decodeNeonUTwoMiscScFpReg<UcvtfIntScX>(
size & 0x1, machInst, vd, vn);
else
return decodeNeonUTwoMiscScFpReg<FrsqrteScX>(
size & 0x1, machInst, vd, vn);
default:
return new Unknown64(machInst);
}
}
StaticInstPtr
decodeNeonScPwise(ExtMachInst machInst)
{
uint8_t u = bits(machInst, 29);
uint8_t size = bits(machInst, 23, 22);
uint8_t opcode = bits(machInst, 16, 12);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
if (!u) {
if (opcode == 0x1b && size == 0x3)
return new AddpScQX<uint64_t>(machInst, vd, vn);
else
return new Unknown64(machInst);
}
uint8_t switchVal = (opcode << 0) | (size << 5);
switch (switchVal) {
case 0x0c:
case 0x2c:
return decodeNeonUTwoMiscPwiseScFpReg<FmaxnmpScDX, FmaxnmpScQX>(
size & 0x1, machInst, vd, vn);
case 0x0d:
case 0x2d:
return decodeNeonUTwoMiscPwiseScFpReg<FaddpScDX, FaddpScQX>(
size & 0x1, machInst, vd, vn);
case 0x0f:
case 0x2f:
return decodeNeonUTwoMiscPwiseScFpReg<FmaxpScDX, FmaxpScQX>(
size & 0x1, machInst, vd, vn);
case 0x4c:
case 0x6c:
return decodeNeonUTwoMiscPwiseScFpReg<FminnmpScDX, FminnmpScQX>(
size & 0x1, machInst, vd, vn);
case 0x4f:
case 0x6f:
return decodeNeonUTwoMiscPwiseScFpReg<FminpScDX, FminpScQX>(
size & 0x1, machInst, vd, vn);
default:
return new Unknown64(machInst);
}
}
StaticInstPtr
decodeNeonScCopy(ExtMachInst machInst)
{
if (bits(machInst, 14, 11) != 0 || bits(machInst, 29))
return new Unknown64(machInst);
uint8_t imm5 = bits(machInst, 20, 16);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
uint8_t size = findLsbSet(imm5);
uint8_t index = bits(imm5, 4, size + 1);
return decodeNeonUTwoShiftUReg<DupElemScX>(
size, machInst, vd, vn, index);
}
StaticInstPtr
decodeNeonScIndexedElem(ExtMachInst machInst)
{
uint8_t u = bits(machInst, 29);
uint8_t size = bits(machInst, 23, 22);
uint8_t L = bits(machInst, 21);
uint8_t M = bits(machInst, 20);
uint8_t opcode = bits(machInst, 15, 12);
uint8_t H = bits(machInst, 11);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
IntRegIndex vm_bf = (IntRegIndex) (uint8_t) bits(machInst, 19, 16);
uint8_t index = 0;
uint8_t index_fp = 0;
uint8_t vmh = 0;
uint8_t sz_L = bits(machInst, 22, 21);
// Index and 2nd register operand for integer instructions
if (size == 0x1) {
index = (H << 2) | (L << 1) | M;
// vmh = 0;
} else if (size == 0x2) {
index = (H << 1) | L;
vmh = M;
} else if (size == 0x3) {
index = H;
vmh = M;
}
IntRegIndex vm = (IntRegIndex) (uint8_t) (vmh << 4 | vm_bf);
// Index and 2nd register operand for FP instructions
vmh = M;
if ((size & 0x1) == 0) {
index_fp = (H << 1) | L;
} else if (L == 0) {
index_fp = H;
}
IntRegIndex vm_fp = (IntRegIndex) (uint8_t) (vmh << 4 | vm_bf);
if (u && opcode != 9)
return new Unknown64(machInst);
switch (opcode) {
case 0x1:
if (size < 2 || sz_L == 0x3)
return new Unknown64(machInst);
else
return decodeNeonUThreeImmScFpReg<FmlaElemScX>(
size & 0x1, machInst, vd, vn, vm_fp, index_fp);
case 0x3:
if (size == 0x0 || size == 0x3)
return new Unknown64(machInst);
else
return decodeNeonSThreeImmHAndWReg<SqdmlalElemScX>(
size, machInst, vd, vn, vm, index);
case 0x5:
if (size < 2 || sz_L == 0x3)
return new Unknown64(machInst);
else
return decodeNeonUThreeImmScFpReg<FmlsElemScX>(
size & 0x1, machInst, vd, vn, vm_fp, index_fp);
case 0x7:
if (size == 0x0 || size == 0x3)
return new Unknown64(machInst);
else
return decodeNeonSThreeImmHAndWReg<SqdmlslElemScX>(
size, machInst, vd, vn, vm, index);
case 0x9:
if (size < 2 || sz_L == 0x3)
return new Unknown64(machInst);
if (u)
return decodeNeonUThreeImmScFpReg<FmulxElemScX>(
size & 0x1, machInst, vd, vn, vm_fp, index_fp);
else
return decodeNeonUThreeImmScFpReg<FmulElemScX>(
size & 0x1, machInst, vd, vn, vm_fp, index_fp);
case 0xb:
if (size == 0x0 || size == 0x3)
return new Unknown64(machInst);
else
return decodeNeonSThreeImmHAndWReg<SqdmullElemScX>(
size, machInst, vd, vn, vm, index);
case 0xc:
if (size == 0x0 || size == 0x3)
return new Unknown64(machInst);
else
return decodeNeonSThreeImmHAndWReg<SqdmulhElemScX>(
size, machInst, vd, vn, vm, index);
case 0xd:
if (size == 0x0 || size == 0x3)
return new Unknown64(machInst);
else
return decodeNeonSThreeImmHAndWReg<SqrdmulhElemScX>(
size, machInst, vd, vn, vm, index);
default:
return new Unknown64(machInst);
}
}
StaticInstPtr
decodeNeonScShiftByImm(ExtMachInst machInst)
{
bool u = bits(machInst, 29);
uint8_t immh = bits(machInst, 22, 19);
uint8_t immb = bits(machInst, 18, 16);
uint8_t opcode = bits(machInst, 15, 11);
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
uint8_t immh3 = bits(machInst, 22);
uint8_t size = findMsbSet(immh);
int shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (immh == 0x0)
return new Unknown64(machInst);
switch (opcode) {
case 0x00:
if (!immh3)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return new UshrDX<uint64_t>(machInst, vd, vn, shiftAmt);
else
return new SshrDX<int64_t>(machInst, vd, vn, shiftAmt);
case 0x02:
if (!immh3)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return new UsraDX<uint64_t>(machInst, vd, vn, shiftAmt);
else
return new SsraDX<int64_t>(machInst, vd, vn, shiftAmt);
case 0x04:
if (!immh3)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return new UrshrDX<uint64_t>(machInst, vd, vn, shiftAmt);
else
return new SrshrDX<int64_t>(machInst, vd, vn, shiftAmt);
case 0x06:
if (!immh3)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return new UrsraDX<uint64_t>(machInst, vd, vn, shiftAmt);
else
return new SrsraDX<int64_t>(machInst, vd, vn, shiftAmt);
case 0x08:
if (!immh3)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return new SriDX<uint64_t>(machInst, vd, vn, shiftAmt);
else
return new Unknown64(machInst);
case 0x0a:
if (!immh3)
return new Unknown64(machInst);
shiftAmt = ((immh << 3) | immb) - (8 << size);
if (u)
return new SliDX<uint64_t>(machInst, vd, vn, shiftAmt);
else
return new ShlDX<uint64_t>(machInst, vd, vn, shiftAmt);
case 0x0c:
if (u) {
shiftAmt = ((immh << 3) | immb) - (8 << size);
return decodeNeonSTwoShiftUReg<SqshluScX>(
size, machInst, vd, vn, shiftAmt);
} else {
return new Unknown64(machInst);
}
case 0x0e:
shiftAmt = ((immh << 3) | immb) - (8 << size);
if (u)
return decodeNeonUTwoShiftUReg<UqshlImmScX>(
size, machInst, vd, vn, shiftAmt);
else
return decodeNeonSTwoShiftUReg<SqshlImmScX>(
size, machInst, vd, vn, shiftAmt);
case 0x10:
if (!u || immh3)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
return decodeNeonSTwoShiftUSReg<SqshrunScX>(
size, machInst, vd, vn, shiftAmt);
case 0x11:
if (!u || immh3)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
return decodeNeonSTwoShiftUSReg<SqrshrunScX>(
size, machInst, vd, vn, shiftAmt);
case 0x12:
if (immh3)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return decodeNeonUTwoShiftUSReg<UqshrnScX>(
size, machInst, vd, vn, shiftAmt);
else
return decodeNeonSTwoShiftUSReg<SqshrnScX>(
size, machInst, vd, vn, shiftAmt);
case 0x13:
if (immh3)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return decodeNeonUTwoShiftUSReg<UqrshrnScX>(
size, machInst, vd, vn, shiftAmt);
else
return decodeNeonSTwoShiftUSReg<SqrshrnScX>(
size, machInst, vd, vn, shiftAmt);
case 0x1c:
if (immh < 0x4)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u) {
return decodeNeonUTwoShiftUFpReg<UcvtfFixedScX>(
size & 0x1, machInst, vd, vn, shiftAmt);
} else {
if (size & 0x1)
return new ScvtfFixedScDX<uint64_t>(machInst, vd, vn,
shiftAmt);
else
return new ScvtfFixedScSX<uint32_t>(machInst, vd, vn,
shiftAmt);
}
case 0x1f:
if (immh < 0x4)
return new Unknown64(machInst);
shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb);
if (u)
return decodeNeonUTwoShiftUFpReg<FcvtzuFixedScX>(
size & 0x1, machInst, vd, vn, shiftAmt);
else
return decodeNeonUTwoShiftUFpReg<FcvtzsFixedScX>(
size & 0x1, machInst, vd, vn, shiftAmt);
default:
return new Unknown64(machInst);
}
}
StaticInstPtr
decodeNeonMem(ExtMachInst machInst)
{
uint8_t dataSize = bits(machInst, 30) ? 128 : 64;
bool multiple = bits(machInst, 24, 23) < 0x2;
bool load = bits(machInst, 22);
uint8_t numStructElems = 0;
uint8_t numRegs = 0;
if (multiple) { // AdvSIMD load/store multiple structures
uint8_t opcode = bits(machInst, 15, 12);
uint8_t eSize = bits(machInst, 11, 10);
bool wb = !(bits(machInst, 20, 16) == 0x0 && !bits(machInst, 23));
switch (opcode) {
case 0x0: // LD/ST4 (4 regs)
numStructElems = 4;
numRegs = 4;
break;
case 0x2: // LD/ST1 (4 regs)
numStructElems = 1;
numRegs = 4;
break;
case 0x4: // LD/ST3 (3 regs)
numStructElems = 3;
numRegs = 3;
break;
case 0x6: // LD/ST1 (3 regs)
numStructElems = 1;
numRegs = 3;
break;
case 0x7: // LD/ST1 (1 reg)
numStructElems = 1;
numRegs = 1;
break;
case 0x8: // LD/ST2 (2 regs)
numStructElems = 2;
numRegs = 2;
break;
case 0xa: // LD/ST1 (2 regs)
numStructElems = 1;
numRegs = 2;
break;
default:
return new Unknown64(machInst);
}
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex rn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
IntRegIndex rm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16);
if (load) {
return new VldMult64(machInst, rn, vd, rm, eSize, dataSize,
numStructElems, numRegs, wb);
} else {
return new VstMult64(machInst, rn, vd, rm, eSize, dataSize,
numStructElems, numRegs, wb);
}
} else { // AdvSIMD load/store single structure
uint8_t scale = bits(machInst, 15, 14);
uint8_t numStructElems = (((uint8_t) bits(machInst, 13) << 1) |
(uint8_t) bits(machInst, 21)) + 1;
uint8_t index = 0;
bool wb = !(bits(machInst, 20, 16) == 0x0 && !bits(machInst, 23));
bool replicate = false;
switch (scale) {
case 0x0:
index = ((uint8_t) bits(machInst, 30) << 3) |
((uint8_t) bits(machInst, 12) << 2) |
(uint8_t) bits(machInst, 11, 10);
break;
case 0x1:
index = ((uint8_t) bits(machInst, 30) << 2) |
((uint8_t) bits(machInst, 12) << 1) |
(uint8_t) bits(machInst, 11);
break;
case 0x2:
if (bits(machInst, 10) == 0x0) {
index = ((uint8_t) bits(machInst, 30) << 1) |
bits(machInst, 12);
} else {
index = (uint8_t) bits(machInst, 30);
scale = 0x3;
}
break;
case 0x3:
scale = bits(machInst, 11, 10);
replicate = true;
break;
default:
return new Unknown64(machInst);
}
uint8_t eSize = scale;
IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0);
IntRegIndex rn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5);
IntRegIndex rm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16);
if (load) {
return new VldSingle64(machInst, rn, vd, rm, eSize, dataSize,
numStructElems, index, wb, replicate);
} else {
return new VstSingle64(machInst, rn, vd, rm, eSize, dataSize,
numStructElems, index, wb, replicate);
}
}
}
}
}};