| //===-- RISCVDisassembler.cpp - Disassembler for RISC-V -------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file implements the RISCVDisassembler class. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "MCTargetDesc/RISCVBaseInfo.h" | |
| #include "MCTargetDesc/RISCVMCTargetDesc.h" | |
| #include "TargetInfo/RISCVTargetInfo.h" | |
| #include "llvm/MC/MCContext.h" | |
| #include "llvm/MC/MCDecoder.h" | |
| #include "llvm/MC/MCDecoderOps.h" | |
| #include "llvm/MC/MCDisassembler/MCDisassembler.h" | |
| #include "llvm/MC/MCInst.h" | |
| #include "llvm/MC/MCInstrInfo.h" | |
| #include "llvm/MC/MCRegisterInfo.h" | |
| #include "llvm/MC/MCSubtargetInfo.h" | |
| #include "llvm/MC/TargetRegistry.h" | |
| #include "llvm/Support/Compiler.h" | |
| #include "llvm/Support/Endian.h" | |
| using namespace llvm; | |
| using namespace llvm::MCD; | |
| #define DEBUG_TYPE "riscv-disassembler" | |
| typedef MCDisassembler::DecodeStatus DecodeStatus; | |
| namespace { | |
| class RISCVDisassembler : public MCDisassembler { | |
| std::unique_ptr<MCInstrInfo const> const MCII; | |
| public: | |
| RISCVDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, | |
| MCInstrInfo const *MCII) | |
| : MCDisassembler(STI, Ctx), MCII(MCII) {} | |
| DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, | |
| ArrayRef<uint8_t> Bytes, uint64_t Address, | |
| raw_ostream &CStream) const override; | |
| private: | |
| DecodeStatus getInstruction48(MCInst &Instr, uint64_t &Size, | |
| ArrayRef<uint8_t> Bytes, uint64_t Address, | |
| raw_ostream &CStream) const; | |
| DecodeStatus getInstruction32(MCInst &Instr, uint64_t &Size, | |
| ArrayRef<uint8_t> Bytes, uint64_t Address, | |
| raw_ostream &CStream) const; | |
| DecodeStatus getInstruction16(MCInst &Instr, uint64_t &Size, | |
| ArrayRef<uint8_t> Bytes, uint64_t Address, | |
| raw_ostream &CStream) const; | |
| }; | |
| } // end anonymous namespace | |
| static MCDisassembler *createRISCVDisassembler(const Target &T, | |
| const MCSubtargetInfo &STI, | |
| MCContext &Ctx) { | |
| return new RISCVDisassembler(STI, Ctx, T.createMCInstrInfo()); | |
| } | |
| static MCSymbolizer * | |
| createRISCVMCSymbolizer(const Triple &TT, LLVMOpInfoCallback GetOpInfo, | |
| LLVMSymbolLookupCallback /*SymbolLookUp*/, | |
| void *DisInfo, MCContext *Ctx, | |
| std::unique_ptr<MCRelocationInfo> &&RelInfo) { | |
| // RISC-V only asks MCSymbolizer to decode HI20/LO12 address fragments. They | |
| // require relocation information and cannot be looked up as absolute | |
| // addresses when GetOpInfo fails. | |
| return llvm::createMCSymbolizer(TT, GetOpInfo, /*SymbolLookUp=*/nullptr, | |
| DisInfo, Ctx, std::move(RelInfo)); | |
| } | |
| extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void | |
| LLVMInitializeRISCVDisassembler() { | |
| // Register the disassembler for each target. | |
| TargetRegistry::RegisterMCDisassembler(getTheRISCV32Target(), | |
| createRISCVDisassembler); | |
| TargetRegistry::RegisterMCSymbolizer(getTheRISCV32Target(), | |
| createRISCVMCSymbolizer); | |
| TargetRegistry::RegisterMCDisassembler(getTheRISCV64Target(), | |
| createRISCVDisassembler); | |
| TargetRegistry::RegisterMCSymbolizer(getTheRISCV64Target(), | |
| createRISCVMCSymbolizer); | |
| TargetRegistry::RegisterMCDisassembler(getTheRISCV32beTarget(), | |
| createRISCVDisassembler); | |
| TargetRegistry::RegisterMCSymbolizer(getTheRISCV32beTarget(), | |
| createRISCVMCSymbolizer); | |
| TargetRegistry::RegisterMCDisassembler(getTheRISCV64beTarget(), | |
| createRISCVDisassembler); | |
| TargetRegistry::RegisterMCSymbolizer(getTheRISCV64beTarget(), | |
| createRISCVMCSymbolizer); | |
| } | |
| template <unsigned FirstReg, unsigned NumRegsInClass, unsigned RVELimit = 0> | |
| static DecodeStatus DecodeSimpleRegisterClass(MCInst &Inst, uint32_t RegNo, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| bool CheckRVE = RVELimit != 0 && | |
| Decoder->getSubtargetInfo().hasFeature(RISCV::FeatureStdExtE); | |
| if (RegNo >= NumRegsInClass || (CheckRVE && RegNo >= RVELimit)) | |
| return MCDisassembler::Fail; | |
| MCRegister Reg = FirstReg + RegNo; | |
| Inst.addOperand(MCOperand::createReg(Reg)); | |
| return MCDisassembler::Success; | |
| } | |
| template <unsigned PhysReg, unsigned Encoding> | |
| static DecodeStatus DecodeSingleRegister(MCInst &Inst, uint32_t RegNo, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| assert(RegNo == Encoding); | |
| Inst.addOperand(MCOperand::createReg(PhysReg)); | |
| return MCDisassembler::Success; | |
| } | |
| template <unsigned PhysReg, unsigned Encoding> | |
| static DecodeStatus DecodeSingleRegister(MCInst &Inst, | |
| const MCDisassembler *Decoder) { | |
| Inst.addOperand(MCOperand::createReg(PhysReg)); | |
| return MCDisassembler::Success; | |
| } | |
| constexpr auto DecodeGPRRegisterClass = | |
| DecodeSimpleRegisterClass<RISCV::X0, 32, /*RVELimit=*/16>; | |
| template <auto DecodeFn, auto PredicateFn> | |
| static DecodeStatus DecodeFilteredRegisterClass(MCInst &Inst, uint32_t RegNo, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| if (!PredicateFn(RegNo)) | |
| return MCDisassembler::Fail; | |
| return DecodeFn(Inst, RegNo, Address, Decoder); | |
| } | |
| constexpr bool PredNoX0(uint32_t RegNo) { return RegNo != 0; } | |
| constexpr bool PredNoX2(uint32_t RegNo) { return RegNo != 2; } | |
| constexpr bool PredNoX31(uint32_t RegNo) { return RegNo != 31; } | |
| constexpr bool PredX1OrX5(uint32_t RegNo) { return RegNo == 1 || RegNo == 5; } | |
| constexpr auto DecodeGPRNoX0RegisterClass = | |
| DecodeFilteredRegisterClass<DecodeGPRRegisterClass, PredNoX0>; | |
| constexpr auto DecodeGPRNoX2RegisterClass = | |
| DecodeFilteredRegisterClass<DecodeGPRRegisterClass, PredNoX2>; | |
| constexpr auto DecodeGPRNoX31RegisterClass = | |
| DecodeFilteredRegisterClass<DecodeGPRRegisterClass, PredNoX31>; | |
| constexpr auto DecodeGPRX1X5RegisterClass = | |
| DecodeFilteredRegisterClass<DecodeGPRRegisterClass, PredX1OrX5>; | |
| static DecodeStatus decodeTHMemIdxRs1Operand(MCInst &Inst, uint32_t RegNo, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| const DecodeStatus Result = | |
| DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder); | |
| if (Result != MCDisassembler::Success) | |
| return Result; | |
| const MCRegister Rd = Inst.getOperand(0).getReg(); | |
| const MCRegister Rs1 = Inst.getOperand(Inst.getNumOperands() - 1).getReg(); | |
| if (Rd == Rs1) | |
| return MCDisassembler::Fail; | |
| return Result; | |
| } | |
| static DecodeStatus decodeTHMemPairRs1Operand(MCInst &Inst, uint32_t RegNo, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| const DecodeStatus Result = | |
| DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder); | |
| if (Result != MCDisassembler::Success) | |
| return Result; | |
| const MCRegister Rd1 = Inst.getOperand(0).getReg(); | |
| const MCRegister Rd2 = Inst.getOperand(1).getReg(); | |
| const MCRegister Rs1 = Inst.getOperand(Inst.getNumOperands() - 1).getReg(); | |
| if (Rs1 == Rd1 || Rs1 == Rd2 || Rd1 == Rd2) | |
| return MCDisassembler::Fail; | |
| return Result; | |
| } | |
| static DecodeStatus DecodeGPRPairRegisterClass(MCInst &Inst, uint32_t RegNo, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| if (RegNo >= 32 || RegNo % 2) | |
| return MCDisassembler::Fail; | |
| bool IsRVE = Decoder->getSubtargetInfo().hasFeature(RISCV::FeatureStdExtE); | |
| if (IsRVE && RegNo >= 16) | |
| return MCDisassembler::Fail; | |
| const RISCVDisassembler *Dis = | |
| static_cast<const RISCVDisassembler *>(Decoder); | |
| const MCRegisterInfo *RI = Dis->getContext().getRegisterInfo(); | |
| MCRegister Reg = RI->getMatchingSuperReg( | |
| RISCV::X0 + RegNo, RISCV::sub_gpr_even, | |
| &getRISCVMCRegisterClass(RISCV::GPRPairRegClassID)); | |
| Inst.addOperand(MCOperand::createReg(Reg)); | |
| return MCDisassembler::Success; | |
| } | |
| constexpr auto DecodeGPRPairNoX0RegisterClass = | |
| DecodeFilteredRegisterClass<DecodeGPRPairRegisterClass, PredNoX0>; | |
| static DecodeStatus DecodeGPRPairCRegisterClass(MCInst &Inst, uint32_t RegNo, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| if (RegNo >= 8 || RegNo % 2) | |
| return MCDisassembler::Fail; | |
| return DecodeGPRPairRegisterClass(Inst, RegNo + 8, Address, Decoder); | |
| } | |
| static DecodeStatus DecodeGPRS07RegisterClass(MCInst &Inst, uint32_t RegNo, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| // Only s0 and s1 exist on RVE, so sreg values above 1 are reserved. | |
| bool IsRVE = Decoder->getSubtargetInfo().hasFeature(RISCV::FeatureStdExtE); | |
| if (RegNo >= 8 || (IsRVE && RegNo > 1)) | |
| return MCDisassembler::Fail; | |
| MCRegister Reg = (RegNo < 2) ? (RegNo + RISCV::X8) : (RegNo - 2 + RISCV::X18); | |
| Inst.addOperand(MCOperand::createReg(Reg)); | |
| return MCDisassembler::Success; | |
| } | |
| template <unsigned RegisterClass, unsigned NumRegsInClass, unsigned LMul> | |
| static DecodeStatus DecodeVectorRegisterClass(MCInst &Inst, uint32_t RegNo, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| if (RegNo >= NumRegsInClass || RegNo % LMul) | |
| return MCDisassembler::Fail; | |
| const RISCVDisassembler *Dis = | |
| static_cast<const RISCVDisassembler *>(Decoder); | |
| const MCRegisterInfo *RI = Dis->getContext().getRegisterInfo(); | |
| MCRegister Reg = | |
| RI->getMatchingSuperReg(RISCV::V0 + RegNo, RISCV::sub_vrm1_0, | |
| &getRISCVMCRegisterClass(RegisterClass)); | |
| Inst.addOperand(MCOperand::createReg(Reg)); | |
| return MCDisassembler::Success; | |
| } | |
| static DecodeStatus DecodeTRM2RegisterClass(MCInst &Inst, uint32_t RegNo, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| if (RegNo > 15 || RegNo % 2) | |
| return MCDisassembler::Fail; | |
| MCRegister Reg = RISCV::T0 + RegNo; | |
| Inst.addOperand(MCOperand::createReg(Reg)); | |
| return MCDisassembler::Success; | |
| } | |
| static DecodeStatus DecodeTRM4RegisterClass(MCInst &Inst, uint32_t RegNo, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| if (RegNo > 15 || RegNo % 4) | |
| return MCDisassembler::Fail; | |
| MCRegister Reg = RISCV::T0 + RegNo; | |
| Inst.addOperand(MCOperand::createReg(Reg)); | |
| return MCDisassembler::Success; | |
| } | |
| static DecodeStatus DecodeYBNDSWImm(MCInst &Inst, uint64_t Imm, int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| assert(isUInt<9>(Imm) && "Invalid immediate"); | |
| uint64_t Result; | |
| if (Imm == 0) { | |
| // If imm[8:0] == 0, result is 4096. | |
| Result = 4096; | |
| } else if (Imm <= 255) { | |
| // If imm[8] == 0 and imm[7:0] != 0, result is imm[7:0]. | |
| Result = Imm; | |
| } else { | |
| uint64_t Imm7To0 = Imm & 0xFF; | |
| if (Imm7To0 <= 31) { | |
| // If imm[8] == 1 and imm[7:5] == 0 (i.e. imm[7:0] <= 31), result is | |
| // `256 | (imm[3:0] << 4) | (imm[4] << 3)`. | |
| Result = 256 + ((Imm & 0xF) << 4) + (((Imm >> 4) & 1) << 3); | |
| } else { | |
| // Otherwise, result is imm[7:0] << 4. | |
| Result = Imm7To0 << 4; | |
| } | |
| } | |
| Inst.addOperand(MCOperand::createImm(Result)); | |
| return MCDisassembler::Success; | |
| } | |
| static DecodeStatus decodeVMaskReg(MCInst &Inst, uint32_t RegNo, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| if (RegNo >= 2) | |
| return MCDisassembler::Fail; | |
| MCRegister Reg = (RegNo == 0) ? RISCV::V0 : RISCV::NoRegister; | |
| Inst.addOperand(MCOperand::createReg(Reg)); | |
| return MCDisassembler::Success; | |
| } | |
| template <int64_t Imm> | |
| static DecodeStatus decodeFixedImmOperand(MCInst &Inst, | |
| const MCDisassembler *Decoder) { | |
| Inst.addOperand(MCOperand::createImm(Imm)); | |
| return MCDisassembler::Success; | |
| } | |
| template <unsigned N, unsigned LowerBound = 0> | |
| static DecodeStatus decodeUImmOperand(MCInst &Inst, uint32_t Imm, | |
| int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| assert(isUInt<N>(Imm) && "Invalid immediate"); | |
| if (Imm < LowerBound) | |
| return MCDisassembler::Fail; | |
| Inst.addOperand(MCOperand::createImm(Imm)); | |
| return MCDisassembler::Success; | |
| } | |
| static DecodeStatus decodeUImmSlistOperand(MCInst &Inst, uint32_t Imm, | |
| int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| assert(isUInt<3>(Imm) && "Invalid Slist immediate"); | |
| const uint8_t Slist[] = {0, 1, 2, 4, 8, 16, 15, 31}; | |
| Inst.addOperand(MCOperand::createImm(Slist[Imm])); | |
| return MCDisassembler::Success; | |
| } | |
| static DecodeStatus decodeUImmLog2XLenOperand(MCInst &Inst, uint32_t Imm, | |
| int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| assert(isUInt<6>(Imm) && "Invalid immediate"); | |
| if (!Decoder->getSubtargetInfo().hasFeature(RISCV::Feature64Bit) && | |
| !isUInt<5>(Imm)) | |
| return MCDisassembler::Fail; | |
| Inst.addOperand(MCOperand::createImm(Imm)); | |
| return MCDisassembler::Success; | |
| } | |
| template <unsigned N> | |
| static DecodeStatus decodeUImmNonZeroOperand(MCInst &Inst, uint32_t Imm, | |
| int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| if (Imm == 0) | |
| return MCDisassembler::Fail; | |
| return decodeUImmOperand<N>(Inst, Imm, Address, Decoder); | |
| } | |
| static DecodeStatus | |
| decodeUImmLog2XLenNonZeroOperand(MCInst &Inst, uint32_t Imm, int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| if (Imm == 0) | |
| return MCDisassembler::Fail; | |
| return decodeUImmLog2XLenOperand(Inst, Imm, Address, Decoder); | |
| } | |
| template <unsigned N, unsigned LowerBound = 1> | |
| static DecodeStatus decodeUImmPlus1Operand(MCInst &Inst, uint32_t Imm, | |
| int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| assert(isUInt<N>(Imm) && "Invalid immediate"); | |
| if ((Imm + 1) < LowerBound) | |
| return MCDisassembler::Fail; | |
| Inst.addOperand(MCOperand::createImm(Imm + 1)); | |
| return MCDisassembler::Success; | |
| } | |
| static DecodeStatus decodeImmZibiOperand(MCInst &Inst, uint32_t Imm, | |
| int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| assert(isUInt<5>(Imm) && "Invalid immediate"); | |
| Inst.addOperand(MCOperand::createImm(Imm ? Imm : -1LL)); | |
| return MCDisassembler::Success; | |
| } | |
| template <unsigned N> | |
| static DecodeStatus decodeSImmOperand(MCInst &Inst, uint32_t Imm, | |
| int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| assert(isUInt<N>(Imm) && "Invalid immediate"); | |
| // Sign-extend the number in the bottom N bits of Imm | |
| Inst.addOperand(MCOperand::createImm(SignExtend64<N>(Imm))); | |
| return MCDisassembler::Success; | |
| } | |
| static DecodeStatus decodeSImm12LoOperand(MCInst &Inst, uint32_t Imm, | |
| int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| assert(isUInt<12>(Imm) && "Invalid immediate"); | |
| const int64_t Value = SignExtend64<12>(Imm); | |
| if (!Decoder->tryAddingSymbolicOperand(Inst, Value, Address, | |
| /*IsBranch=*/false, | |
| /*Offset=*/0, /*OpSize=*/4, | |
| /*InstSize=*/4)) | |
| Inst.addOperand(MCOperand::createImm(Value)); | |
| return MCDisassembler::Success; | |
| } | |
| static DecodeStatus decodeUImm20Operand(MCInst &Inst, uint32_t Imm, | |
| int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| assert(isUInt<20>(Imm) && "Invalid immediate"); | |
| const int64_t Value = SignExtend64<32>(Imm << 12); | |
| if (!Decoder->tryAddingSymbolicOperand(Inst, Value, Address, | |
| /*IsBranch=*/false, | |
| /*Offset=*/0, /*OpSize=*/4, | |
| /*InstSize=*/4)) | |
| Inst.addOperand(MCOperand::createImm(Imm)); | |
| return MCDisassembler::Success; | |
| } | |
| template <unsigned N> | |
| static DecodeStatus decodeSImmNonZeroOperand(MCInst &Inst, uint32_t Imm, | |
| int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| if (Imm == 0) | |
| return MCDisassembler::Fail; | |
| return decodeSImmOperand<N>(Inst, Imm, Address, Decoder); | |
| } | |
| template <unsigned T, unsigned N> | |
| static DecodeStatus decodeSImmOperandAndLslN(MCInst &Inst, uint32_t Imm, | |
| int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| assert(isUInt<T - N + 1>(Imm) && "Invalid immediate"); | |
| // Sign-extend the number in the bottom T bits of Imm after accounting for | |
| // the fact that the T bit immediate is stored in T-N bits (the LSB is | |
| // always zero) | |
| Inst.addOperand(MCOperand::createImm(SignExtend64<T>(Imm << N))); | |
| return MCDisassembler::Success; | |
| } | |
| static DecodeStatus decodeCLUIImmOperand(MCInst &Inst, uint32_t Imm, | |
| int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| assert(isUInt<6>(Imm) && "Invalid immediate"); | |
| if (Imm == 0) | |
| return MCDisassembler::Fail; | |
| Imm = SignExtend64<6>(Imm) & 0xfffff; | |
| Inst.addOperand(MCOperand::createImm(Imm)); | |
| return MCDisassembler::Success; | |
| } | |
| static DecodeStatus decodeFRMArg(MCInst &Inst, uint32_t Imm, int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| assert(isUInt<3>(Imm) && "Invalid immediate"); | |
| if (!llvm::RISCVFPRndMode::isValidRoundingMode(Imm)) | |
| return MCDisassembler::Fail; | |
| Inst.addOperand(MCOperand::createImm(Imm)); | |
| return MCDisassembler::Success; | |
| } | |
| static DecodeStatus decodeCVInsertIs2Operand(MCInst &Inst, uint32_t Imm, | |
| int64_t Address, | |
| const MCDisassembler *Decoder) { | |
| const int64_t Is3 = Inst.getOperand(Inst.getNumOperands() - 1).getImm(); | |
| if (Is3 + Imm >= 32) | |
| return MCDisassembler::Fail; | |
| return decodeUImmOperand<5>(Inst, Imm, Address, Decoder); | |
| } | |
| static DecodeStatus decodeZcmpRlist(MCInst &Inst, uint32_t Imm, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| bool IsRVE = Decoder->getSubtargetInfo().hasFeature(RISCV::FeatureStdExtE); | |
| if (Imm < RISCVZC::RA || (IsRVE && Imm >= RISCVZC::RA_S0_S2)) | |
| return MCDisassembler::Fail; | |
| Inst.addOperand(MCOperand::createImm(Imm)); | |
| return MCDisassembler::Success; | |
| } | |
| static DecodeStatus decodeXqccmpRlistS0(MCInst &Inst, uint32_t Imm, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| if (Imm < RISCVZC::RA_S0) | |
| return MCDisassembler::Fail; | |
| return decodeZcmpRlist(Inst, Imm, Address, Decoder); | |
| } | |
| static DecodeStatus decodeMvsa01Rs2Operand(MCInst &Inst, uint32_t RegNo, | |
| uint64_t Address, | |
| const MCDisassembler *Decoder) { | |
| const DecodeStatus Result = | |
| DecodeGPRS07RegisterClass(Inst, RegNo, Address, Decoder); | |
| if (Result != MCDisassembler::Success) | |
| return Result; | |
| if (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg()) | |
| return MCDisassembler::Fail; | |
| return MCDisassembler::Success; | |
| } | |
| #include "RISCVGenDisassemblerTables.inc" | |
| namespace { | |
| struct DecoderListEntry { | |
| const uint8_t *Table; | |
| FeatureBitset ContainedFeatures; | |
| const char *Desc; | |
| bool haveContainedFeatures(const FeatureBitset &ActiveFeatures) const { | |
| return ContainedFeatures.none() || | |
| (ContainedFeatures & ActiveFeatures).any(); | |
| } | |
| }; | |
| } // end anonymous namespace | |
| static constexpr FeatureBitset XCVFeatureGroup = { | |
| RISCV::FeatureVendorXCVbitmanip, RISCV::FeatureVendorXCVelw, | |
| RISCV::FeatureVendorXCVmac, RISCV::FeatureVendorXCVmem, | |
| RISCV::FeatureVendorXCValu, RISCV::FeatureVendorXCVsimd, | |
| RISCV::FeatureVendorXCVbi}; | |
| static constexpr FeatureBitset XqciFeatureGroup = { | |
| RISCV::FeatureVendorXqcia, RISCV::FeatureVendorXqciac, | |
| RISCV::FeatureVendorXqcibi, RISCV::FeatureVendorXqcibm, | |
| RISCV::FeatureVendorXqcicli, RISCV::FeatureVendorXqcicm, | |
| RISCV::FeatureVendorXqcics, RISCV::FeatureVendorXqcicsr, | |
| RISCV::FeatureVendorXqciint, RISCV::FeatureVendorXqciio, | |
| RISCV::FeatureVendorXqcilb, RISCV::FeatureVendorXqcili, | |
| RISCV::FeatureVendorXqcilia, RISCV::FeatureVendorXqcilo, | |
| RISCV::FeatureVendorXqcilsm, RISCV::FeatureVendorXqcisim, | |
| RISCV::FeatureVendorXqcisls, RISCV::FeatureVendorXqcisync, | |
| }; | |
| static constexpr FeatureBitset XSfVectorGroup = { | |
| RISCV::FeatureVendorXSfvcp, RISCV::FeatureVendorXSfvqmaccdod, | |
| RISCV::FeatureVendorXSfvqmaccqoq, RISCV::FeatureVendorXSfvfwmaccqqq, | |
| RISCV::FeatureVendorXSfvfnrclipxfqf, RISCV::FeatureVendorXSfmmbase, | |
| RISCV::FeatureVendorXSfvfexpa, RISCV::FeatureVendorXSfvfexpa64e, | |
| RISCV::FeatureVendorXSfvfbfexp16e, RISCV::FeatureVendorXSfvfexp16e, | |
| RISCV::FeatureVendorXSfvfexp32e}; | |
| static constexpr FeatureBitset XSfSystemGroup = { | |
| RISCV::FeatureVendorXSiFivecdiscarddlone, | |
| RISCV::FeatureVendorXSiFivecflushdlone, | |
| }; | |
| static constexpr FeatureBitset XMIPSGroup = { | |
| RISCV::FeatureVendorXMIPSLSP, | |
| RISCV::FeatureVendorXMIPSCMov, | |
| RISCV::FeatureVendorXMIPSCBOP, | |
| RISCV::FeatureVendorXMIPSEXECTL, | |
| }; | |
| static constexpr FeatureBitset XTHeadGroup = { | |
| RISCV::FeatureVendorXTHeadBa, RISCV::FeatureVendorXTHeadBb, | |
| RISCV::FeatureVendorXTHeadBs, RISCV::FeatureVendorXTHeadCondMov, | |
| RISCV::FeatureVendorXTHeadCmo, RISCV::FeatureVendorXTHeadFMemIdx, | |
| RISCV::FeatureVendorXTHeadMac, RISCV::FeatureVendorXTHeadMemIdx, | |
| RISCV::FeatureVendorXTHeadMemPair, RISCV::FeatureVendorXTHeadSync, | |
| RISCV::FeatureVendorXTHeadVdot}; | |
| static constexpr FeatureBitset XAndesGroup = { | |
| RISCV::FeatureVendorXAndesPerf, RISCV::FeatureVendorXAndesBFHCvt, | |
| RISCV::FeatureVendorXAndesVBFHCvt, RISCV::FeatureVendorXAndesVSIntH, | |
| RISCV::FeatureVendorXAndesVSIntLoad, RISCV::FeatureVendorXAndesVPackFPH, | |
| RISCV::FeatureVendorXAndesVDot}; | |
| static constexpr FeatureBitset XSMTGroup = {RISCV::FeatureVendorXSMTVDot, | |
| RISCV::FeatureVendorXSMTVDotII}; | |
| static constexpr FeatureBitset XAIFGroup = {RISCV::FeatureVendorXAIFET}; | |
| static constexpr DecoderListEntry DecoderList32[]{ | |
| // Vendor Extensions | |
| {DecoderTableXCV32, XCVFeatureGroup, "CORE-V extensions"}, | |
| {DecoderTableXqci32, XqciFeatureGroup, "Qualcomm uC Extensions"}, | |
| {DecoderTableXTHead32, XTHeadGroup, "T-Head extensions"}, | |
| {DecoderTableXSfvector32, XSfVectorGroup, "SiFive vector extensions"}, | |
| {DecoderTableXSfsystem32, XSfSystemGroup, "SiFive system extensions"}, | |
| {DecoderTableXSfcease32, {RISCV::FeatureVendorXSfcease}, "SiFive sf.cease"}, | |
| {DecoderTableXMIPS32, XMIPSGroup, "Mips extensions"}, | |
| {DecoderTableXAndes32, XAndesGroup, "Andes extensions"}, | |
| {DecoderTableXSMT32, XSMTGroup, "SpacemiT extensions"}, | |
| {DecoderTableXAIF32, XAIFGroup, "AI Foundry extensions"}, | |
| // Standard Extensions | |
| {DecoderTable32, {}, "standard 32-bit instructions"}, | |
| {DecoderTableRV32Only32, {}, "RV32-only standard 32-bit instructions"}, | |
| {DecoderTableZfinx32, {}, "Zfinx (Float in Integer)"}, | |
| {DecoderTableZdinxRV32Only32, {}, "RV32-only Zdinx (Double in Integer)"}, | |
| }; | |
| namespace { | |
| // Define bitwidths for various types used to instantiate the decoder. | |
| template <> constexpr uint32_t InsnBitWidth<uint16_t> = 16; | |
| template <> constexpr uint32_t InsnBitWidth<uint32_t> = 32; | |
| // Use uint64_t to represent 48 bit instructions. | |
| template <> constexpr uint32_t InsnBitWidth<uint64_t> = 48; | |
| } // namespace | |
| DecodeStatus RISCVDisassembler::getInstruction32(MCInst &MI, uint64_t &Size, | |
| ArrayRef<uint8_t> Bytes, | |
| uint64_t Address, | |
| raw_ostream &CS) const { | |
| if (Bytes.size() < 4) { | |
| Size = 0; | |
| return MCDisassembler::Fail; | |
| } | |
| Size = 4; | |
| uint32_t Insn = support::endian::read32le(Bytes.data()); | |
| for (const DecoderListEntry &Entry : DecoderList32) { | |
| if (!Entry.haveContainedFeatures(STI.getFeatureBits())) | |
| continue; | |
| LLVM_DEBUG(dbgs() << "Trying " << Entry.Desc << " table:\n"); | |
| DecodeStatus Result = | |
| decodeInstruction(Entry.Table, MI, Insn, Address, this, STI); | |
| if (Result == MCDisassembler::Fail) | |
| continue; | |
| return Result; | |
| } | |
| return MCDisassembler::Fail; | |
| } | |
| static constexpr DecoderListEntry DecoderList16[]{ | |
| // Vendor Extensions | |
| {DecoderTableXqci16, XqciFeatureGroup, "Qualcomm uC 16-bit"}, | |
| {DecoderTableXqccmp16, | |
| {RISCV::FeatureVendorXqccmp}, | |
| "Xqccmp (Qualcomm 16-bit Push/Pop & Double Move Instructions)"}, | |
| {DecoderTableXqccmi16, | |
| {RISCV::FeatureVendorXqccmi}, | |
| "Xqccmi (Qualcomm 16-bit Instruction Lookup Table)"}, | |
| {DecoderTableXqccmt16, | |
| {RISCV::FeatureVendorXqccmt}, | |
| "Xqccmt (Qualcomm 16-bit Table Jump Instructions)"}, | |
| {DecoderTableXwchc16, {RISCV::FeatureVendorXwchc}, "WCH QingKe XW"}, | |
| // Standard Extensions | |
| {DecoderTable16, {}, "standard 16-bit instructions"}, | |
| {DecoderTableRV32Only16, {}, "RV32-only 16-bit instructions"}, | |
| // Zc* instructions incompatible with Zcf or Zcd | |
| {DecoderTableZcOverlap16, | |
| {}, | |
| "ZcOverlap (16-bit Instructions overlapping with Zcf/Zcd)"}, | |
| }; | |
| DecodeStatus RISCVDisassembler::getInstruction16(MCInst &MI, uint64_t &Size, | |
| ArrayRef<uint8_t> Bytes, | |
| uint64_t Address, | |
| raw_ostream &CS) const { | |
| if (Bytes.size() < 2) { | |
| Size = 0; | |
| return MCDisassembler::Fail; | |
| } | |
| Size = 2; | |
| uint16_t Insn = support::endian::read16le(Bytes.data()); | |
| for (const DecoderListEntry &Entry : DecoderList16) { | |
| if (!Entry.haveContainedFeatures(STI.getFeatureBits())) | |
| continue; | |
| LLVM_DEBUG(dbgs() << "Trying " << Entry.Desc << " table:\n"); | |
| DecodeStatus Result = | |
| decodeInstruction(Entry.Table, MI, Insn, Address, this, STI); | |
| if (Result != MCDisassembler::Fail) | |
| return Result; | |
| } | |
| return MCDisassembler::Fail; | |
| } | |
| static constexpr DecoderListEntry DecoderList48[]{ | |
| {DecoderTableXqci48, XqciFeatureGroup, "Qualcomm uC 48bit"}, | |
| }; | |
| DecodeStatus RISCVDisassembler::getInstruction48(MCInst &MI, uint64_t &Size, | |
| ArrayRef<uint8_t> Bytes, | |
| uint64_t Address, | |
| raw_ostream &CS) const { | |
| if (Bytes.size() < 6) { | |
| Size = 0; | |
| return MCDisassembler::Fail; | |
| } | |
| Size = 6; | |
| uint64_t Insn = 0; | |
| for (size_t i = Size; i-- != 0;) | |
| Insn += (static_cast<uint64_t>(Bytes[i]) << 8 * i); | |
| for (const DecoderListEntry &Entry : DecoderList48) { | |
| if (!Entry.haveContainedFeatures(STI.getFeatureBits())) | |
| continue; | |
| LLVM_DEBUG(dbgs() << "Trying " << Entry.Desc << " table:\n"); | |
| DecodeStatus Result = | |
| decodeInstruction(Entry.Table, MI, Insn, Address, this, STI); | |
| if (Result == MCDisassembler::Fail) | |
| continue; | |
| return Result; | |
| } | |
| return MCDisassembler::Fail; | |
| } | |
| DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size, | |
| ArrayRef<uint8_t> Bytes, | |
| uint64_t Address, | |
| raw_ostream &CS) const { | |
| CommentStream = &CS; | |
| // It's a 16 bit instruction if bit 0 and 1 are not 0b11. | |
| if ((Bytes[0] & 0b11) != 0b11) | |
| return getInstruction16(MI, Size, Bytes, Address, CS); | |
| // Try to decode as a 32-bit instruction first. | |
| DecodeStatus Result = getInstruction32(MI, Size, Bytes, Address, CS); | |
| if (Result != MCDisassembler::Fail) | |
| return Result; | |
| // If bits [4:2] are 0b111 this might be a 48-bit or larger instruction, | |
| // otherwise assume it's an unknown 32-bit instruction. | |
| if ((Bytes[0] & 0b1'1100) != 0b1'1100) { | |
| Size = Bytes.size() >= 4 ? 4 : 0; | |
| return MCDisassembler::Fail; | |
| } | |
| // 48-bit instructions are encoded as 0bxx011111. | |
| if ((Bytes[0] & 0b11'1111) == 0b01'1111) | |
| return getInstruction48(MI, Size, Bytes, Address, CS); | |
| // 64-bit instructions are encoded as 0x0111111. | |
| if ((Bytes[0] & 0b111'1111) == 0b011'1111) { | |
| Size = Bytes.size() >= 8 ? 8 : 0; | |
| return MCDisassembler::Fail; | |
| } | |
| // Remaining cases need to check a second byte. | |
| if (Bytes.size() < 2) { | |
| Size = 0; | |
| return MCDisassembler::Fail; | |
| } | |
| // 80-bit through 176-bit instructions are encoded as 0bxnnnxxxx_x1111111. | |
| // Where the number of bits is (80 + (nnn * 16)) for nnn != 0b111. | |
| unsigned nnn = (Bytes[1] >> 4) & 0b111; | |
| if (nnn != 0b111) { | |
| Size = 10 + (nnn * 2); | |
| if (Bytes.size() < Size) | |
| Size = 0; | |
| return MCDisassembler::Fail; | |
| } | |
| // Remaining encodings are reserved for > 176-bit instructions. | |
| Size = 0; | |
| return MCDisassembler::Fail; | |
| } |