| //===-- LoongArchDisassembler.cpp - Disassembler for LoongArch ------------===// |
| // |
| // 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 LoongArchDisassembler class. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "MCTargetDesc/LoongArchBaseInfo.h" |
| #include "MCTargetDesc/LoongArchMCTargetDesc.h" |
| #include "TargetInfo/LoongArchTargetInfo.h" |
| #include "llvm/MC/MCContext.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/Endian.h" |
| |
| using namespace llvm; |
| |
| #define DEBUG_TYPE "loongarch-disassembler" |
| |
| typedef MCDisassembler::DecodeStatus DecodeStatus; |
| |
| namespace { |
| class LoongArchDisassembler : public MCDisassembler { |
| public: |
| LoongArchDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) |
| : MCDisassembler(STI, Ctx) {} |
| |
| DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, |
| ArrayRef<uint8_t> Bytes, uint64_t Address, |
| raw_ostream &CStream) const override; |
| }; |
| } // end namespace |
| |
| static MCDisassembler *createLoongArchDisassembler(const Target &T, |
| const MCSubtargetInfo &STI, |
| MCContext &Ctx) { |
| return new LoongArchDisassembler(STI, Ctx); |
| } |
| |
| extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchDisassembler() { |
| // Register the disassembler for each target. |
| TargetRegistry::RegisterMCDisassembler(getTheLoongArch32Target(), |
| createLoongArchDisassembler); |
| TargetRegistry::RegisterMCDisassembler(getTheLoongArch64Target(), |
| createLoongArchDisassembler); |
| } |
| |
| static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint64_t RegNo, |
| uint64_t Address, |
| const MCDisassembler *Decoder) { |
| if (RegNo >= 32) |
| return MCDisassembler::Fail; |
| Inst.addOperand(MCOperand::createReg(LoongArch::R0 + RegNo)); |
| return MCDisassembler::Success; |
| } |
| |
| static DecodeStatus DecodeFPR32RegisterClass(MCInst &Inst, uint64_t RegNo, |
| uint64_t Address, |
| const MCDisassembler *Decoder) { |
| if (RegNo >= 32) |
| return MCDisassembler::Fail; |
| Inst.addOperand(MCOperand::createReg(LoongArch::F0 + RegNo)); |
| return MCDisassembler::Success; |
| } |
| |
| static DecodeStatus DecodeFPR64RegisterClass(MCInst &Inst, uint64_t RegNo, |
| uint64_t Address, |
| const MCDisassembler *Decoder) { |
| if (RegNo >= 32) |
| return MCDisassembler::Fail; |
| Inst.addOperand(MCOperand::createReg(LoongArch::F0_64 + RegNo)); |
| return MCDisassembler::Success; |
| } |
| |
| static DecodeStatus DecodeCFRRegisterClass(MCInst &Inst, uint64_t RegNo, |
| uint64_t Address, |
| const MCDisassembler *Decoder) { |
| if (RegNo >= 8) |
| return MCDisassembler::Fail; |
| Inst.addOperand(MCOperand::createReg(LoongArch::FCC0 + RegNo)); |
| return MCDisassembler::Success; |
| } |
| |
| static DecodeStatus DecodeFCSRRegisterClass(MCInst &Inst, uint64_t RegNo, |
| uint64_t Address, |
| const MCDisassembler *Decoder) { |
| if (RegNo >= 4) |
| return MCDisassembler::Fail; |
| Inst.addOperand(MCOperand::createReg(LoongArch::FCSR0 + RegNo)); |
| return MCDisassembler::Success; |
| } |
| |
| template <unsigned N, int P = 0> |
| static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm, |
| int64_t Address, |
| const MCDisassembler *Decoder) { |
| assert(isUInt<N>(Imm) && "Invalid immediate"); |
| Inst.addOperand(MCOperand::createImm(Imm + P)); |
| return MCDisassembler::Success; |
| } |
| |
| template <unsigned N, unsigned S = 0> |
| static DecodeStatus decodeSImmOperand(MCInst &Inst, uint64_t Imm, |
| int64_t Address, |
| const MCDisassembler *Decoder) { |
| assert(isUInt<N>(Imm) && "Invalid immediate"); |
| // Shift left Imm <S> bits, then sign-extend the number in the bottom <N+S> |
| // bits. |
| Inst.addOperand(MCOperand::createImm(SignExtend64<N + S>(Imm << S))); |
| return MCDisassembler::Success; |
| } |
| |
| #include "LoongArchGenDisassemblerTables.inc" |
| |
| DecodeStatus LoongArchDisassembler::getInstruction(MCInst &MI, uint64_t &Size, |
| ArrayRef<uint8_t> Bytes, |
| uint64_t Address, |
| raw_ostream &CS) const { |
| uint32_t Insn; |
| DecodeStatus Result; |
| |
| // We want to read exactly 4 bytes of data because all LoongArch instructions |
| // are fixed 32 bits. |
| if (Bytes.size() < 4) { |
| Size = 0; |
| return MCDisassembler::Fail; |
| } |
| |
| Insn = support::endian::read32le(Bytes.data()); |
| // Calling the auto-generated decoder function. |
| Result = decodeInstruction(DecoderTable32, MI, Insn, Address, this, STI); |
| Size = 4; |
| |
| return Result; |
| } |