mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-10 01:10:48 +00:00
9224192321
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@195936 91177308-0d34-0410-b5e6-96231b3b80d8
1573 lines
60 KiB
C++
1573 lines
60 KiB
C++
//===- AArch64Disassembler.cpp - Disassembler for AArch64 ISA -------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file contains the functions necessary to decode AArch64 instruction
|
|
// bitpatterns into MCInsts (with the help of TableGenerated information from
|
|
// the instruction definitions).
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "arm-disassembler"
|
|
|
|
#include "AArch64.h"
|
|
#include "AArch64RegisterInfo.h"
|
|
#include "AArch64Subtarget.h"
|
|
#include "Utils/AArch64BaseInfo.h"
|
|
#include "llvm/MC/MCInst.h"
|
|
#include "llvm/MC/MCInstrDesc.h"
|
|
#include "llvm/MC/MCExpr.h"
|
|
#include "llvm/MC/MCContext.h"
|
|
#include "llvm/MC/MCDisassembler.h"
|
|
#include "llvm/MC/MCFixedLenDisassembler.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/MemoryObject.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace llvm;
|
|
|
|
typedef MCDisassembler::DecodeStatus DecodeStatus;
|
|
|
|
namespace {
|
|
/// AArch64 disassembler for all AArch64 platforms.
|
|
class AArch64Disassembler : public MCDisassembler {
|
|
OwningPtr<const MCRegisterInfo> RegInfo;
|
|
public:
|
|
/// Initializes the disassembler.
|
|
///
|
|
AArch64Disassembler(const MCSubtargetInfo &STI, const MCRegisterInfo *Info)
|
|
: MCDisassembler(STI), RegInfo(Info) {
|
|
}
|
|
|
|
~AArch64Disassembler() {}
|
|
|
|
/// See MCDisassembler.
|
|
DecodeStatus getInstruction(MCInst &instr,
|
|
uint64_t &size,
|
|
const MemoryObject ®ion,
|
|
uint64_t address,
|
|
raw_ostream &vStream,
|
|
raw_ostream &cStream) const;
|
|
|
|
const MCRegisterInfo *getRegInfo() const { return RegInfo.get(); }
|
|
};
|
|
|
|
}
|
|
|
|
// Forward-declarations used in the auto-generated files.
|
|
static DecodeStatus DecodeGPR64RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder);
|
|
static DecodeStatus
|
|
DecodeGPR64xspRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder);
|
|
|
|
static DecodeStatus DecodeGPR32RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder);
|
|
static DecodeStatus
|
|
DecodeGPR32wspRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder);
|
|
|
|
static DecodeStatus DecodeFPR8RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder);
|
|
static DecodeStatus DecodeFPR16RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder);
|
|
static DecodeStatus DecodeFPR32RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder);
|
|
static DecodeStatus DecodeFPR64RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder);
|
|
static DecodeStatus DecodeFPR64LoRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder);
|
|
static DecodeStatus DecodeFPR128RegisterClass(llvm::MCInst &Inst,
|
|
unsigned RegNo, uint64_t Address,
|
|
const void *Decoder);
|
|
static DecodeStatus DecodeFPR128LoRegisterClass(llvm::MCInst &Inst,
|
|
unsigned RegNo, uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeGPR64noxzrRegisterClass(llvm::MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeDPairRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
static DecodeStatus DecodeQPairRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
static DecodeStatus DecodeDTripleRegisterClass(llvm::MCInst &Inst,
|
|
unsigned RegNo, uint64_t Address,
|
|
const void *Decoder);
|
|
static DecodeStatus DecodeQTripleRegisterClass(llvm::MCInst &Inst,
|
|
unsigned RegNo, uint64_t Address,
|
|
const void *Decoder);
|
|
static DecodeStatus DecodeDQuadRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
static DecodeStatus DecodeQQuadRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeAddrRegExtendOperand(llvm::MCInst &Inst,
|
|
unsigned OptionHiS,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
|
|
static DecodeStatus DecodeBitfield32ImmOperand(llvm::MCInst &Inst,
|
|
unsigned Imm6Bits,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeCVT32FixedPosOperand(llvm::MCInst &Inst,
|
|
unsigned Imm6Bits,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeFPZeroOperand(llvm::MCInst &Inst,
|
|
unsigned RmBits,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeShiftRightImm8(MCInst &Inst, unsigned Val,
|
|
uint64_t Address, const void *Decoder);
|
|
static DecodeStatus DecodeShiftRightImm16(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
static DecodeStatus DecodeShiftRightImm32(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
static DecodeStatus DecodeShiftRightImm64(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeShiftLeftImm8(MCInst &Inst, unsigned Val,
|
|
uint64_t Address, const void *Decoder);
|
|
static DecodeStatus DecodeShiftLeftImm16(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
static DecodeStatus DecodeShiftLeftImm32(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
static DecodeStatus DecodeShiftLeftImm64(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
template<int RegWidth>
|
|
static DecodeStatus DecodeMoveWideImmOperand(llvm::MCInst &Inst,
|
|
unsigned FullImm,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
template<int RegWidth>
|
|
static DecodeStatus DecodeLogicalImmOperand(llvm::MCInst &Inst,
|
|
unsigned Bits,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeRegExtendOperand(llvm::MCInst &Inst,
|
|
unsigned ShiftAmount,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
template <A64SE::ShiftExtSpecifiers Ext, bool IsHalf>
|
|
static DecodeStatus
|
|
DecodeNeonMovImmShiftOperand(llvm::MCInst &Inst, unsigned ShiftAmount,
|
|
uint64_t Address, const void *Decoder);
|
|
|
|
static DecodeStatus Decode32BitShiftOperand(llvm::MCInst &Inst,
|
|
unsigned ShiftAmount,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
static DecodeStatus DecodeBitfieldInstruction(llvm::MCInst &Inst, unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeFMOVLaneInstruction(llvm::MCInst &Inst, unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeLDSTPairInstruction(llvm::MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeLoadPairExclusiveInstruction(llvm::MCInst &Inst,
|
|
unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
template<typename SomeNamedImmMapper>
|
|
static DecodeStatus DecodeNamedImmOperand(llvm::MCInst &Inst,
|
|
unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus
|
|
DecodeSysRegOperand(const A64SysReg::SysRegMapper &InstMapper,
|
|
llvm::MCInst &Inst, unsigned Val,
|
|
uint64_t Address, const void *Decoder);
|
|
|
|
static DecodeStatus DecodeMRSOperand(llvm::MCInst &Inst,
|
|
unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeMSROperand(llvm::MCInst &Inst,
|
|
unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
|
|
static DecodeStatus DecodeSingleIndexedInstruction(llvm::MCInst &Inst,
|
|
unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeVLDSTPostInstruction(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeVLDSTLanePostInstruction(MCInst &Inst, unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeSHLLInstruction(MCInst &Inst, unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static bool Check(DecodeStatus &Out, DecodeStatus In);
|
|
|
|
#include "AArch64GenDisassemblerTables.inc"
|
|
#include "AArch64GenInstrInfo.inc"
|
|
|
|
static bool Check(DecodeStatus &Out, DecodeStatus In) {
|
|
switch (In) {
|
|
case MCDisassembler::Success:
|
|
// Out stays the same.
|
|
return true;
|
|
case MCDisassembler::SoftFail:
|
|
Out = In;
|
|
return true;
|
|
case MCDisassembler::Fail:
|
|
Out = In;
|
|
return false;
|
|
}
|
|
llvm_unreachable("Invalid DecodeStatus!");
|
|
}
|
|
|
|
DecodeStatus AArch64Disassembler::getInstruction(MCInst &MI, uint64_t &Size,
|
|
const MemoryObject &Region,
|
|
uint64_t Address,
|
|
raw_ostream &os,
|
|
raw_ostream &cs) const {
|
|
CommentStream = &cs;
|
|
|
|
uint8_t bytes[4];
|
|
|
|
// We want to read exactly 4 bytes of data.
|
|
if (Region.readBytes(Address, 4, bytes) == -1) {
|
|
Size = 0;
|
|
return MCDisassembler::Fail;
|
|
}
|
|
|
|
// Encoded as a small-endian 32-bit word in the stream.
|
|
uint32_t insn = (bytes[3] << 24) |
|
|
(bytes[2] << 16) |
|
|
(bytes[1] << 8) |
|
|
(bytes[0] << 0);
|
|
|
|
// Calling the auto-generated decoder function.
|
|
DecodeStatus result = decodeInstruction(DecoderTableA6432, MI, insn, Address,
|
|
this, STI);
|
|
if (result != MCDisassembler::Fail) {
|
|
Size = 4;
|
|
return result;
|
|
}
|
|
|
|
MI.clear();
|
|
Size = 0;
|
|
return MCDisassembler::Fail;
|
|
}
|
|
|
|
static unsigned getReg(const void *D, unsigned RC, unsigned RegNo) {
|
|
const AArch64Disassembler *Dis = static_cast<const AArch64Disassembler*>(D);
|
|
return Dis->getRegInfo()->getRegClass(RC).getRegister(RegNo);
|
|
}
|
|
|
|
static DecodeStatus DecodeGPR64RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder) {
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
uint16_t Register = getReg(Decoder, AArch64::GPR64RegClassID, RegNo);
|
|
Inst.addOperand(MCOperand::CreateReg(Register));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus
|
|
DecodeGPR64xspRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder) {
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
uint16_t Register = getReg(Decoder, AArch64::GPR64xspRegClassID, RegNo);
|
|
Inst.addOperand(MCOperand::CreateReg(Register));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeGPR32RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
uint16_t Register = getReg(Decoder, AArch64::GPR32RegClassID, RegNo);
|
|
Inst.addOperand(MCOperand::CreateReg(Register));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus
|
|
DecodeGPR32wspRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder) {
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
uint16_t Register = getReg(Decoder, AArch64::GPR32wspRegClassID, RegNo);
|
|
Inst.addOperand(MCOperand::CreateReg(Register));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus
|
|
DecodeFPR8RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder) {
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
uint16_t Register = getReg(Decoder, AArch64::FPR8RegClassID, RegNo);
|
|
Inst.addOperand(MCOperand::CreateReg(Register));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus
|
|
DecodeFPR16RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder) {
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
uint16_t Register = getReg(Decoder, AArch64::FPR16RegClassID, RegNo);
|
|
Inst.addOperand(MCOperand::CreateReg(Register));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
|
|
static DecodeStatus
|
|
DecodeFPR32RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder) {
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
uint16_t Register = getReg(Decoder, AArch64::FPR32RegClassID, RegNo);
|
|
Inst.addOperand(MCOperand::CreateReg(Register));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus
|
|
DecodeFPR64RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder) {
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
uint16_t Register = getReg(Decoder, AArch64::FPR64RegClassID, RegNo);
|
|
Inst.addOperand(MCOperand::CreateReg(Register));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus
|
|
DecodeFPR64LoRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder) {
|
|
if (RegNo > 15)
|
|
return MCDisassembler::Fail;
|
|
|
|
return DecodeFPR64RegisterClass(Inst, RegNo, Address, Decoder);
|
|
}
|
|
|
|
static DecodeStatus
|
|
DecodeFPR128RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder) {
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
uint16_t Register = getReg(Decoder, AArch64::FPR128RegClassID, RegNo);
|
|
Inst.addOperand(MCOperand::CreateReg(Register));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus
|
|
DecodeFPR128LoRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address, const void *Decoder) {
|
|
if (RegNo > 15)
|
|
return MCDisassembler::Fail;
|
|
|
|
return DecodeFPR128RegisterClass(Inst, RegNo, Address, Decoder);
|
|
}
|
|
|
|
static DecodeStatus DecodeGPR64noxzrRegisterClass(llvm::MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
if (RegNo > 30)
|
|
return MCDisassembler::Fail;
|
|
|
|
uint16_t Register = getReg(Decoder, AArch64::GPR64noxzrRegClassID, RegNo);
|
|
Inst.addOperand(MCOperand::CreateReg(Register));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeRegisterClassByID(llvm::MCInst &Inst, unsigned RegNo,
|
|
unsigned RegID,
|
|
const void *Decoder) {
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
uint16_t Register = getReg(Decoder, RegID, RegNo);
|
|
Inst.addOperand(MCOperand::CreateReg(Register));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeDPairRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
return DecodeRegisterClassByID(Inst, RegNo, AArch64::DPairRegClassID,
|
|
Decoder);
|
|
}
|
|
|
|
static DecodeStatus DecodeQPairRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
return DecodeRegisterClassByID(Inst, RegNo, AArch64::QPairRegClassID,
|
|
Decoder);
|
|
}
|
|
|
|
static DecodeStatus DecodeDTripleRegisterClass(llvm::MCInst &Inst,
|
|
unsigned RegNo, uint64_t Address,
|
|
const void *Decoder) {
|
|
return DecodeRegisterClassByID(Inst, RegNo, AArch64::DTripleRegClassID,
|
|
Decoder);
|
|
}
|
|
|
|
static DecodeStatus DecodeQTripleRegisterClass(llvm::MCInst &Inst,
|
|
unsigned RegNo, uint64_t Address,
|
|
const void *Decoder) {
|
|
return DecodeRegisterClassByID(Inst, RegNo, AArch64::QTripleRegClassID,
|
|
Decoder);
|
|
}
|
|
|
|
static DecodeStatus DecodeDQuadRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
return DecodeRegisterClassByID(Inst, RegNo, AArch64::DQuadRegClassID,
|
|
Decoder);
|
|
}
|
|
|
|
static DecodeStatus DecodeQQuadRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
return DecodeRegisterClassByID(Inst, RegNo, AArch64::QQuadRegClassID,
|
|
Decoder);
|
|
}
|
|
|
|
static DecodeStatus DecodeAddrRegExtendOperand(llvm::MCInst &Inst,
|
|
unsigned OptionHiS,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
// Option{1} must be 1. OptionHiS is made up of {Option{2}, Option{1},
|
|
// S}. Hence we want to check bit 1.
|
|
if (!(OptionHiS & 2))
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateImm(OptionHiS));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeBitfield32ImmOperand(llvm::MCInst &Inst,
|
|
unsigned Imm6Bits,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
// In the 32-bit variant, bit 6 must be zero. I.e. the immediate must be
|
|
// between 0 and 31.
|
|
if (Imm6Bits > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateImm(Imm6Bits));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeCVT32FixedPosOperand(llvm::MCInst &Inst,
|
|
unsigned Imm6Bits,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
// 1 <= Imm <= 32. Encoded as 64 - Imm so: 63 >= Encoded >= 32.
|
|
if (Imm6Bits < 32)
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateImm(Imm6Bits));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeFPZeroOperand(llvm::MCInst &Inst,
|
|
unsigned RmBits,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
// Any bits are valid in the instruction (they're architecturally ignored),
|
|
// but a code generator should insert 0.
|
|
Inst.addOperand(MCOperand::CreateImm(0));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeShiftRightImm8(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
Inst.addOperand(MCOperand::CreateImm(8 - Val));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeShiftRightImm16(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
Inst.addOperand(MCOperand::CreateImm(16 - Val));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeShiftRightImm32(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
Inst.addOperand(MCOperand::CreateImm(32 - Val));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeShiftRightImm64(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
Inst.addOperand(MCOperand::CreateImm(64 - Val));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeShiftLeftImm8(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
if (Val > 7)
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateImm(Val));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeShiftLeftImm16(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
if (Val > 15)
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateImm(Val));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeShiftLeftImm32(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
if (Val > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateImm(Val));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeShiftLeftImm64(MCInst &Inst, unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
if (Val > 63)
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateImm(Val));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
template<int RegWidth>
|
|
static DecodeStatus DecodeMoveWideImmOperand(llvm::MCInst &Inst,
|
|
unsigned FullImm,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
unsigned Imm16 = FullImm & 0xffff;
|
|
unsigned Shift = FullImm >> 16;
|
|
|
|
if (RegWidth == 32 && Shift > 1) return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateImm(Imm16));
|
|
Inst.addOperand(MCOperand::CreateImm(Shift));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
template<int RegWidth>
|
|
static DecodeStatus DecodeLogicalImmOperand(llvm::MCInst &Inst,
|
|
unsigned Bits,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
uint64_t Imm;
|
|
if (!A64Imms::isLogicalImmBits(RegWidth, Bits, Imm))
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateImm(Bits));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
|
|
static DecodeStatus DecodeRegExtendOperand(llvm::MCInst &Inst,
|
|
unsigned ShiftAmount,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
// Only values 0-4 are valid for this 3-bit field
|
|
if (ShiftAmount > 4)
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateImm(ShiftAmount));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus Decode32BitShiftOperand(llvm::MCInst &Inst,
|
|
unsigned ShiftAmount,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
// Only values below 32 are valid for a 32-bit register
|
|
if (ShiftAmount > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateImm(ShiftAmount));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeBitfieldInstruction(llvm::MCInst &Inst, unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
unsigned Rd = fieldFromInstruction(Insn, 0, 5);
|
|
unsigned Rn = fieldFromInstruction(Insn, 5, 5);
|
|
unsigned ImmS = fieldFromInstruction(Insn, 10, 6);
|
|
unsigned ImmR = fieldFromInstruction(Insn, 16, 6);
|
|
unsigned SF = fieldFromInstruction(Insn, 31, 1);
|
|
|
|
// Undef for 0b11 just in case it occurs. Don't want the compiler to optimise
|
|
// out assertions that it thinks should never be hit.
|
|
enum OpcTypes { SBFM = 0, BFM, UBFM, Undef } Opc;
|
|
Opc = (OpcTypes)fieldFromInstruction(Insn, 29, 2);
|
|
|
|
if (!SF) {
|
|
// ImmR and ImmS must be between 0 and 31 for 32-bit instructions.
|
|
if (ImmR > 31 || ImmS > 31)
|
|
return MCDisassembler::Fail;
|
|
}
|
|
|
|
if (SF) {
|
|
DecodeGPR64RegisterClass(Inst, Rd, Address, Decoder);
|
|
// BFM MCInsts use Rd as a source too.
|
|
if (Opc == BFM) DecodeGPR64RegisterClass(Inst, Rd, Address, Decoder);
|
|
DecodeGPR64RegisterClass(Inst, Rn, Address, Decoder);
|
|
} else {
|
|
DecodeGPR32RegisterClass(Inst, Rd, Address, Decoder);
|
|
// BFM MCInsts use Rd as a source too.
|
|
if (Opc == BFM) DecodeGPR32RegisterClass(Inst, Rd, Address, Decoder);
|
|
DecodeGPR32RegisterClass(Inst, Rn, Address, Decoder);
|
|
}
|
|
|
|
// ASR and LSR have more specific patterns so they won't get here:
|
|
assert(!(ImmS == 31 && !SF && Opc != BFM)
|
|
&& "shift should have used auto decode");
|
|
assert(!(ImmS == 63 && SF && Opc != BFM)
|
|
&& "shift should have used auto decode");
|
|
|
|
// Extension instructions similarly:
|
|
if (Opc == SBFM && ImmR == 0) {
|
|
assert((ImmS != 7 && ImmS != 15) && "extension got here");
|
|
assert((ImmS != 31 || SF == 0) && "extension got here");
|
|
} else if (Opc == UBFM && ImmR == 0) {
|
|
assert((SF != 0 || (ImmS != 7 && ImmS != 15)) && "extension got here");
|
|
}
|
|
|
|
if (Opc == UBFM) {
|
|
// It might be a LSL instruction, which actually takes the shift amount
|
|
// itself as an MCInst operand.
|
|
if (SF && (ImmS + 1) % 64 == ImmR) {
|
|
Inst.setOpcode(AArch64::LSLxxi);
|
|
Inst.addOperand(MCOperand::CreateImm(63 - ImmS));
|
|
return MCDisassembler::Success;
|
|
} else if (!SF && (ImmS + 1) % 32 == ImmR) {
|
|
Inst.setOpcode(AArch64::LSLwwi);
|
|
Inst.addOperand(MCOperand::CreateImm(31 - ImmS));
|
|
return MCDisassembler::Success;
|
|
}
|
|
}
|
|
|
|
// Otherwise it's definitely either an extract or an insert depending on which
|
|
// of ImmR or ImmS is larger.
|
|
unsigned ExtractOp, InsertOp;
|
|
switch (Opc) {
|
|
default: llvm_unreachable("unexpected instruction trying to decode bitfield");
|
|
case SBFM:
|
|
ExtractOp = SF ? AArch64::SBFXxxii : AArch64::SBFXwwii;
|
|
InsertOp = SF ? AArch64::SBFIZxxii : AArch64::SBFIZwwii;
|
|
break;
|
|
case BFM:
|
|
ExtractOp = SF ? AArch64::BFXILxxii : AArch64::BFXILwwii;
|
|
InsertOp = SF ? AArch64::BFIxxii : AArch64::BFIwwii;
|
|
break;
|
|
case UBFM:
|
|
ExtractOp = SF ? AArch64::UBFXxxii : AArch64::UBFXwwii;
|
|
InsertOp = SF ? AArch64::UBFIZxxii : AArch64::UBFIZwwii;
|
|
break;
|
|
}
|
|
|
|
// Otherwise it's a boring insert or extract
|
|
Inst.addOperand(MCOperand::CreateImm(ImmR));
|
|
Inst.addOperand(MCOperand::CreateImm(ImmS));
|
|
|
|
|
|
if (ImmS < ImmR)
|
|
Inst.setOpcode(InsertOp);
|
|
else
|
|
Inst.setOpcode(ExtractOp);
|
|
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeFMOVLaneInstruction(llvm::MCInst &Inst, unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
// This decoder exists to add the dummy Lane operand to the MCInst, which must
|
|
// be 1 in assembly but has no other real manifestation.
|
|
unsigned Rd = fieldFromInstruction(Insn, 0, 5);
|
|
unsigned Rn = fieldFromInstruction(Insn, 5, 5);
|
|
unsigned IsToVec = fieldFromInstruction(Insn, 16, 1);
|
|
|
|
if (IsToVec) {
|
|
DecodeFPR128RegisterClass(Inst, Rd, Address, Decoder);
|
|
DecodeGPR64RegisterClass(Inst, Rn, Address, Decoder);
|
|
} else {
|
|
DecodeGPR64RegisterClass(Inst, Rd, Address, Decoder);
|
|
DecodeFPR128RegisterClass(Inst, Rn, Address, Decoder);
|
|
}
|
|
|
|
// Add the lane
|
|
Inst.addOperand(MCOperand::CreateImm(1));
|
|
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
|
|
static DecodeStatus DecodeLDSTPairInstruction(llvm::MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
DecodeStatus Result = MCDisassembler::Success;
|
|
unsigned Rt = fieldFromInstruction(Insn, 0, 5);
|
|
unsigned Rn = fieldFromInstruction(Insn, 5, 5);
|
|
unsigned Rt2 = fieldFromInstruction(Insn, 10, 5);
|
|
unsigned SImm7 = fieldFromInstruction(Insn, 15, 7);
|
|
unsigned L = fieldFromInstruction(Insn, 22, 1);
|
|
unsigned V = fieldFromInstruction(Insn, 26, 1);
|
|
unsigned Opc = fieldFromInstruction(Insn, 30, 2);
|
|
|
|
// Not an official name, but it turns out that bit 23 distinguishes indexed
|
|
// from non-indexed operations.
|
|
unsigned Indexed = fieldFromInstruction(Insn, 23, 1);
|
|
|
|
if (Indexed && L == 0) {
|
|
// The MCInst for an indexed store has an out operand and 4 ins:
|
|
// Rn_wb, Rt, Rt2, Rn, Imm
|
|
DecodeGPR64xspRegisterClass(Inst, Rn, Address, Decoder);
|
|
}
|
|
|
|
// You shouldn't load to the same register twice in an instruction...
|
|
if (L && Rt == Rt2)
|
|
Result = MCDisassembler::SoftFail;
|
|
|
|
// ... or do any operation that writes-back to a transfer register. But note
|
|
// that "stp xzr, xzr, [sp], #4" is fine because xzr and sp are different.
|
|
if (Indexed && V == 0 && Rn != 31 && (Rt == Rn || Rt2 == Rn))
|
|
Result = MCDisassembler::SoftFail;
|
|
|
|
// Exactly how we decode the MCInst's registers depends on the Opc and V
|
|
// fields of the instruction. These also obviously determine the size of the
|
|
// operation so we can fill in that information while we're at it.
|
|
if (V) {
|
|
// The instruction operates on the FP/SIMD registers
|
|
switch (Opc) {
|
|
default: return MCDisassembler::Fail;
|
|
case 0:
|
|
DecodeFPR32RegisterClass(Inst, Rt, Address, Decoder);
|
|
DecodeFPR32RegisterClass(Inst, Rt2, Address, Decoder);
|
|
break;
|
|
case 1:
|
|
DecodeFPR64RegisterClass(Inst, Rt, Address, Decoder);
|
|
DecodeFPR64RegisterClass(Inst, Rt2, Address, Decoder);
|
|
break;
|
|
case 2:
|
|
DecodeFPR128RegisterClass(Inst, Rt, Address, Decoder);
|
|
DecodeFPR128RegisterClass(Inst, Rt2, Address, Decoder);
|
|
break;
|
|
}
|
|
} else {
|
|
switch (Opc) {
|
|
default: return MCDisassembler::Fail;
|
|
case 0:
|
|
DecodeGPR32RegisterClass(Inst, Rt, Address, Decoder);
|
|
DecodeGPR32RegisterClass(Inst, Rt2, Address, Decoder);
|
|
break;
|
|
case 1:
|
|
assert(L && "unexpected \"store signed\" attempt");
|
|
DecodeGPR64RegisterClass(Inst, Rt, Address, Decoder);
|
|
DecodeGPR64RegisterClass(Inst, Rt2, Address, Decoder);
|
|
break;
|
|
case 2:
|
|
DecodeGPR64RegisterClass(Inst, Rt, Address, Decoder);
|
|
DecodeGPR64RegisterClass(Inst, Rt2, Address, Decoder);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Indexed && L == 1) {
|
|
// The MCInst for an indexed load has 3 out operands and an 3 ins:
|
|
// Rt, Rt2, Rn_wb, Rt2, Rn, Imm
|
|
DecodeGPR64xspRegisterClass(Inst, Rn, Address, Decoder);
|
|
}
|
|
|
|
|
|
DecodeGPR64xspRegisterClass(Inst, Rn, Address, Decoder);
|
|
Inst.addOperand(MCOperand::CreateImm(SImm7));
|
|
|
|
return Result;
|
|
}
|
|
|
|
static DecodeStatus DecodeLoadPairExclusiveInstruction(llvm::MCInst &Inst,
|
|
uint32_t Val,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
unsigned Rt = fieldFromInstruction(Val, 0, 5);
|
|
unsigned Rn = fieldFromInstruction(Val, 5, 5);
|
|
unsigned Rt2 = fieldFromInstruction(Val, 10, 5);
|
|
unsigned MemSize = fieldFromInstruction(Val, 30, 2);
|
|
|
|
DecodeStatus S = MCDisassembler::Success;
|
|
if (Rt == Rt2) S = MCDisassembler::SoftFail;
|
|
|
|
switch (MemSize) {
|
|
case 2:
|
|
if (!Check(S, DecodeGPR32RegisterClass(Inst, Rt, Address, Decoder)))
|
|
return MCDisassembler::Fail;
|
|
if (!Check(S, DecodeGPR32RegisterClass(Inst, Rt2, Address, Decoder)))
|
|
return MCDisassembler::Fail;
|
|
break;
|
|
case 3:
|
|
if (!Check(S, DecodeGPR64RegisterClass(Inst, Rt, Address, Decoder)))
|
|
return MCDisassembler::Fail;
|
|
if (!Check(S, DecodeGPR64RegisterClass(Inst, Rt2, Address, Decoder)))
|
|
return MCDisassembler::Fail;
|
|
break;
|
|
default:
|
|
llvm_unreachable("Invalid MemSize in DecodeLoadPairExclusiveInstruction");
|
|
}
|
|
|
|
if (!Check(S, DecodeGPR64xspRegisterClass(Inst, Rn, Address, Decoder)))
|
|
return MCDisassembler::Fail;
|
|
|
|
return S;
|
|
}
|
|
|
|
template<typename SomeNamedImmMapper>
|
|
static DecodeStatus DecodeNamedImmOperand(llvm::MCInst &Inst,
|
|
unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
SomeNamedImmMapper Mapper;
|
|
bool ValidNamed;
|
|
Mapper.toString(Val, ValidNamed);
|
|
if (ValidNamed || Mapper.validImm(Val)) {
|
|
Inst.addOperand(MCOperand::CreateImm(Val));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
return MCDisassembler::Fail;
|
|
}
|
|
|
|
static DecodeStatus DecodeSysRegOperand(const A64SysReg::SysRegMapper &Mapper,
|
|
llvm::MCInst &Inst,
|
|
unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
bool ValidNamed;
|
|
Mapper.toString(Val, ValidNamed);
|
|
|
|
Inst.addOperand(MCOperand::CreateImm(Val));
|
|
|
|
return ValidNamed ? MCDisassembler::Success : MCDisassembler::Fail;
|
|
}
|
|
|
|
static DecodeStatus DecodeMRSOperand(llvm::MCInst &Inst,
|
|
unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
return DecodeSysRegOperand(A64SysReg::MRSMapper(), Inst, Val, Address,
|
|
Decoder);
|
|
}
|
|
|
|
static DecodeStatus DecodeMSROperand(llvm::MCInst &Inst,
|
|
unsigned Val,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
return DecodeSysRegOperand(A64SysReg::MSRMapper(), Inst, Val, Address,
|
|
Decoder);
|
|
}
|
|
|
|
static DecodeStatus DecodeSingleIndexedInstruction(llvm::MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
unsigned Rt = fieldFromInstruction(Insn, 0, 5);
|
|
unsigned Rn = fieldFromInstruction(Insn, 5, 5);
|
|
unsigned Imm9 = fieldFromInstruction(Insn, 12, 9);
|
|
|
|
unsigned Opc = fieldFromInstruction(Insn, 22, 2);
|
|
unsigned V = fieldFromInstruction(Insn, 26, 1);
|
|
unsigned Size = fieldFromInstruction(Insn, 30, 2);
|
|
|
|
if (Opc == 0 || (V == 1 && Opc == 2)) {
|
|
// It's a store, the MCInst gets: Rn_wb, Rt, Rn, Imm
|
|
DecodeGPR64xspRegisterClass(Inst, Rn, Address, Decoder);
|
|
}
|
|
|
|
if (V == 0 && (Opc == 2 || Size == 3)) {
|
|
DecodeGPR64RegisterClass(Inst, Rt, Address, Decoder);
|
|
} else if (V == 0) {
|
|
DecodeGPR32RegisterClass(Inst, Rt, Address, Decoder);
|
|
} else if (V == 1 && (Opc & 2)) {
|
|
DecodeFPR128RegisterClass(Inst, Rt, Address, Decoder);
|
|
} else {
|
|
switch (Size) {
|
|
case 0:
|
|
DecodeFPR8RegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 1:
|
|
DecodeFPR16RegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 2:
|
|
DecodeFPR32RegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 3:
|
|
DecodeFPR64RegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Opc != 0 && (V != 1 || Opc != 2)) {
|
|
// It's a load, the MCInst gets: Rt, Rn_wb, Rn, Imm
|
|
DecodeGPR64xspRegisterClass(Inst, Rn, Address, Decoder);
|
|
}
|
|
|
|
DecodeGPR64xspRegisterClass(Inst, Rn, Address, Decoder);
|
|
|
|
Inst.addOperand(MCOperand::CreateImm(Imm9));
|
|
|
|
// N.b. The official documentation says undpredictable if Rt == Rn, but this
|
|
// takes place at the architectural rather than encoding level:
|
|
//
|
|
// "STR xzr, [sp], #4" is perfectly valid.
|
|
if (V == 0 && Rt == Rn && Rn != 31)
|
|
return MCDisassembler::SoftFail;
|
|
else
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static MCDisassembler *createAArch64Disassembler(const Target &T,
|
|
const MCSubtargetInfo &STI) {
|
|
return new AArch64Disassembler(STI, T.createMCRegInfo(""));
|
|
}
|
|
|
|
extern "C" void LLVMInitializeAArch64Disassembler() {
|
|
TargetRegistry::RegisterMCDisassembler(TheAArch64Target,
|
|
createAArch64Disassembler);
|
|
}
|
|
|
|
template <A64SE::ShiftExtSpecifiers Ext, bool IsHalf>
|
|
static DecodeStatus
|
|
DecodeNeonMovImmShiftOperand(llvm::MCInst &Inst, unsigned ShiftAmount,
|
|
uint64_t Address, const void *Decoder) {
|
|
bool IsLSL = false;
|
|
if (Ext == A64SE::LSL)
|
|
IsLSL = true;
|
|
else if (Ext != A64SE::MSL)
|
|
return MCDisassembler::Fail;
|
|
|
|
// MSL and LSLH accepts encoded shift amount 0 or 1.
|
|
if ((!IsLSL || (IsLSL && IsHalf)) && ShiftAmount != 0 && ShiftAmount != 1)
|
|
return MCDisassembler::Fail;
|
|
|
|
// LSL accepts encoded shift amount 0, 1, 2 or 3.
|
|
if (IsLSL && ShiftAmount > 3)
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateImm(ShiftAmount));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
// Decode post-index vector load/store instructions.
|
|
// This is necessary as we need to decode Rm: if Rm == 0b11111, the last
|
|
// operand is an immediate equal the the length of vector list in bytes,
|
|
// or Rm is decoded to a GPR64noxzr register.
|
|
static DecodeStatus DecodeVLDSTPostInstruction(MCInst &Inst, unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
unsigned Rt = fieldFromInstruction(Insn, 0, 5);
|
|
unsigned Rn = fieldFromInstruction(Insn, 5, 5);
|
|
unsigned Rm = fieldFromInstruction(Insn, 16, 5);
|
|
unsigned Opcode = fieldFromInstruction(Insn, 12, 4);
|
|
unsigned IsLoad = fieldFromInstruction(Insn, 22, 1);
|
|
// 0 for 64bit vector list, 1 for 128bit vector list
|
|
unsigned Is128BitVec = fieldFromInstruction(Insn, 30, 1);
|
|
|
|
unsigned NumVecs;
|
|
switch (Opcode) {
|
|
case 0: // ld4/st4
|
|
case 2: // ld1/st1 with 4 vectors
|
|
NumVecs = 4; break;
|
|
case 4: // ld3/st3
|
|
case 6: // ld1/st1 with 3 vectors
|
|
NumVecs = 3; break;
|
|
case 7: // ld1/st1 with 1 vector
|
|
NumVecs = 1; break;
|
|
case 8: // ld2/st2
|
|
case 10: // ld1/st1 with 2 vectors
|
|
NumVecs = 2; break;
|
|
default:
|
|
llvm_unreachable("Invalid opcode for post-index load/store instructions");
|
|
}
|
|
|
|
// Decode vector list of 1/2/3/4 vectors for load instructions.
|
|
if (IsLoad) {
|
|
switch (NumVecs) {
|
|
case 1:
|
|
Is128BitVec ? DecodeFPR128RegisterClass(Inst, Rt, Address, Decoder)
|
|
: DecodeFPR64RegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 2:
|
|
Is128BitVec ? DecodeQPairRegisterClass(Inst, Rt, Address, Decoder)
|
|
: DecodeDPairRegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 3:
|
|
Is128BitVec ? DecodeQTripleRegisterClass(Inst, Rt, Address, Decoder)
|
|
: DecodeDTripleRegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 4:
|
|
Is128BitVec ? DecodeQQuadRegisterClass(Inst, Rt, Address, Decoder)
|
|
: DecodeDQuadRegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Decode write back register, which is equal to Rn.
|
|
DecodeGPR64xspRegisterClass(Inst, Rn, Address, Decoder);
|
|
DecodeGPR64xspRegisterClass(Inst, Rn, Address, Decoder);
|
|
|
|
if (Rm == 31) // If Rm is 0x11111, add the vector list length in byte
|
|
Inst.addOperand(MCOperand::CreateImm(NumVecs * (Is128BitVec ? 16 : 8)));
|
|
else // Decode Rm
|
|
DecodeGPR64noxzrRegisterClass(Inst, Rm, Address, Decoder);
|
|
|
|
// Decode vector list of 1/2/3/4 vectors for load instructions.
|
|
if (!IsLoad) {
|
|
switch (NumVecs) {
|
|
case 1:
|
|
Is128BitVec ? DecodeFPR128RegisterClass(Inst, Rt, Address, Decoder)
|
|
: DecodeFPR64RegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 2:
|
|
Is128BitVec ? DecodeQPairRegisterClass(Inst, Rt, Address, Decoder)
|
|
: DecodeDPairRegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 3:
|
|
Is128BitVec ? DecodeQTripleRegisterClass(Inst, Rt, Address, Decoder)
|
|
: DecodeDTripleRegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 4:
|
|
Is128BitVec ? DecodeQQuadRegisterClass(Inst, Rt, Address, Decoder)
|
|
: DecodeDQuadRegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
// Decode post-index vector load/store lane instructions.
|
|
// This is necessary as we need to decode Rm: if Rm == 0b11111, the last
|
|
// operand is an immediate equal the the length of the changed bytes,
|
|
// or Rm is decoded to a GPR64noxzr register.
|
|
static DecodeStatus DecodeVLDSTLanePostInstruction(MCInst &Inst, unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
bool Is64bitVec = false;
|
|
bool IsLoadDup = false;
|
|
bool IsLoad = false;
|
|
// The total number of bytes transferred.
|
|
// TransferBytes = NumVecs * OneLaneBytes
|
|
unsigned TransferBytes = 0;
|
|
unsigned NumVecs = 0;
|
|
unsigned Opc = Inst.getOpcode();
|
|
switch (Opc) {
|
|
case AArch64::LD1R_WB_8B_fixed: case AArch64::LD1R_WB_8B_register:
|
|
case AArch64::LD1R_WB_4H_fixed: case AArch64::LD1R_WB_4H_register:
|
|
case AArch64::LD1R_WB_2S_fixed: case AArch64::LD1R_WB_2S_register:
|
|
case AArch64::LD1R_WB_1D_fixed: case AArch64::LD1R_WB_1D_register: {
|
|
switch (Opc) {
|
|
case AArch64::LD1R_WB_8B_fixed: case AArch64::LD1R_WB_8B_register:
|
|
TransferBytes = 1; break;
|
|
case AArch64::LD1R_WB_4H_fixed: case AArch64::LD1R_WB_4H_register:
|
|
TransferBytes = 2; break;
|
|
case AArch64::LD1R_WB_2S_fixed: case AArch64::LD1R_WB_2S_register:
|
|
TransferBytes = 4; break;
|
|
case AArch64::LD1R_WB_1D_fixed: case AArch64::LD1R_WB_1D_register:
|
|
TransferBytes = 8; break;
|
|
}
|
|
Is64bitVec = true;
|
|
IsLoadDup = true;
|
|
NumVecs = 1;
|
|
break;
|
|
}
|
|
|
|
case AArch64::LD1R_WB_16B_fixed: case AArch64::LD1R_WB_16B_register:
|
|
case AArch64::LD1R_WB_8H_fixed: case AArch64::LD1R_WB_8H_register:
|
|
case AArch64::LD1R_WB_4S_fixed: case AArch64::LD1R_WB_4S_register:
|
|
case AArch64::LD1R_WB_2D_fixed: case AArch64::LD1R_WB_2D_register: {
|
|
switch (Opc) {
|
|
case AArch64::LD1R_WB_16B_fixed: case AArch64::LD1R_WB_16B_register:
|
|
TransferBytes = 1; break;
|
|
case AArch64::LD1R_WB_8H_fixed: case AArch64::LD1R_WB_8H_register:
|
|
TransferBytes = 2; break;
|
|
case AArch64::LD1R_WB_4S_fixed: case AArch64::LD1R_WB_4S_register:
|
|
TransferBytes = 4; break;
|
|
case AArch64::LD1R_WB_2D_fixed: case AArch64::LD1R_WB_2D_register:
|
|
TransferBytes = 8; break;
|
|
}
|
|
IsLoadDup = true;
|
|
NumVecs = 1;
|
|
break;
|
|
}
|
|
|
|
case AArch64::LD2R_WB_8B_fixed: case AArch64::LD2R_WB_8B_register:
|
|
case AArch64::LD2R_WB_4H_fixed: case AArch64::LD2R_WB_4H_register:
|
|
case AArch64::LD2R_WB_2S_fixed: case AArch64::LD2R_WB_2S_register:
|
|
case AArch64::LD2R_WB_1D_fixed: case AArch64::LD2R_WB_1D_register: {
|
|
switch (Opc) {
|
|
case AArch64::LD2R_WB_8B_fixed: case AArch64::LD2R_WB_8B_register:
|
|
TransferBytes = 2; break;
|
|
case AArch64::LD2R_WB_4H_fixed: case AArch64::LD2R_WB_4H_register:
|
|
TransferBytes = 4; break;
|
|
case AArch64::LD2R_WB_2S_fixed: case AArch64::LD2R_WB_2S_register:
|
|
TransferBytes = 8; break;
|
|
case AArch64::LD2R_WB_1D_fixed: case AArch64::LD2R_WB_1D_register:
|
|
TransferBytes = 16; break;
|
|
}
|
|
Is64bitVec = true;
|
|
IsLoadDup = true;
|
|
NumVecs = 2;
|
|
break;
|
|
}
|
|
|
|
case AArch64::LD2R_WB_16B_fixed: case AArch64::LD2R_WB_16B_register:
|
|
case AArch64::LD2R_WB_8H_fixed: case AArch64::LD2R_WB_8H_register:
|
|
case AArch64::LD2R_WB_4S_fixed: case AArch64::LD2R_WB_4S_register:
|
|
case AArch64::LD2R_WB_2D_fixed: case AArch64::LD2R_WB_2D_register: {
|
|
switch (Opc) {
|
|
case AArch64::LD2R_WB_16B_fixed: case AArch64::LD2R_WB_16B_register:
|
|
TransferBytes = 2; break;
|
|
case AArch64::LD2R_WB_8H_fixed: case AArch64::LD2R_WB_8H_register:
|
|
TransferBytes = 4; break;
|
|
case AArch64::LD2R_WB_4S_fixed: case AArch64::LD2R_WB_4S_register:
|
|
TransferBytes = 8; break;
|
|
case AArch64::LD2R_WB_2D_fixed: case AArch64::LD2R_WB_2D_register:
|
|
TransferBytes = 16; break;
|
|
}
|
|
IsLoadDup = true;
|
|
NumVecs = 2;
|
|
break;
|
|
}
|
|
|
|
case AArch64::LD3R_WB_8B_fixed: case AArch64::LD3R_WB_8B_register:
|
|
case AArch64::LD3R_WB_4H_fixed: case AArch64::LD3R_WB_4H_register:
|
|
case AArch64::LD3R_WB_2S_fixed: case AArch64::LD3R_WB_2S_register:
|
|
case AArch64::LD3R_WB_1D_fixed: case AArch64::LD3R_WB_1D_register: {
|
|
switch (Opc) {
|
|
case AArch64::LD3R_WB_8B_fixed: case AArch64::LD3R_WB_8B_register:
|
|
TransferBytes = 3; break;
|
|
case AArch64::LD3R_WB_4H_fixed: case AArch64::LD3R_WB_4H_register:
|
|
TransferBytes = 6; break;
|
|
case AArch64::LD3R_WB_2S_fixed: case AArch64::LD3R_WB_2S_register:
|
|
TransferBytes = 12; break;
|
|
case AArch64::LD3R_WB_1D_fixed: case AArch64::LD3R_WB_1D_register:
|
|
TransferBytes = 24; break;
|
|
}
|
|
Is64bitVec = true;
|
|
IsLoadDup = true;
|
|
NumVecs = 3;
|
|
break;
|
|
}
|
|
|
|
case AArch64::LD3R_WB_16B_fixed: case AArch64::LD3R_WB_16B_register:
|
|
case AArch64::LD3R_WB_4S_fixed: case AArch64::LD3R_WB_8H_register:
|
|
case AArch64::LD3R_WB_8H_fixed: case AArch64::LD3R_WB_4S_register:
|
|
case AArch64::LD3R_WB_2D_fixed: case AArch64::LD3R_WB_2D_register: {
|
|
switch (Opc) {
|
|
case AArch64::LD3R_WB_16B_fixed: case AArch64::LD3R_WB_16B_register:
|
|
TransferBytes = 3; break;
|
|
case AArch64::LD3R_WB_8H_fixed: case AArch64::LD3R_WB_8H_register:
|
|
TransferBytes = 6; break;
|
|
case AArch64::LD3R_WB_4S_fixed: case AArch64::LD3R_WB_4S_register:
|
|
TransferBytes = 12; break;
|
|
case AArch64::LD3R_WB_2D_fixed: case AArch64::LD3R_WB_2D_register:
|
|
TransferBytes = 24; break;
|
|
}
|
|
IsLoadDup = true;
|
|
NumVecs = 3;
|
|
break;
|
|
}
|
|
|
|
case AArch64::LD4R_WB_8B_fixed: case AArch64::LD4R_WB_8B_register:
|
|
case AArch64::LD4R_WB_4H_fixed: case AArch64::LD4R_WB_4H_register:
|
|
case AArch64::LD4R_WB_2S_fixed: case AArch64::LD4R_WB_2S_register:
|
|
case AArch64::LD4R_WB_1D_fixed: case AArch64::LD4R_WB_1D_register: {
|
|
switch (Opc) {
|
|
case AArch64::LD4R_WB_8B_fixed: case AArch64::LD4R_WB_8B_register:
|
|
TransferBytes = 4; break;
|
|
case AArch64::LD4R_WB_4H_fixed: case AArch64::LD4R_WB_4H_register:
|
|
TransferBytes = 8; break;
|
|
case AArch64::LD4R_WB_2S_fixed: case AArch64::LD4R_WB_2S_register:
|
|
TransferBytes = 16; break;
|
|
case AArch64::LD4R_WB_1D_fixed: case AArch64::LD4R_WB_1D_register:
|
|
TransferBytes = 32; break;
|
|
}
|
|
Is64bitVec = true;
|
|
IsLoadDup = true;
|
|
NumVecs = 4;
|
|
break;
|
|
}
|
|
|
|
case AArch64::LD4R_WB_16B_fixed: case AArch64::LD4R_WB_16B_register:
|
|
case AArch64::LD4R_WB_4S_fixed: case AArch64::LD4R_WB_8H_register:
|
|
case AArch64::LD4R_WB_8H_fixed: case AArch64::LD4R_WB_4S_register:
|
|
case AArch64::LD4R_WB_2D_fixed: case AArch64::LD4R_WB_2D_register: {
|
|
switch (Opc) {
|
|
case AArch64::LD4R_WB_16B_fixed: case AArch64::LD4R_WB_16B_register:
|
|
TransferBytes = 4; break;
|
|
case AArch64::LD4R_WB_8H_fixed: case AArch64::LD4R_WB_8H_register:
|
|
TransferBytes = 8; break;
|
|
case AArch64::LD4R_WB_4S_fixed: case AArch64::LD4R_WB_4S_register:
|
|
TransferBytes = 16; break;
|
|
case AArch64::LD4R_WB_2D_fixed: case AArch64::LD4R_WB_2D_register:
|
|
TransferBytes = 32; break;
|
|
}
|
|
IsLoadDup = true;
|
|
NumVecs = 4;
|
|
break;
|
|
}
|
|
|
|
case AArch64::LD1LN_WB_B_fixed: case AArch64::LD1LN_WB_B_register:
|
|
case AArch64::LD1LN_WB_H_fixed: case AArch64::LD1LN_WB_H_register:
|
|
case AArch64::LD1LN_WB_S_fixed: case AArch64::LD1LN_WB_S_register:
|
|
case AArch64::LD1LN_WB_D_fixed: case AArch64::LD1LN_WB_D_register: {
|
|
switch (Opc) {
|
|
case AArch64::LD1LN_WB_B_fixed: case AArch64::LD1LN_WB_B_register:
|
|
TransferBytes = 1; break;
|
|
case AArch64::LD1LN_WB_H_fixed: case AArch64::LD1LN_WB_H_register:
|
|
TransferBytes = 2; break;
|
|
case AArch64::LD1LN_WB_S_fixed: case AArch64::LD1LN_WB_S_register:
|
|
TransferBytes = 4; break;
|
|
case AArch64::LD1LN_WB_D_fixed: case AArch64::LD1LN_WB_D_register:
|
|
TransferBytes = 8; break;
|
|
}
|
|
IsLoad = true;
|
|
NumVecs = 1;
|
|
break;
|
|
}
|
|
|
|
case AArch64::LD2LN_WB_B_fixed: case AArch64::LD2LN_WB_B_register:
|
|
case AArch64::LD2LN_WB_H_fixed: case AArch64::LD2LN_WB_H_register:
|
|
case AArch64::LD2LN_WB_S_fixed: case AArch64::LD2LN_WB_S_register:
|
|
case AArch64::LD2LN_WB_D_fixed: case AArch64::LD2LN_WB_D_register: {
|
|
switch (Opc) {
|
|
case AArch64::LD2LN_WB_B_fixed: case AArch64::LD2LN_WB_B_register:
|
|
TransferBytes = 2; break;
|
|
case AArch64::LD2LN_WB_H_fixed: case AArch64::LD2LN_WB_H_register:
|
|
TransferBytes = 4; break;
|
|
case AArch64::LD2LN_WB_S_fixed: case AArch64::LD2LN_WB_S_register:
|
|
TransferBytes = 8; break;
|
|
case AArch64::LD2LN_WB_D_fixed: case AArch64::LD2LN_WB_D_register:
|
|
TransferBytes = 16; break;
|
|
}
|
|
IsLoad = true;
|
|
NumVecs = 2;
|
|
break;
|
|
}
|
|
|
|
case AArch64::LD3LN_WB_B_fixed: case AArch64::LD3LN_WB_B_register:
|
|
case AArch64::LD3LN_WB_H_fixed: case AArch64::LD3LN_WB_H_register:
|
|
case AArch64::LD3LN_WB_S_fixed: case AArch64::LD3LN_WB_S_register:
|
|
case AArch64::LD3LN_WB_D_fixed: case AArch64::LD3LN_WB_D_register: {
|
|
switch (Opc) {
|
|
case AArch64::LD3LN_WB_B_fixed: case AArch64::LD3LN_WB_B_register:
|
|
TransferBytes = 3; break;
|
|
case AArch64::LD3LN_WB_H_fixed: case AArch64::LD3LN_WB_H_register:
|
|
TransferBytes = 6; break;
|
|
case AArch64::LD3LN_WB_S_fixed: case AArch64::LD3LN_WB_S_register:
|
|
TransferBytes = 12; break;
|
|
case AArch64::LD3LN_WB_D_fixed: case AArch64::LD3LN_WB_D_register:
|
|
TransferBytes = 24; break;
|
|
}
|
|
IsLoad = true;
|
|
NumVecs = 3;
|
|
break;
|
|
}
|
|
|
|
case AArch64::LD4LN_WB_B_fixed: case AArch64::LD4LN_WB_B_register:
|
|
case AArch64::LD4LN_WB_H_fixed: case AArch64::LD4LN_WB_H_register:
|
|
case AArch64::LD4LN_WB_S_fixed: case AArch64::LD4LN_WB_S_register:
|
|
case AArch64::LD4LN_WB_D_fixed: case AArch64::LD4LN_WB_D_register: {
|
|
switch (Opc) {
|
|
case AArch64::LD4LN_WB_B_fixed: case AArch64::LD4LN_WB_B_register:
|
|
TransferBytes = 4; break;
|
|
case AArch64::LD4LN_WB_H_fixed: case AArch64::LD4LN_WB_H_register:
|
|
TransferBytes = 8; break;
|
|
case AArch64::LD4LN_WB_S_fixed: case AArch64::LD4LN_WB_S_register:
|
|
TransferBytes = 16; break;
|
|
case AArch64::LD4LN_WB_D_fixed: case AArch64::LD4LN_WB_D_register:
|
|
TransferBytes = 32; break;
|
|
}
|
|
IsLoad = true;
|
|
NumVecs = 4;
|
|
break;
|
|
}
|
|
|
|
case AArch64::ST1LN_WB_B_fixed: case AArch64::ST1LN_WB_B_register:
|
|
case AArch64::ST1LN_WB_H_fixed: case AArch64::ST1LN_WB_H_register:
|
|
case AArch64::ST1LN_WB_S_fixed: case AArch64::ST1LN_WB_S_register:
|
|
case AArch64::ST1LN_WB_D_fixed: case AArch64::ST1LN_WB_D_register: {
|
|
switch (Opc) {
|
|
case AArch64::ST1LN_WB_B_fixed: case AArch64::ST1LN_WB_B_register:
|
|
TransferBytes = 1; break;
|
|
case AArch64::ST1LN_WB_H_fixed: case AArch64::ST1LN_WB_H_register:
|
|
TransferBytes = 2; break;
|
|
case AArch64::ST1LN_WB_S_fixed: case AArch64::ST1LN_WB_S_register:
|
|
TransferBytes = 4; break;
|
|
case AArch64::ST1LN_WB_D_fixed: case AArch64::ST1LN_WB_D_register:
|
|
TransferBytes = 8; break;
|
|
}
|
|
NumVecs = 1;
|
|
break;
|
|
}
|
|
|
|
case AArch64::ST2LN_WB_B_fixed: case AArch64::ST2LN_WB_B_register:
|
|
case AArch64::ST2LN_WB_H_fixed: case AArch64::ST2LN_WB_H_register:
|
|
case AArch64::ST2LN_WB_S_fixed: case AArch64::ST2LN_WB_S_register:
|
|
case AArch64::ST2LN_WB_D_fixed: case AArch64::ST2LN_WB_D_register: {
|
|
switch (Opc) {
|
|
case AArch64::ST2LN_WB_B_fixed: case AArch64::ST2LN_WB_B_register:
|
|
TransferBytes = 2; break;
|
|
case AArch64::ST2LN_WB_H_fixed: case AArch64::ST2LN_WB_H_register:
|
|
TransferBytes = 4; break;
|
|
case AArch64::ST2LN_WB_S_fixed: case AArch64::ST2LN_WB_S_register:
|
|
TransferBytes = 8; break;
|
|
case AArch64::ST2LN_WB_D_fixed: case AArch64::ST2LN_WB_D_register:
|
|
TransferBytes = 16; break;
|
|
}
|
|
NumVecs = 2;
|
|
break;
|
|
}
|
|
|
|
case AArch64::ST3LN_WB_B_fixed: case AArch64::ST3LN_WB_B_register:
|
|
case AArch64::ST3LN_WB_H_fixed: case AArch64::ST3LN_WB_H_register:
|
|
case AArch64::ST3LN_WB_S_fixed: case AArch64::ST3LN_WB_S_register:
|
|
case AArch64::ST3LN_WB_D_fixed: case AArch64::ST3LN_WB_D_register: {
|
|
switch (Opc) {
|
|
case AArch64::ST3LN_WB_B_fixed: case AArch64::ST3LN_WB_B_register:
|
|
TransferBytes = 3; break;
|
|
case AArch64::ST3LN_WB_H_fixed: case AArch64::ST3LN_WB_H_register:
|
|
TransferBytes = 6; break;
|
|
case AArch64::ST3LN_WB_S_fixed: case AArch64::ST3LN_WB_S_register:
|
|
TransferBytes = 12; break;
|
|
case AArch64::ST3LN_WB_D_fixed: case AArch64::ST3LN_WB_D_register:
|
|
TransferBytes = 24; break;
|
|
}
|
|
NumVecs = 3;
|
|
break;
|
|
}
|
|
|
|
case AArch64::ST4LN_WB_B_fixed: case AArch64::ST4LN_WB_B_register:
|
|
case AArch64::ST4LN_WB_H_fixed: case AArch64::ST4LN_WB_H_register:
|
|
case AArch64::ST4LN_WB_S_fixed: case AArch64::ST4LN_WB_S_register:
|
|
case AArch64::ST4LN_WB_D_fixed: case AArch64::ST4LN_WB_D_register: {
|
|
switch (Opc) {
|
|
case AArch64::ST4LN_WB_B_fixed: case AArch64::ST4LN_WB_B_register:
|
|
TransferBytes = 4; break;
|
|
case AArch64::ST4LN_WB_H_fixed: case AArch64::ST4LN_WB_H_register:
|
|
TransferBytes = 8; break;
|
|
case AArch64::ST4LN_WB_S_fixed: case AArch64::ST4LN_WB_S_register:
|
|
TransferBytes = 16; break;
|
|
case AArch64::ST4LN_WB_D_fixed: case AArch64::ST4LN_WB_D_register:
|
|
TransferBytes = 32; break;
|
|
}
|
|
NumVecs = 4;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return MCDisassembler::Fail;
|
|
} // End of switch (Opc)
|
|
|
|
unsigned Rt = fieldFromInstruction(Insn, 0, 5);
|
|
unsigned Rn = fieldFromInstruction(Insn, 5, 5);
|
|
unsigned Rm = fieldFromInstruction(Insn, 16, 5);
|
|
|
|
// Decode post-index of load duplicate lane
|
|
if (IsLoadDup) {
|
|
switch (NumVecs) {
|
|
case 1:
|
|
Is64bitVec ? DecodeFPR64RegisterClass(Inst, Rt, Address, Decoder)
|
|
: DecodeFPR128RegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 2:
|
|
Is64bitVec ? DecodeDPairRegisterClass(Inst, Rt, Address, Decoder)
|
|
: DecodeQPairRegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 3:
|
|
Is64bitVec ? DecodeDTripleRegisterClass(Inst, Rt, Address, Decoder)
|
|
: DecodeQTripleRegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 4:
|
|
Is64bitVec ? DecodeDQuadRegisterClass(Inst, Rt, Address, Decoder)
|
|
: DecodeQQuadRegisterClass(Inst, Rt, Address, Decoder);
|
|
}
|
|
|
|
// Decode write back register, which is equal to Rn.
|
|
DecodeGPR64xspRegisterClass(Inst, Rn, Address, Decoder);
|
|
DecodeGPR64xspRegisterClass(Inst, Rn, Address, Decoder);
|
|
|
|
if (Rm == 31) // If Rm is 0x11111, add the number of transferred bytes
|
|
Inst.addOperand(MCOperand::CreateImm(TransferBytes));
|
|
else // Decode Rm
|
|
DecodeGPR64noxzrRegisterClass(Inst, Rm, Address, Decoder);
|
|
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
// Decode post-index of load/store lane
|
|
// Loads have a vector list as output.
|
|
if (IsLoad) {
|
|
switch (NumVecs) {
|
|
case 1:
|
|
DecodeFPR128RegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 2:
|
|
DecodeQPairRegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 3:
|
|
DecodeQTripleRegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 4:
|
|
DecodeQQuadRegisterClass(Inst, Rt, Address, Decoder);
|
|
}
|
|
}
|
|
|
|
// Decode write back register, which is equal to Rn.
|
|
DecodeGPR64xspRegisterClass(Inst, Rn, Address, Decoder);
|
|
DecodeGPR64xspRegisterClass(Inst, Rn, Address, Decoder);
|
|
|
|
if (Rm == 31) // If Rm is 0x11111, add the number of transferred bytes
|
|
Inst.addOperand(MCOperand::CreateImm(TransferBytes));
|
|
else // Decode Rm
|
|
DecodeGPR64noxzrRegisterClass(Inst, Rm, Address, Decoder);
|
|
|
|
// Decode the source vector list.
|
|
switch (NumVecs) {
|
|
case 1:
|
|
DecodeFPR128RegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 2:
|
|
DecodeQPairRegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 3:
|
|
DecodeQTripleRegisterClass(Inst, Rt, Address, Decoder);
|
|
break;
|
|
case 4:
|
|
DecodeQQuadRegisterClass(Inst, Rt, Address, Decoder);
|
|
}
|
|
|
|
// Decode lane
|
|
unsigned Q = fieldFromInstruction(Insn, 30, 1);
|
|
unsigned S = fieldFromInstruction(Insn, 10, 3);
|
|
unsigned lane = 0;
|
|
// Calculate the number of lanes by number of vectors and transfered bytes.
|
|
// NumLanes = 16 bytes / bytes of each lane
|
|
unsigned NumLanes = 16 / (TransferBytes / NumVecs);
|
|
switch (NumLanes) {
|
|
case 16: // A vector has 16 lanes, each lane is 1 bytes.
|
|
lane = (Q << 3) | S;
|
|
break;
|
|
case 8:
|
|
lane = (Q << 2) | (S >> 1);
|
|
break;
|
|
case 4:
|
|
lane = (Q << 1) | (S >> 2);
|
|
break;
|
|
case 2:
|
|
lane = Q;
|
|
break;
|
|
}
|
|
Inst.addOperand(MCOperand::CreateImm(lane));
|
|
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeSHLLInstruction(MCInst &Inst, unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
unsigned Rd = fieldFromInstruction(Insn, 0, 5);
|
|
unsigned Rn = fieldFromInstruction(Insn, 5, 5);
|
|
unsigned size = fieldFromInstruction(Insn, 22, 2);
|
|
unsigned Q = fieldFromInstruction(Insn, 30, 1);
|
|
|
|
DecodeFPR128RegisterClass(Inst, Rd, Address, Decoder);
|
|
|
|
if(Q)
|
|
DecodeFPR128RegisterClass(Inst, Rn, Address, Decoder);
|
|
else
|
|
DecodeFPR64RegisterClass(Inst, Rn, Address, Decoder);
|
|
|
|
switch (size) {
|
|
case 0:
|
|
Inst.addOperand(MCOperand::CreateImm(8));
|
|
break;
|
|
case 1:
|
|
Inst.addOperand(MCOperand::CreateImm(16));
|
|
break;
|
|
case 2:
|
|
Inst.addOperand(MCOperand::CreateImm(32));
|
|
break;
|
|
default :
|
|
return MCDisassembler::Fail;
|
|
}
|
|
return MCDisassembler::Success;
|
|
}
|
|
|