1 //===-- LoongArchDisassembler.cpp - Disassembler for LoongArch ------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the LoongArchDisassembler class. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "MCTargetDesc/LoongArchBaseInfo.h" 14 #include "MCTargetDesc/LoongArchMCTargetDesc.h" 15 #include "TargetInfo/LoongArchTargetInfo.h" 16 #include "llvm/MC/MCContext.h" 17 #include "llvm/MC/MCDisassembler/MCDisassembler.h" 18 #include "llvm/MC/MCFixedLenDisassembler.h" 19 #include "llvm/MC/MCInst.h" 20 #include "llvm/MC/MCInstrInfo.h" 21 #include "llvm/MC/MCRegisterInfo.h" 22 #include "llvm/MC/MCSubtargetInfo.h" 23 #include "llvm/MC/TargetRegistry.h" 24 #include "llvm/Support/Endian.h" 25 26 using namespace llvm; 27 28 #define DEBUG_TYPE "loongarch-disassembler" 29 30 typedef MCDisassembler::DecodeStatus DecodeStatus; 31 32 namespace { 33 class LoongArchDisassembler : public MCDisassembler { 34 public: 35 LoongArchDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) 36 : MCDisassembler(STI, Ctx) {} 37 38 DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, 39 ArrayRef<uint8_t> Bytes, uint64_t Address, 40 raw_ostream &CStream) const override; 41 }; 42 } // end anonymous namespace 43 44 static MCDisassembler *createLoongArchDisassembler(const Target &T, 45 const MCSubtargetInfo &STI, 46 MCContext &Ctx) { 47 return new LoongArchDisassembler(STI, Ctx); 48 } 49 50 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchDisassembler() { 51 // Register the disassembler for each target. 52 TargetRegistry::RegisterMCDisassembler(getTheLoongArch32Target(), 53 createLoongArchDisassembler); 54 TargetRegistry::RegisterMCDisassembler(getTheLoongArch64Target(), 55 createLoongArchDisassembler); 56 } 57 58 static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint64_t RegNo, 59 uint64_t Address, 60 const MCDisassembler *Decoder) { 61 if (RegNo >= 32) 62 return MCDisassembler::Fail; 63 Inst.addOperand(MCOperand::createReg(LoongArch::R0 + RegNo)); 64 return MCDisassembler::Success; 65 } 66 67 template <unsigned N, int P = 0> 68 static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm, 69 int64_t Address, 70 const MCDisassembler *Decoder) { 71 assert(isUInt<N>(Imm) && "Invalid immediate"); 72 Inst.addOperand(MCOperand::createImm(Imm + P)); 73 return MCDisassembler::Success; 74 } 75 76 template <unsigned N, unsigned S = 0> 77 static DecodeStatus decodeSImmOperand(MCInst &Inst, uint64_t Imm, 78 int64_t Address, 79 const MCDisassembler *Decoder) { 80 assert(isUInt<N>(Imm) && "Invalid immediate"); 81 // Sign-extend the number in the bottom <N> bits of Imm, then shift left <S> 82 // bits. 83 Inst.addOperand(MCOperand::createImm(SignExtend64<N>(Imm) << S)); 84 return MCDisassembler::Success; 85 } 86 87 #include "LoongArchGenDisassemblerTables.inc" 88 89 DecodeStatus LoongArchDisassembler::getInstruction(MCInst &MI, uint64_t &Size, 90 ArrayRef<uint8_t> Bytes, 91 uint64_t Address, 92 raw_ostream &CS) const { 93 uint32_t Insn; 94 DecodeStatus Result; 95 96 // We want to read exactly 4 bytes of data because all LoongArch instructions 97 // are fixed 32 bits. 98 if (Bytes.size() < 4) { 99 Size = 0; 100 return MCDisassembler::Fail; 101 } 102 103 Insn = support::endian::read32le(Bytes.data()); 104 // Calling the auto-generated decoder function. 105 Result = decodeInstruction(DecoderTable32, MI, Insn, Address, this, STI); 106 Size = 4; 107 108 return Result; 109 } 110