181ad6265SDimitry Andric //===-- LoongArchDisassembler.cpp - Disassembler for LoongArch ------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This file implements the LoongArchDisassembler class.
1081ad6265SDimitry Andric //
1181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1281ad6265SDimitry Andric
1381ad6265SDimitry Andric #include "MCTargetDesc/LoongArchBaseInfo.h"
1481ad6265SDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h"
1581ad6265SDimitry Andric #include "TargetInfo/LoongArchTargetInfo.h"
1681ad6265SDimitry Andric #include "llvm/MC/MCContext.h"
1781ad6265SDimitry Andric #include "llvm/MC/MCDecoderOps.h"
1881ad6265SDimitry Andric #include "llvm/MC/MCDisassembler/MCDisassembler.h"
1981ad6265SDimitry Andric #include "llvm/MC/MCInst.h"
2081ad6265SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
2181ad6265SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
2281ad6265SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
2381ad6265SDimitry Andric #include "llvm/MC/TargetRegistry.h"
2481ad6265SDimitry Andric #include "llvm/Support/Endian.h"
2581ad6265SDimitry Andric
2681ad6265SDimitry Andric using namespace llvm;
2781ad6265SDimitry Andric
2881ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-disassembler"
2981ad6265SDimitry Andric
3081ad6265SDimitry Andric typedef MCDisassembler::DecodeStatus DecodeStatus;
3181ad6265SDimitry Andric
3281ad6265SDimitry Andric namespace {
3381ad6265SDimitry Andric class LoongArchDisassembler : public MCDisassembler {
3481ad6265SDimitry Andric public:
LoongArchDisassembler(const MCSubtargetInfo & STI,MCContext & Ctx)3581ad6265SDimitry Andric LoongArchDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
3681ad6265SDimitry Andric : MCDisassembler(STI, Ctx) {}
3781ad6265SDimitry Andric
3881ad6265SDimitry Andric DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
3981ad6265SDimitry Andric ArrayRef<uint8_t> Bytes, uint64_t Address,
4081ad6265SDimitry Andric raw_ostream &CStream) const override;
4181ad6265SDimitry Andric };
42972a253aSDimitry Andric } // end namespace
4381ad6265SDimitry Andric
createLoongArchDisassembler(const Target & T,const MCSubtargetInfo & STI,MCContext & Ctx)4481ad6265SDimitry Andric static MCDisassembler *createLoongArchDisassembler(const Target &T,
4581ad6265SDimitry Andric const MCSubtargetInfo &STI,
4681ad6265SDimitry Andric MCContext &Ctx) {
4781ad6265SDimitry Andric return new LoongArchDisassembler(STI, Ctx);
4881ad6265SDimitry Andric }
4981ad6265SDimitry Andric
LLVMInitializeLoongArchDisassembler()5081ad6265SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchDisassembler() {
5181ad6265SDimitry Andric // Register the disassembler for each target.
5281ad6265SDimitry Andric TargetRegistry::RegisterMCDisassembler(getTheLoongArch32Target(),
5381ad6265SDimitry Andric createLoongArchDisassembler);
5481ad6265SDimitry Andric TargetRegistry::RegisterMCDisassembler(getTheLoongArch64Target(),
5581ad6265SDimitry Andric createLoongArchDisassembler);
5681ad6265SDimitry Andric }
5781ad6265SDimitry Andric
DecodeGPRRegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)5881ad6265SDimitry Andric static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint64_t RegNo,
5981ad6265SDimitry Andric uint64_t Address,
6081ad6265SDimitry Andric const MCDisassembler *Decoder) {
6181ad6265SDimitry Andric if (RegNo >= 32)
6281ad6265SDimitry Andric return MCDisassembler::Fail;
6381ad6265SDimitry Andric Inst.addOperand(MCOperand::createReg(LoongArch::R0 + RegNo));
6481ad6265SDimitry Andric return MCDisassembler::Success;
6581ad6265SDimitry Andric }
6681ad6265SDimitry Andric
DecodeFPR32RegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)6781ad6265SDimitry Andric static DecodeStatus DecodeFPR32RegisterClass(MCInst &Inst, uint64_t RegNo,
6881ad6265SDimitry Andric uint64_t Address,
6981ad6265SDimitry Andric const MCDisassembler *Decoder) {
7081ad6265SDimitry Andric if (RegNo >= 32)
7181ad6265SDimitry Andric return MCDisassembler::Fail;
7281ad6265SDimitry Andric Inst.addOperand(MCOperand::createReg(LoongArch::F0 + RegNo));
7381ad6265SDimitry Andric return MCDisassembler::Success;
7481ad6265SDimitry Andric }
7581ad6265SDimitry Andric
DecodeFPR64RegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)7681ad6265SDimitry Andric static DecodeStatus DecodeFPR64RegisterClass(MCInst &Inst, uint64_t RegNo,
7781ad6265SDimitry Andric uint64_t Address,
7881ad6265SDimitry Andric const MCDisassembler *Decoder) {
7981ad6265SDimitry Andric if (RegNo >= 32)
8081ad6265SDimitry Andric return MCDisassembler::Fail;
8181ad6265SDimitry Andric Inst.addOperand(MCOperand::createReg(LoongArch::F0_64 + RegNo));
8281ad6265SDimitry Andric return MCDisassembler::Success;
8381ad6265SDimitry Andric }
8481ad6265SDimitry Andric
DecodeCFRRegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)8581ad6265SDimitry Andric static DecodeStatus DecodeCFRRegisterClass(MCInst &Inst, uint64_t RegNo,
8681ad6265SDimitry Andric uint64_t Address,
8781ad6265SDimitry Andric const MCDisassembler *Decoder) {
8881ad6265SDimitry Andric if (RegNo >= 8)
8981ad6265SDimitry Andric return MCDisassembler::Fail;
9081ad6265SDimitry Andric Inst.addOperand(MCOperand::createReg(LoongArch::FCC0 + RegNo));
9181ad6265SDimitry Andric return MCDisassembler::Success;
9281ad6265SDimitry Andric }
9381ad6265SDimitry Andric
DecodeFCSRRegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)9481ad6265SDimitry Andric static DecodeStatus DecodeFCSRRegisterClass(MCInst &Inst, uint64_t RegNo,
9581ad6265SDimitry Andric uint64_t Address,
9681ad6265SDimitry Andric const MCDisassembler *Decoder) {
9781ad6265SDimitry Andric if (RegNo >= 4)
9881ad6265SDimitry Andric return MCDisassembler::Fail;
9981ad6265SDimitry Andric Inst.addOperand(MCOperand::createReg(LoongArch::FCSR0 + RegNo));
10081ad6265SDimitry Andric return MCDisassembler::Success;
10181ad6265SDimitry Andric }
10281ad6265SDimitry Andric
DecodeLSX128RegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)103*06c3fb27SDimitry Andric static DecodeStatus DecodeLSX128RegisterClass(MCInst &Inst, uint64_t RegNo,
104*06c3fb27SDimitry Andric uint64_t Address,
105*06c3fb27SDimitry Andric const MCDisassembler *Decoder) {
106*06c3fb27SDimitry Andric if (RegNo >= 32)
107*06c3fb27SDimitry Andric return MCDisassembler::Fail;
108*06c3fb27SDimitry Andric Inst.addOperand(MCOperand::createReg(LoongArch::VR0 + RegNo));
109*06c3fb27SDimitry Andric return MCDisassembler::Success;
110*06c3fb27SDimitry Andric }
111*06c3fb27SDimitry Andric
DecodeLASX256RegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)112*06c3fb27SDimitry Andric static DecodeStatus DecodeLASX256RegisterClass(MCInst &Inst, uint64_t RegNo,
113*06c3fb27SDimitry Andric uint64_t Address,
114*06c3fb27SDimitry Andric const MCDisassembler *Decoder) {
115*06c3fb27SDimitry Andric if (RegNo >= 32)
116*06c3fb27SDimitry Andric return MCDisassembler::Fail;
117*06c3fb27SDimitry Andric Inst.addOperand(MCOperand::createReg(LoongArch::XR0 + RegNo));
118*06c3fb27SDimitry Andric return MCDisassembler::Success;
119*06c3fb27SDimitry Andric }
120*06c3fb27SDimitry Andric
DecodeSCRRegisterClass(MCInst & Inst,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)121*06c3fb27SDimitry Andric static DecodeStatus DecodeSCRRegisterClass(MCInst &Inst, uint64_t RegNo,
122*06c3fb27SDimitry Andric uint64_t Address,
123*06c3fb27SDimitry Andric const MCDisassembler *Decoder) {
124*06c3fb27SDimitry Andric if (RegNo >= 4)
125*06c3fb27SDimitry Andric return MCDisassembler::Fail;
126*06c3fb27SDimitry Andric Inst.addOperand(MCOperand::createReg(LoongArch::SCR0 + RegNo));
127*06c3fb27SDimitry Andric return MCDisassembler::Success;
128*06c3fb27SDimitry Andric }
129*06c3fb27SDimitry Andric
13081ad6265SDimitry Andric template <unsigned N, int P = 0>
decodeUImmOperand(MCInst & Inst,uint64_t Imm,int64_t Address,const MCDisassembler * Decoder)13181ad6265SDimitry Andric static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm,
13281ad6265SDimitry Andric int64_t Address,
13381ad6265SDimitry Andric const MCDisassembler *Decoder) {
13481ad6265SDimitry Andric assert(isUInt<N>(Imm) && "Invalid immediate");
13581ad6265SDimitry Andric Inst.addOperand(MCOperand::createImm(Imm + P));
13681ad6265SDimitry Andric return MCDisassembler::Success;
13781ad6265SDimitry Andric }
13881ad6265SDimitry Andric
13981ad6265SDimitry Andric template <unsigned N, unsigned S = 0>
decodeSImmOperand(MCInst & Inst,uint64_t Imm,int64_t Address,const MCDisassembler * Decoder)14081ad6265SDimitry Andric static DecodeStatus decodeSImmOperand(MCInst &Inst, uint64_t Imm,
14181ad6265SDimitry Andric int64_t Address,
14281ad6265SDimitry Andric const MCDisassembler *Decoder) {
14381ad6265SDimitry Andric assert(isUInt<N>(Imm) && "Invalid immediate");
144bdd1243dSDimitry Andric // Shift left Imm <S> bits, then sign-extend the number in the bottom <N+S>
14581ad6265SDimitry Andric // bits.
146bdd1243dSDimitry Andric Inst.addOperand(MCOperand::createImm(SignExtend64<N + S>(Imm << S)));
14781ad6265SDimitry Andric return MCDisassembler::Success;
14881ad6265SDimitry Andric }
14981ad6265SDimitry Andric
15081ad6265SDimitry Andric #include "LoongArchGenDisassemblerTables.inc"
15181ad6265SDimitry Andric
getInstruction(MCInst & MI,uint64_t & Size,ArrayRef<uint8_t> Bytes,uint64_t Address,raw_ostream & CS) const15281ad6265SDimitry Andric DecodeStatus LoongArchDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
15381ad6265SDimitry Andric ArrayRef<uint8_t> Bytes,
15481ad6265SDimitry Andric uint64_t Address,
15581ad6265SDimitry Andric raw_ostream &CS) const {
15681ad6265SDimitry Andric uint32_t Insn;
15781ad6265SDimitry Andric DecodeStatus Result;
15881ad6265SDimitry Andric
15981ad6265SDimitry Andric // We want to read exactly 4 bytes of data because all LoongArch instructions
16081ad6265SDimitry Andric // are fixed 32 bits.
16181ad6265SDimitry Andric if (Bytes.size() < 4) {
16281ad6265SDimitry Andric Size = 0;
16381ad6265SDimitry Andric return MCDisassembler::Fail;
16481ad6265SDimitry Andric }
16581ad6265SDimitry Andric
16681ad6265SDimitry Andric Insn = support::endian::read32le(Bytes.data());
16781ad6265SDimitry Andric // Calling the auto-generated decoder function.
16881ad6265SDimitry Andric Result = decodeInstruction(DecoderTable32, MI, Insn, Address, this, STI);
16981ad6265SDimitry Andric Size = 4;
17081ad6265SDimitry Andric
17181ad6265SDimitry Andric return Result;
17281ad6265SDimitry Andric }
173